diff --git a/.vscode/snippets/diagram.json b/.vscode/snippets/diagram.json new file mode 100644 index 0000000..1cbf8d7 --- /dev/null +++ b/.vscode/snippets/diagram.json @@ -0,0 +1,86 @@ +{ + "C4_Person": { + "prefix": "Person", + "body": [ + "Person(${1:alias}, \"${2:label}\")", + "$0" + ], + "description": "Add Person to C4 diagram" + }, + "C4_Person_Descr": { + "prefix": "Person with Description", + "body": [ + "Person(${1:alias}, \"${2:label}\", \"${3:description}\")", + "$0" + ], + "description": "Add Person with Description to C4 diagram" + }, + + "C4_Container": { + "prefix": "Container", + "body": [ + "Container(${1:alias}, \"${2:label}\", \"${3:technology}\")", + "$0" + ], + "description": "Add Container to C4 diagram" + }, + "C4_Container_Descr": { + "prefix": "Container with Description", + "body": [ + "Container(${1:alias}, \"${2:label}\", \"${3:technology}\", \"${4:description}\")", + "$0" + ], + "description": "Add Container with Description to C4 diagram" + }, + + "C4_System": { + "prefix": "System", + "body": [ + "System(${1:alias}, \"${2:label}\")", + "$0" + ], + "description": "Add System to C4 diagram" + }, + "C4_System_Descr": { + "prefix": "System with Description", + "body": [ + "System(${1:alias}, \"${2:label}\", \"${3:description}\")", + "$0" + ], + "description": "Add System with Description to C4 diagram" + }, + + "C4_Relationship": { + "prefix": "Relationship", + "body": [ + "Rel(${1:from_alias}, ${2:to_alias}, \"${3:label}\")", + "$0" + ], + "description": "Add unidirectional Relationship to C4 diagram" + }, + "C4_Relationship_Techn": { + "prefix": "Relationship with Technology", + "body": [ + "Rel(${1:from_alias}, ${2:to_alias}, \"${3:label}\", \"${4:technology}\")", + "$0" + ], + "description": "Add unidirectional Relationship with Technology to C4 diagram" + }, + + "C4_Layout_Right": { + "prefix": "Layout to Right side", + "body": [ + "Lay_R(${1:from_alias}, ${2:to_alias})", + "$0" + ], + "description": "Add hidden layout line to put {to} to the right of {from}" + }, + "C4_Layout_Left": { + "prefix": "Layout to Left side", + "body": [ + "Lay_L(${1:from_alias}, ${2:to_alias})", + "$0" + ], + "description": "Add hidden layout line to put {to} to the left of {from}" + } +} \ No newline at end of file diff --git a/C4_Container.puml b/C4_Container.puml new file mode 100644 index 0000000..ea7a5ad --- /dev/null +++ b/C4_Container.puml @@ -0,0 +1,109 @@ +' Colors +' ################################## + +!define PERSON_BG_COLOR #08427B +!define CONTAINER_BG_COLOR #438DD5 +!define SYSTEM_BG_COLOR #999999 +!define ELEMENT_FONT_COLOR #FFFFFF + +!define TECHN_FONT_SIZE 12 + +' Styling +' ################################## +skinparam defaultTextAlignment center + +skinparam wrapWidth 200 +skinparam maxMessageSize 200 + +skinparam rectangle { + StereotypeFontSize 12 +} + +skinparam Arrow { + Color #666666 + FontColor #666666 +} + +skinparam rectangle<> { + StereotypeFontColor ELEMENT_FONT_COLOR + FontColor ELEMENT_FONT_COLOR + BackgroundColor PERSON_BG_COLOR + BorderColor #073B6F +} + +skinparam rectangle<> { + StereotypeFontColor ELEMENT_FONT_COLOR + FontColor ELEMENT_FONT_COLOR + BackgroundColor CONTAINER_BG_COLOR + BorderColor #3C7FC0 +} + +skinparam rectangle<> { + StereotypeFontColor ELEMENT_FONT_COLOR + FontColor ELEMENT_FONT_COLOR + BackgroundColor SYSTEM_BG_COLOR + BorderColor #8A8A8A +} + +skinparam package<> { + StereotypeFontSize 0 + FontColor #999999 + BorderColor #cccccc +} + +' Layout +' ################################## + +!definelong LAYOUT_AS_SKETCH +skinparam backgroundColor #EEEBDC +skinparam handwritten true +skinparam defaultFontName "Comic Sans MS" +center footer Warning: Created for discussion, needs to be validated +!enddefinelong + +!definelong LAYOUT_WITH_LEGEND +hide stereotype +legend right +|= |= Type | +| | person | +| | container | +| | external system | +endlegend +!enddefinelong + +!define LAYOUT_TOP_DOWN top to bottom direction +!define LAYOUT_LEFT_RIGHT left to right direction + +' Elements +' ################################## + +!define Person(e_alias, e_label) rectangle "==e_label" <> as e_alias +!define Person(e_alias, e_label, e_descr) rectangle "==e_label\n\n e_descr" <> as e_alias + +!define Container(e_alias, e_label, e_techn) rectangle "==e_label\n//[e_techn]//" <> as e_alias +!define Container(e_alias, e_label, e_techn, e_descr) rectangle "==e_label\n//[e_techn]//\n\n e_descr" <> as e_alias + +!define System(e_alias, e_label) rectangle "==e_label" <> as e_alias +!define System(e_alias, e_label, e_descr) rectangle "==e_label\n\n e_descr" <> as e_alias + + +!define Rel_(e_from,e_to, e_label, e_direction="") e_from -e_direction-> e_to : "===e_label" +!define Rel_(e_from,e_to, e_label, e_techn, e_direction="") e_from -e_direction-> e_to : "===e_label\n//[e_techn]//" + +!define Rel(e_from,e_to, e_label) Rel_(e_from,e_to, e_label, "") +!define Rel(e_from,e_to, e_label, e_techn) Rel_(e_from,e_to, e_label, e_techn, "") + +!define Rel_D(e_from,e_to, e_label) Rel_(e_from,e_to, e_label, "DOWN") +!define Rel_D(e_from,e_to, e_label, e_techn) Rel_(e_from,e_to, e_label, e_techn, "DOWN") + +!define Rel_U(e_from,e_to, e_label) Rel_(e_from,e_to, e_label, "UP") +!define Rel_U(e_from,e_to, e_label, e_techn) Rel_(e_from,e_to, e_label, e_techn, "UP") + +!define Rel_L(e_from,e_to, e_label) Rel_(e_from,e_to, e_label, "LEFT") +!define Rel_L(e_from,e_to, e_label, e_techn) Rel_(e_from,e_to, e_label, e_techn, "LEFT") + +!define Rel_R(e_from,e_to, e_label) Rel_(e_from,e_to, e_label, "RIGHT") +!define Rel_R(e_from,e_to, e_label, e_techn) Rel_(e_from,e_to, e_label, e_techn, "RIGHT") + +!define Lay_R(e_from, e_to) e_from -[hidden]R- e_to +!define Lay_L(e_from, e_to) e_from -[hidden]L- e_to \ No newline at end of file diff --git a/README.md b/README.md index 56c4165..a9b4832 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,140 @@ # C4-PlantUML -C4-PlantUML combines the benefits of PlantUML and the C4 model for providing a simple way of describing and communicate software architectures + +C4-PlantUML combines the benefits of [PlantUML](http://en.plantuml.com/) and the [C4 model](https://c4model.com/) for providing a simple way of describing and communicate software architectures - especially during up-front design sessions - with an intuitive language using open source and platform independent tools. + +C4-PlantUML includes macros, stereotypes, and other goodies (like VSCode Snippets) for creating C4 diagrams with PlantUML. + +## Background + +[PlantUML](http://en.plantuml.com/) is an open source project that allows you to create UML diagrams. +Diagrams are defined using a simple and intuitive language. +Images can be generated in PNG, in SVG or in LaTeX format. + +PlantUML was created to allow the drawing of UML diagrams, using a simple and human readable text description. +Because it does not prevent you from drawing inconsistent diagrams, it is a drawing tool and not a modeling tool. +It is the most used text-based diagram drawing tool with [extensive support into wikis and forums, text editors and IDEs, use by different programming languages and documentation generators](http://en.plantuml.com/running). + +The [C4 model](https://c4model.com/) for software architecture is an "abstraction-first" approach to diagramming, based upon abstractions that reflect how software architects and developers think about and build software. +The small set of abstractions and diagram types makes the C4 model easy to learn and use. +C4 stands for context, containers, components, and code — a set of hierarchical diagrams that you can use to describe your software architecture at different zoom levels, each useful for different audiences. + +The C4 model was created as a way to help software development teams describe and communicate software architecture, both during up-front design sessions and when retrospectively documenting an existing codebase. + +More information can be found here: + +* [The C4 model for software architecture](https://c4model.com/) +* [REAL WORLD PlantUML - Sample Gallery](https://real-world-plantuml.com/) +* [Visualising and documenting software architecture cheat sheets](http://www.codingthearchitecture.com/2017/04/27/visualising_and_documenting_software_architecture_cheat_sheets.html) +* [PlantUML and Structurizr - Create models not diagrams](http://www.codingthearchitecture.com/2016/12/08/plantuml_and_structurizr.html) + +## Getting Started + +At the top of your C4 PlantUML `.puml` file, you need to include the `C4_Container.puml` file found in the `root` of this repo. + +To be independent of any internet connectifity, you can also download `C4_Container.puml` and reference it locally with + +```plantuml +!include path/to/C4_Container.puml +``` + +If you want to use the always up-to-date version in this repo, use the following: + +```plantuml +!includeurl https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/master/C4_Container.puml +``` + +After you have inlcluded `C4_Container.puml` you can use the defined macro definitions for the C4 elements: `Person`, `System`, `Container`, `Relationship`. + +```plantuml +@startuml Basic Sample +!include C4_Container.puml + +Person(personAlias, "Label", "Optional Description") +Container(containerAlias, "Label", "Technology", "Optional Description") +System(systemAlias, "Label", "Optional Description") + +Rel(personAlias, containerAlias, "Label", "Optional Technology") +@enduml +``` + +In addition to this, it is also possible to define a system boundary. + +Take a look a look at the following sample of a C4 Container Diagram: + +```plantuml +@startuml Basic Sample +!include C4_Container.puml + +Person(admin, "Administrator") +package "Sample System" <> as c1 { + Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines") +} +System(twitter, "Twitter") + +Rel(admin, web_app, "Uses", "HTTPS") +Rel(web_app, twitter, "Gets tweets from", "HTTPS") +@enduml +``` + +## Snipptes for Visual Studio Code + +Lorem + +https://medium.com/hack-visual-studio-code/share-snippets-with-your-team-in-vs-code-817801e853fb + +## Layout Options + +PlantUML uses [Graphviz](https://www.graphviz.org/) for his graph visualization. Thus the rendering itself is done automatically for you - that it one of the biggest advantages of using PlantUML. + +...and also sometimes one of the biggest disadvantages, if the rendering is not what the user intended. + +For this reason, C4-PlantUML also comes with some layout options. + +### LAYOUT_TOP_DOWN or LAYOUT_LEFT_RIGHT + +With the two macros `LAYOUT_TOP_DOWN` and `LAYOUT_LEFT_RIGHT` it is possible to easily change the flow visualization of the diagram. `LAYOUT_TOP_DOWN` is the default. + +```plantuml +@startuml Basic Sample +!include C4_Container.puml + +' Not needed because this is the default +LAYOUT_TOP_DOWN + +Person(admin, "Administrator") +package "Sample System" <> as c1 { + Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines") +} +System(twitter, "Twitter") + +Rel(admin, web_app, "Uses", "HTTPS") +Rel(web_app, twitter, "Gets tweets from", "HTTPS") +@enduml +``` + +Using `LAYOUT_LEFT_RIGHT` + +```plantuml +@startuml Basic Sample +!include C4_Container.puml + +LAYOUT_LEFT_RIGHT + +Person(admin, "Administrator") +package "Sample System" <> as c1 { + Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines") +} +System(twitter, "Twitter") + +Rel(admin, web_app, "Uses", "HTTPS") +Rel(web_app, twitter, "Gets tweets from", "HTTPS") +@enduml +``` + +### LAYOUT_WITH_LEGEND + +Colors can help to add additional information or simply to make the diagram more aesthetically pleasing. + + +## Advanced Samples + diff --git a/samples/C4_Container Diagram Sample - bigbankplc.puml b/samples/C4_Container Diagram Sample - bigbankplc.puml new file mode 100644 index 0000000..5faa1f0 --- /dev/null +++ b/samples/C4_Container Diagram Sample - bigbankplc.puml @@ -0,0 +1,48 @@ +@startuml "bigbankplc" +!include ..\C4_Container.puml + +LAYOUT_TOP_DOWN +'LAYOUT_AS_SKETCH +LAYOUT_WITH_LEGEND + + +Person(customer, Customer, "A customer of the bank, with personal bank accounts") + +package "Internet Banking System" <> as c1 { + + Container(web_app, "Web Application", "Java, Spring MVC", "Delivers the static content and the Internet banking SPA") + + Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to cutomers via their web browser") + + Container(mobile_app, "Mobile App", "C#, Xamarin", "Provides a limited subset of the Internet banking functionality to customers via their mobile device") + + Container(backend_api, "API Application", "Java, Docker Container", "Provides Internet banking functionality via API") + + Container(database, "Database", "SQL Database", "Stores user registraion information, hased auth credentials, access logs, etc.") +} + +System(email_system, "E-Mail System", "The internal Microsoft Exchange system") +System(banking_system, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") + +Rel(customer, web_app, "Uses", "HTTPS") +Rel(customer, spa, "Uses", "HTTPS") +Rel(customer, mobile_app, "Uses") + +Rel_R(web_app, spa, "Delivers") + +Rel(spa, backend_api, "Uses", "async, JSON/HTTPS") + +Rel(mobile_app, backend_api, "Uses", "async, JSON/HTTPS") + +Rel_L(backend_api, database, "Reads from and writes to", "sync, JDBC") +Rel_R(backend_api, banking_system, "Uses", "sync/async, XML/HTTPS") +Rel_U(backend_api, email_system, "Sends e-mails using", "sync, SMTP") + +Rel(email_system, customer, "Sends e-mails to") + +rectangle test +email_system -UP-> test +test -LEFT-> customer +hide test + +@enduml \ No newline at end of file diff --git a/samples/C4_Container Diagram Sample - message bus.puml b/samples/C4_Container Diagram Sample - message bus.puml new file mode 100644 index 0000000..886950c --- /dev/null +++ b/samples/C4_Container Diagram Sample - message bus.puml @@ -0,0 +1,49 @@ +@startuml "bigbankplc" +!include ..\C4_Container.puml + +skinparam wrapWidth 200 +skinparam maxMessageSize 200 + +LAYOUT_TOP_DOWN +'LAYOUT_AS_SKETCH +LAYOUT_WITH_LEGEND + + +Person(customer, Customer, "A customer") + +package "Customer Information System" <> as c1 { + + Container(app, "Customer Application", "Javascript, Angular", "Allows customers to manage their profile") + + Container(customer_service, "Customer Service", "Java, Spring Boot", "The point of access for customer information") + + Container(message_bus, "Message Bus", "RabbitMQ", "Transport for business events") + + Container(reporting_service, "Reporting Service", "Ruby", "Creates normalised data for reporting purposes") + + Container(audit_service, "Audit Service", "C#/.NET", "Provides organisation-wide auditing facilities") + + Container(customer_db, "Customer Database", "Oracle 12c", "Stores customer information") + + Container(reporting_db, "Reporting Database", "MySQL", "Stores a normalized version of all business data for ad hoc reporting purposes") + + Container(audit_store, "Audit Store", "Event Store", "Stores information about events that have happened") +} + +Rel(customer, app, "Uses", "HTTPS") + +Rel_R(app, customer_service, "Updates customer information using", "async, JSON/HTTPS") + +Rel_L(customer_service, app, "Sends events to", "WebSocket") +Rel_R(customer_service, message_bus, "Sends customer update events to") +Rel(customer_service, customer_db, "Stores data in", "JDBC") + +Rel(message_bus, reporting_service, "Sends customer update events to") +Rel(message_bus, audit_service, "Sends customer update events to") + +Rel(reporting_service, reporting_db, "Stores data in") +Rel(audit_service, audit_store, "Stores events in") + +Lay_R(reporting_service, audit_service) + +@enduml \ No newline at end of file diff --git a/samples/C4_Container Diagram Sample - techtribesje.puml b/samples/C4_Container Diagram Sample - techtribesje.puml new file mode 100644 index 0000000..4cc078f --- /dev/null +++ b/samples/C4_Container Diagram Sample - techtribesje.puml @@ -0,0 +1,49 @@ +@startuml "bigbankplc" +!include ..\C4_Container.puml + +LAYOUT_TOP_DOWN +'LAYOUT_AS_SKETCH +LAYOUT_WITH_LEGEND + + +Person(anonymous_user, "Anonymous User") +Person(aggregated_user, "Aggregated User") +Person(administration_user, "Administration User") + +package "techtribes.js" <> as c1 { + + Container(web_app, "Web Application", "Java, Spring MVC, Tomcat 7.x", "Allows users to view people, tribes, content, events, jobs, etc. from the local tech, digital and IT sector") + + Container(rel_db, "Relational Database", "MySQL 5.5.x", "Stores people, tribes, tribe membership, talks, events, jobs, badges, GitHub repos, etc.") + + Container(filesystem, "File System", "FAT32", "Stores search indexes") + + Container(nosql, "NoSQL Data Store", "MongoDB 2.2.x", "Stores from RSS/Atom feeds (blog posts) and tweets") + + Container(updater, "Updater", "Java 7 Console App", "Updates profiles, tweets, GitHub repos and content on a scheduled basis") +} + +System(twitter, "Twitter") +System(github, "GitHub") +System(blogs, "Blogs") + + +Rel(anonymous_user, web_app, "Uses", "HTTPS") +Rel(aggregated_user, web_app, "Uses", "HTTPS") +Rel(administration_user, web_app, "Uses", "HTTPS") + +Rel(web_app, rel_db, "Reads from and writes to", "SQL/JDBC, post 3306") +Rel(web_app, filesystem, "Reads from") +Rel(web_app, nosql, "Reads from", "MongoDB wire protocol, port 27017") + +Rel_U(updater, rel_db, "Reads from and writes data to", "SQL/JDBC, post 3306") +Rel_U(updater, filesystem, "Writes to") +Rel_U(updater, nosql, "Reads from and writes to", "MongoDB wire protocol, port 27017") + +Rel(updater, twitter, "Gets profile information and tweets from", "HTTPS") +Rel(updater, github, "Gets information about public code repositories from", "HTTPS") +Rel(updater, blogs, "Gets content using RSS and Atom feeds from", "HTTP") + +Lay_R(rel_db, filesystem) + +@enduml \ No newline at end of file