Why I use C4 diagrams before writing code

When people talk about software architecture, they often imagine large UML diagrams, lengthy documentation, and numerous blocks connected by arrows. In practice, such diagrams don’t always help quickly understand a system. The diagram may appear complex and “architectural,” but it still doesn’t answer the main questions: how the system is actually structured, what parts it […]

Category

Technologies

Posted

Taras

Sep 10, 2026

When people talk about software architecture, they often imagine large UML diagrams, lengthy documentation, and numerous blocks connected by arrows. In practice, such diagrams don’t always help quickly understand a system. The diagram may appear complex and “architectural,” but it still doesn’t answer the main questions: how the system is actually structured, what parts it contains, and how they interact.

For me, architecture should primarily provide the team with a common technical context. If developers, architects, and the product owner have different understandings of the system’s boundaries, the responsibilities of individual modules, and the relationships between them, then even a simple discussion of new functionality begins to take longer than it should. In such cases, the problem is often not the chosen framework, database, or programming language, but rather that the team lacks a unified picture of the solution.

Problem

When designing a new project or connecting to an existing system, you typically have to deal with several layers at once: services, APIs, databases, background tasks, web applications, mobile applications, and external integrations. These stages rarely include specific architectural details. First, you need to establish a general view of the system and the overall structure of entities, defining the main aspects of the application.

This stage is fundamental, and without it, the rest of the process cannot be completed. Documentation can be outdated or nonexistent, diagrams can be overly detailed or, conversely, overly general, and important architectural decisions are often left to team members. As a result, new team members spend time reconstructing the overall architecture of the system or components rather than implementing the task.

C4 Model

I use the C4 Model for situations like these. This approach, rather than attempting to show the entire system in one large diagram, divides the architectural description into several levels of detail, where each level highlights its own important aspects of the system.

The context level shows the system boundaries, users, and external dependencies. The container level reveals the main executable parts of the solution: applications, services, databases, and APIs. The Component level shows the internal organization of a single container, such as the Backend API. The Code level is used only when it’s truly necessary to delve into implementation details: classes, interfaces, methods, and the relationships between them.

This approach helps avoid mixing business context, infrastructure, the application’s internal structure, and code details in a single diagram. The team first sees the system as a whole, then gradually moves to more technical levels, without overloading each diagram with unnecessary detail.

Example: Payment Flow in an Online Store

For this example, let’s take an online store where a Customer creates an order and pays for it through an external Payment Provider. It’s important that we show the same payment flow at all three levels, rather than different parts of the system. Only the depth of detail and which elements are important at a particular level vary.

At the Context level, it’s sufficient to show three elements: Customer, Online Store, and Payment Provider. At this level, there’s no need to show the database, Backend API, or internal components, as the main goal is to define the system’s boundaries and demonstrate that the online store uses an external provider for payment processing.

At the Container level, we expose the Online Store and show its main components: the Web Application, Backend API, and PostgreSQL. The payment flow itself remains the same, but it’s now clear which runtime components are involved in the scenario: the Customer interacts with the Web Application, the Web Application sends a request to the Backend API, the Backend API stores the order data and accesses the Payment Provider to process the payment.

At the Component level, we expose only the Backend API and no longer describe the entire system. Here, it’s important to show the internal division of responsibilities within the application: the Order Component is responsible for order creation and process coordination, the Payment Component interacts with the Payment Provider, and the Order Storage Component stores the order and payment status in the database. This is still the same payment scenario, but now it’s shown from the perspective of the internal structure of the Backend API.

The main advantage of C4 is that the same system is described sequentially, rather than through a set of unrelated diagrams. A Product Owner might use a Context Diagram to understand the system’s boundaries and external dependencies. A developer often uses a Container Diagram to see the main applications and the relationships between them. An architect or senior developer might use a Component Diagram to discuss the internal division of responsibilities and dependencies within a specific container.

This approach helps avoid overly cluttered diagrams that simultaneously show users, databases, APIs, classes, queues, external systems, and internal modules. When all of this is crammed into a single diagram, it quickly becomes difficult to read and loses its primary purpose—explaining the architecture.

C4 as Part of Design

I don’t view C4 diagrams simply as documentation to be created after development is complete. They are most often useful before coding, when you need to design new functionality, check dependencies, and determine whether unnecessary complexity is being introduced into the solution. Even a simple diagram can quickly reveal problems that are harder to spot in text or during a discussion: unclear component responsibilities, missed integrations, unnecessary calls between services, or an overly complex data flow. Fixing such issues in a diagram is much cheaper than changing the implementation after development or troubleshooting the problem in production.

Benefits for the Client and Team

From the client’s perspective, whether .NET, Java, or Node.js is used internally is usually less important. It’s far more important that the system is understandable, maintainable, and extensible, as this impacts development speed, the cost of changes, and the risks associated with future product development.

When the architecture is clearly described, it’s easier for new developers to join the project, easier for the team to discuss changes, and technical decisions become more transparent to all participants. This is especially important on long-term projects, because the system changes, the team may change, new requirements emerge, and without a common architectural context, the project gradually becomes more difficult to maintain.

Summary

I’ve used various approaches to describing the architecture, but C4 is the most practical. It’s simple enough for discussion with the business and implementation by the development team. Instead of one large diagram that tries to show everything at once, C4 allows you to describe a system layer by layer. First, show the overall context, then expand on the main containers, and finally dive into the internal components of a specific application. Sometimes, three short diagrams are enough to explain a solution better than several pages of technical documentation.

To discover more about how our team could help your team with a custom solution of other technology needs, schedule a free assessment.