Skip to content

Supporting diagrams

In addition, there are 3 supporting diagram types:

System landscape diagram

The system context, container, component, and code diagrams are designed to provide a static view of a single software system but, in the real-world, software systems never live in isolation. For this reason, and particularly if you are responsible for a collection/portfolio of software systems, it’s often useful to understand how all of these software systems fit together within a given enterprise, organisation, department, etc. Essentially this is a map of the software systems within the chosen scope, with a set of system context, container, component, and code diagrams for each software system of interest.

From a practical perspective, a system landscape diagram is really just a system context diagram without a specific focus on a particular software system.

Python DSL
from c4 import (
    EnterpriseBoundary,
    LayD,
    LayU,
    Person,
    PersonExt,
    RelBack,
    RelD,
    RelNeighbor,
    RelR,
    RelU,
    System,
    SystemExt,
    SystemLandscapeDiagram,
)
from c4.renderers.plantuml import LayoutOptions


with SystemLandscapeDiagram(
    title="System Landscape diagram for Big Bank plc"
) as diagram:
    customer = Person(
        "customer",
        "Personal Banking Customer",
        "A customer of the bank, with personal bank accounts.",
    )

    with EnterpriseBoundary("c0", "Big Bank plc"):
        banking_system = System(
            "banking_system",
            "Internet Banking System",
            "Allows customers to view information about their bank accounts, and make payments.",
        )

        atm = SystemExt("atm", "ATM", "Allows customers to withdraw cash.")
        mail_system = SystemExt(
            "mail_system",
            "E-mail system",
            "The internal Microsoft Exchange e-mail system.",
        )

        mainframe = SystemExt(
            "mainframe",
            "Mainframe Banking System",
            "Stores all of the core banking information about customers, accounts, transactions, etc.",
        )

        customer_service = PersonExt(
            "customer_service",
            "Customer Service Staff",
            "Customer service staff within the bank.",
        )
        back_office = PersonExt(
            "back_office",
            "Back Office Staff",
            "Administration and support staff within the bank.",
        )

    customer >> RelNeighbor("Uses") >> banking_system
    customer >> RelR("Withdraws cash using") >> atm
    customer >> RelBack("Sends e-mails to") >> mail_system

    customer >> RelR("Asks questions to", "Telephone") >> customer_service

    banking_system >> RelD("Sends e-mail using") >> mail_system
    atm >> RelR("Uses") >> mainframe
    banking_system >> RelR("Uses") >> mainframe
    customer_service >> RelD("Uses") >> mainframe
    back_office >> RelU("Uses") >> mainframe

    LayD(atm, banking_system)

    LayD(atm, customer)
    LayU(mail_system, customer)

    layout_options = LayoutOptions().layout_with_legend()

diagram_code = diagram.as_plantuml(layout_options=layout_options)

The PlantUML source can be rendered into the following diagram:

system context

Dynamic diagram

A dynamic diagram can be useful when you want to show how elements in the static model collaborate at runtime to implement a user story, use case, feature, etc. This dynamic diagram is based upon a UML communication diagram (previously known as a “UML collaboration diagram”). It is similar to a UML sequence diagram, although it allows a free-form arrangement of diagram elements with numbered interactions to indicate ordering.

Python DSL
from c4 import (
    Container,
    ContainerDb,
    DynamicDiagram,
    Index,
    LastIndex,
    Person,
    Rel,
    RelDown,
    RelLeft,
    RelRight,
    RelUp,
    SetIndex,
    SystemBoundary,
)
from c4.renderers.plantuml import LayoutOptions


with DynamicDiagram() as diagram:
    customer = Person("customer", "Customer", "A customer")

    with SystemBoundary("c1", "Customer Information"):
        app = Container(
            "app",
            "Customer Application",
            "Javascript, Angular",
            "Allows customers to manage their profile",
        )
        customer_service = Container(
            "customer_service",
            "Customer Service",
            "Java, Spring Boot",
            "The point of access for customer information",
        )
        message_bus = Container(
            "message_bus",
            "Message Bus",
            "RabbitMQ",
            "Transport for business events",
        )
        reporting_service = Container(
            "reporting_service",
            "Reporting Service",
            "Ruby",
            "Creates normalised data for reporting purposes",
        )
        audit_service = Container(
            "audit_service",
            "Audit Service",
            "C#/.NET",
            "Provides organisation-wide auditing facilities",
        )
        customer_db = ContainerDb(
            "customer_db",
            "Customer Database",
            "Oracle 12c",
            "Stores customer information",
        )
        reporting_db = ContainerDb(
            "reporting_db",
            "Reporting Database",
            "MySQL",
            "Stores a normalized version of all business data for ad hoc reporting purposes",
        )
        audit_store = Container(
            "audit_store",
            "Audit Store",
            "Event Store",
            "Stores information about events that have happened",
        )

    customer >> RelDown("Updates his profile using", "HTTPS") >> app
    (
        app
        >> Rel("Updates customer information using", "JSON/HTTPS")
        >> customer_service
    )
    customer_service >> RelRight("Stores data in", "JDBC") >> customer_db

    (
        customer_service
        >> RelDown(
            "Sends customer update events to", "async", index=f"{Index()}-1"
        )
        >> message_bus
    )
    (
        customer_service
        >> RelUp("Confirm update to", "async", index=LastIndex() + "-2")
        >> app
    )

    (
        message_bus
        >> RelLeft(
            "Sends customer update events to", "async", index=f"{Index()}-1"
        )
        >> reporting_service
    )
    (
        reporting_service
        >> Rel("Stores data in", index=f"{Index()}-1")
        >> reporting_db
    )

    (
        message_bus
        >> RelRight(
            "Sends customer update events to",
            "async",
            index=f"{SetIndex(5)}-2",
        )
        >> audit_service
    )
    (
        audit_service
        >> Rel("Stores events in", index=f"{Index()}-2")
        >> audit_store
    )

    layout_options = (
        LayoutOptions().layout_top_down(with_legend=True).show_legend()
    )

diagram_code = diagram.as_plantuml(layout_options=layout_options)

The PlantUML source can be rendered into the following diagram:

system context

Deployment diagram

A deployment diagram allows you to illustrate how instances of software systems and/or containers in the static model are deployed on to the infrastructure within a given deployment environment (e.g. production, staging, development, etc). It’s based upon a UML deployment diagram.

Python DSL
from c4 import (
    Container,
    ContainerDb,
    DeploymentDiagram,
    DeploymentNode,
    DeploymentNodeLeft,
    DeploymentNodeRight,
    Rel,
    RelRight,
    RelUp,
)
from c4.renderers.plantuml import LayoutOptions


with DeploymentDiagram(
    title="Deployment Diagram for Internet Banking System - Live"
) as diagram:
    with DeploymentNode("plc", "Big Bank plc", "Big Bank plc data center"):
        with DeploymentNode(
            "dn", "bigbank-api***\\tx8", "Ubuntu 16.04 LTS"
        ):
            with DeploymentNode(
                "apache", "Apache Tomcat", "Apache Tomcat 8.x"
            ):
                api = Container(
                    "api",
                    "API Application",
                    "Java and Spring MVC",
                    "Provides Internet Banking functionality via a JSON/HTTPS API.",
                )

        with DeploymentNode(
            "bigbankdb01", "bigbank-db01", "Ubuntu 16.04 LTS"
        ):
            with DeploymentNode("oracle", "Oracle - Primary", "Oracle 12c"):
                db = ContainerDb(
                    "db",
                    "Database",
                    "Relational Database Schema",
                    "Stores user registration information, hashed authentication credentials, access logs, etc.",
                )

        with DeploymentNode(
            "bigbankdb02",
            "bigbank-db02",
            "Ubuntu 16.04 LTS",
            tags="fallback",
        ):
            with DeploymentNode(
                "oracle2",
                "Oracle - Secondary",
                "Oracle 12c",
                tags="fallback",
            ):
                db2 = ContainerDb(
                    "db2",
                    "Database",
                    "Relational Database Schema",
                    "Stores user registration information, hashed authentication credentials, access logs, etc.",
                    tags="fallback",
                )

        with DeploymentNode(
            "bb2", "bigbank-web***\\tx4", "Ubuntu 16.04 LTS"
        ):
            with DeploymentNode(
                "apache2", "Apache Tomcat", "Apache Tomcat 8.x"
            ):
                web = Container(
                    "web",
                    "Web Application",
                    "Java and Spring MVC",
                    "Delivers the static content and the Internet Banking single page application.",
                )

    with DeploymentNode(
        "mob", "Customer's mobile device", "Apple IOS or Android"
    ):
        mobile = Container(
            "mobile",
            "Mobile App",
            "Xamarin",
            "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.",
        )

    with DeploymentNode(
        "comp", "Customer's computer", "Microsoft Windows or Apple macOS"
    ):
        with DeploymentNode(
            "browser",
            "Web Browser",
            "Google Chrome, Mozilla Firefox, Apple Safari or Microsoft Edge",
        ):
            spa = Container(
                "spa",
                "Single Page Application",
                "JavaScript and Angular",
                "Provides all of the Internet Banking functionality to customers via their web browser.",
            )

    [mobile, spa] >> Rel("Makes API calls to", "json/HTTPS") >> api
    web >> RelUp("Delivers to the customer's web browser") >> spa
    api >> Rel("Reads from and writes to", "JDBC") >> db
    api >> Rel("Reads from and writes to", "JDBC", tags="fallback") >> db2
    db >> RelRight("Replicates data to") >> db2

    layout_options = (
        LayoutOptions()
        .add_element_tag("fallback", bg_color="#c0c0c0")
        .add_rel_tag("fallback", text_color="#c0c0c0", line_color="#438DD5")
        .show_legend()
    )

diagram_code = diagram.as_plantuml(layout_options=layout_options)

The PlantUML source can be rendered into the following diagram:

system context