Skip to content
Slava Vedernikov edited this page Oct 10, 2024 · 39 revisions

Home   CLI   Samples   Q&A   How‐to guides   Quick‐starts   Tutorials


C4 InterFlow - Logo
C4InterFlow = C4 Model + Interfaces + Flows

What is C4InterFlow?

C4InterFlow is a comprehensive Application Architecture focused framework designed for anyone in an organisation, who wants to either contribute to (or just to explore) the Application Architecture documentation.

Concepts

Structural concepts

C4InterFlow Metamodel

C4InterFlow - Metamodel

Person, Software System, Container and Component

These concepts are borrowed from C4 Model created by Simon Brown. C4 Model - Abstractions Image source: www.c4model.com

Interface and Flow

C4InterFlow introduces two new concepts: Interface and Flow. Multiple Interfaces can be added to Software Systems, Containers or Components. Interfaces express capabilities exposed by these structures. Interfaces exposed by a given structure can be used by other structures. In fact, the only way to form Relationships between structures in C4InterFlow, is for one structure to Use the other structure's Interface. Interface may have one or many Flows that express its behaviour, including how and when it Uses other Interfaces. Flows can be nested.

Business Process, Activity and Actor

In C4InterFlow a Business Process can be constructed with one or more Activities that are performed by Actors. Each Activity has to have a Flow, which has to use at least one Interface to be complete.

Architecture as Code (AaC) Domain Specific Language (DSL)

Each structure can be expressed using C4InterFlow Architecture as Code DSL either in C#, YAML or JSON. A single AaC file can have as little as one structure in it, or it can have all structures for the entire Namespace in it. In theory, you can even have all Namespaces and all of their structures stored in a single AaC file.

Below are some examples of AaC in C#, YAML and JSON

Software System

C#

// <auto-generated/>
using C4InterFlow.Structures;
using C4InterFlow.Structures.Interfaces;

namespace DotNetEShop.SoftwareSystems
{
    public partial class BasketApi : ISoftwareSystemInstance
    {
        public static SoftwareSystem Instance => new SoftwareSystem(typeof(BasketApi), "Basket Api")
        {
            Description = "",
            Boundary = Boundary.Internal
        };

        public partial class Containers
        {
        }

        public partial class Interfaces
        {
        }
    }
}

YAML

DotNetEShop:
  SoftwareSystems:
    BasketApi:
      Label: Basket Api
      Boundary: Internal
      Description: ''
      Containers: {}
      Interfaces: {}

JSON

{
  "DotNetEShop": {
    "SoftwareSystems": {
      "BasketApi": {
        "Label": "Basket Api",
        "Boundary": "Internal",
        "Description": "",
        "Containers": {},
        "Interfaces": {}
      }
    }
  }
}

Container

C#

// <auto-generated/>
using C4InterFlow.Structures;
using C4InterFlow.Structures.Interfaces;

namespace DotNetEShop.SoftwareSystems
{
    public partial class BasketApi
    {
        public partial class Containers
        {
            public partial class Grpc : IContainerInstance
            {
                public static Container Instance => new Container(typeof(Grpc), "Grpc")
                {
                    ContainerType = ContainerType.None,
                    Description = "",
                    Technology = "",
                    Boundary = Boundary.Internal
                };

                public partial class Components
                {
                }

                public partial class Interfaces
                {
                }

                public partial class Entities
                {
                }
            }
        }
    }
}

YAML

DotNetEShop:
  SoftwareSystems:
    BasketApi:
      Containers:
        Grpc:
          Label: Grpc
          Description: ''
          ContainerType: None
          Boundary: Internal
          Technology: ''
          Components: {}
          Interfaces: {}
          Entities: {}

JSON

{
  "DotNetEShop": {
    "SoftwareSystems": {
      "BasketApi": {
        "Containers": {
          "Grpc": {
            "Label": "Grpc",
            "Description": "",
            "ContainerType": "None",
            "Boundary": "Internal",
            "Technology": "",
            "Components": {},
            "Interfaces": {},
            "Entities": {}
          }
        }
      }
    }
  }
}

Component

C#

// <auto-generated/>
using C4InterFlow.Structures;
using C4InterFlow.Structures.Interfaces;

namespace DotNetEShop.SoftwareSystems
{
    public partial class BasketApi
    {
        public partial class Containers
        {
            public partial class Grpc
            {
                public partial class Components
                {
                    public partial class BasketService : IComponentInstance
                    {
                        public static Component Instance => new Component(typeof(BasketService), "Basket Service")
                        {
                            ComponentType = ComponentType.None,
                            Description = "",
                            Technology = ""
                        };

                        public partial class Interfaces
                        {
                        }
                    }
                }
            }
        }
    }
}

YAML

DotNetEShop:
  SoftwareSystems:
    BasketApi:
      Containers:
        Grpc:
          Components:
            BasketService:
              Label: Basket Service
              ComponentType: None
              Description: ''
              Technology: ''
              Interfaces: {}

JSON

{
  "DotNetEShop": {
    "SoftwareSystems": {
      "BasketApi": {
        "Containers": {
          "Grpc": {
            "Components": {
              "BasketService": {
                "Label": "Basket Service",
                "ComponentType": "None",
                "Description": "",
                "Technology": "",
                "Interfaces": {}
              }
            }
          }
        }
      }
    }
  }
}

Component Interface

C#

// <auto-generated/>
using C4InterFlow.Structures;
using C4InterFlow.Structures.Interfaces;

namespace DotNetEShop.SoftwareSystems
{
    public partial class BasketApi
    {
        public partial class Containers
        {
            public partial class Grpc
            {
                public partial class Components
                {
                    public partial class BasketService
                    {
                        public partial class Interfaces
                        {
                            public partial class GetBasket : IInterfaceInstance
                            {
                                public static Interface Instance => new Interface(typeof(GetBasket), "Get Basket")
                                {
                                    Description = "",
                                    Path = "",
                                    IsPrivate = false,
                                    Protocol = "",
                                    Flow = new Flow(Interface.GetAlias<GetBasket>())
                                    	.Use<DotNetEShop.SoftwareSystems.BasketApi.Containers.Data.Components.RedisBasketRepository.Interfaces.GetBasketAsync>()
                                    	.If(@"data is not null")
                                    		.Use<DotNetEShop.SoftwareSystems.BasketApi.Containers.Grpc.Components.BasketService.Interfaces.MapToCustomerBasketResponse>()
                                    	.EndIf(),
                                    Input = "",
                                    InputTemplate = "",
                                    Output = "",
                                    OutputTemplate = ""
                                };
                            }
                        }
                    }
                }
            }
        }
    }
}

YAML

DotNetEShop:
  SoftwareSystems:
    BasketApi:
      Containers:
        Grpc:
          Components:
            BasketService:
              Interfaces:
                GetBasket:
                  Label: Get Basket
                  Description: ''
                  Path: ''
                  IsPrivate: false
                  Protocol: ''
                  Flows:
                  - Type: Use
                    Expression: DotNetEShop.SoftwareSystems.BasketApi.Containers.Data.Components.RedisBasketRepository.Interfaces.GetBasketAsync
                  - Type: If
                    Expression: data is not null
                    Flows:
                    - Type: Use
                      Expression: DotNetEShop.SoftwareSystems.BasketApi.Containers.Grpc.Components.BasketService.Interfaces.MapToCustomerBasketResponse
                  Input: ''
                  InputTemplate: ''
                  Output: ''
                  OutputTemplate: ''

JSON

{
  "DotNetEShop": {
    "SoftwareSystems": {
      "BasketApi": {
        "Containers": {
          "Grpc": {
            "Components": {
              "BasketService": {
                "Interfaces": {
                  "GetBasket": {
                    "Label": "Get Basket",
                    "Description": "",
                    "Path": "",
                    "IsPrivate": false,
                    "Protocol": "",
                    "Flows": [
                      {
                        "Type": "Use",
                        "Expression": "DotNetEShop.SoftwareSystems.BasketApi.Containers.Data.Components.RedisBasketRepository.Interfaces.GetBasketAsync"
                      },
                      {
                        "Type": "If",
                        "Expression": "data is not null",
                        "Flows": [
                          {
                            "Type": "Use",
                            "Expression": "DotNetEShop.SoftwareSystems.BasketApi.Containers.Grpc.Components.BasketService.Interfaces.MapToCustomerBasketResponse"
                          }
                        ]
                      }
                    ],
                    "Input": "",
                    "InputTemplate": "",
                    "Output": "",
                    "OutputTemplate": ""
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Visualisation

Diagram Level of Details

C4InterFlow is aligned with C4 Model in terms of diagrams' Level of Details, which are Context (Level 1), Container (Level 2) and Component (Level 3).

NOTE: C4InterFlow does not yet support Class (Level 4) Level of Details.

C4 Model - Levels Image source: www.c4model.com

Examples

Below are example of C4 diagrams auto-generated by C4InterFlow CLI for a Basket API Software System of the E-Shop sample .NET application .

Context (Level 1) Container (Level 2) Component (Level 3)
C4 InterFlow - Diagrams Type - C4 C4 InterFlow - Diagrams Type - C4 C4 InterFlow - Diagrams Type - C4

Diagram Scope

C4InterFlow can draw diagrams which include various number of Interfaces, covering different sub-sets of Application Architecture landscape. The size of such sub-set can be expressed with the concept of Scope. At the moment the following Scopes are supported:

  • All Software Systems - all Interfaces of all Software Systems and their Containers and Components
  • Namespace - all Interfaces of all Software Systems in a particular Namespace and its Sub-Namespaces and their Containers and Components
  • Software System - all Interfaces of a Software System
  • Software System Interface - a single Software System Interface
  • Container - all Interfaces of a Container
  • Container Interface - a single Container Interface
  • Component - all Interfaces of a Component
  • Component Interface - a single Component Interface
  • Business Process - all Interfaces used in the Flows of all Activities of a Business Process

Diagram Type

C4InterFlow can generate the following diagrams Types:

  • C4 Static - a C4 Model Diagram of a specific Scope and at a specific Level Of Details (all Scopes and all Levels of Details are supported), where each "line" has "Uses" label indicating a dependency of a source (from) Structure on a destination (to) Structure

C4 InterFlow - Diagrams Type - C4 Static

  • C4 - a C4 Model Diagram of a specific Scope and at a specific Level Of Details (all Scopes and all Levels of Details are supported), where each "line" has one or many labels that correspond to the labels of one or many Interfaces of a destination (to) Structure used by the source (from) Structure

C4 InterFlow - Diagrams Type - C4

  • C4 Sequence - a Plant UML Sequence diagram (styled like all other C4 diagrams) that can be generated for the following Scopes:
    • Software System Interface
    • Container Interface
    • Component Interface
    • Business Process

C4 InterFlow - Diagrams Type - Sequence

  • Sequence - a Plant UML Sequence diagram that can be generated for the following Scopes:
    • Software System Interface
    • Container Interface
    • Component Interface
    • Business Process

C4 InterFlow - Diagrams Type - Sequence

The table below summarises diagram Types supported for different Scopes and Level of Details

Scope / Level of Details Context Container Component
All Software Systems C4 Static
C4
C4 Static
C4
C4 Static
C4
Namespace C4 Static
C4
C4 Static
C4
C4 Static
C4
Software System C4 Static
C4
C4 Static
C4
C4 Static
C4
Software System Interface C4 Static
C4
Sequence
Container C4 Static
C4
C4 Static
C4
Container Interface C4 Static
C4
Sequence
C4 Static
C4
Sequence
Component C4 Static
C4
Component Interface C4 Static
C4
Sequence
C4 Static
C4
Sequence
C4 Static
C4
Sequence
Business Process C4 Static
C4
Sequence
C4 Static
C4
Sequence
C4 Static
C4
Sequence

Querying Architecture as Code

Both C# and YAML AaC can be queried using JSON Path-like syntax. Below are just some Use Cases and Examples of how AaC can be queried:

Generating diagrams

When using C4InterFlow CLI to generate the diagrams you need to provide a list of Interfaces, which you'd like to be examined for a given Draw Diagrams command execution. You can list all interfaces by their full paths, but that can result in a lengthy command. You can use a * wildcard to indicate that you want to discover all Interfaces at specific location in AaC. Consider the following examples of query expressions:

Example 1

DotNetEShop.SoftwareSystems.BasketApi.Containers.Data.Components.RedisBasketRepository.Interfaces.*

This will select all Interfaces of RedisBasketRepository Component of Data Container of BasketApi Software System in DotNetEShop Namespace.

Example 2

DotNetEShop.SoftwareSystems.BasketApi.Containers.Data.Components.*.Interfaces.*

This will select all Interfaces of all Components of Data Container of BasketApi Software System in DotNetEShop Namespace.

Example 3

DotNetEShop.SoftwareSystems.BasketApi.Containers.*.Components.*.Interfaces.*

This will select all Interfaces of all Components of all Container of BasketApi Software System in DotNetEShop Namespace.

Example 4

DotNetEShop.SoftwareSystems.*.Containers.*.Components.*.Interfaces.*

This will select all Interfaces of all Components of all Containers of all Software Systems in DotNetEShop Namespace.

Example 5

DotNetEShop.SoftwareSystems.*.Containers.*.Interfaces.*

This will select all Interfaces of all Containers of all Software Systems in DotNetEShop Namespace.

Example 6

DotNetEShop.SoftwareSystems.*.Interfaces.*

This will select all Interfaces of Software Systems in DotNetEShop Namespace.


Home   CLI   Samples   Q&A   How‐to guides   Quick‐starts   Tutorials


Note: This document is subject to change. Users are encouraged to check back regularly for updates.