Architecture Components

Thoughts on architecture components and software stability.
In this article we also discuss one approach to evaluating architecture quality.

Software Architecture is about drawing boxes and arrows.
– Some architect

Architecture Quality Challenge

Evaluating software architecture is difficult. Unlike performance or test coverage, architecture lacks clear, objective metrics. Most assessments rely on expert judgment, which are often subjective and inconsistent.

This is a problem because architecture has a huge impact on maintainability, scalability, and delivery speed. To move beyond intuition, we need some indicators to measure architecture based on component relationships, dependencies, and change impact. This article explores one approach, using graph-based analysis to uncover hidden complexity and assess architectural quality.

Architecture Component (box)

An architecture component is a unit of software with a clearly defined responsibility and interface.
In diagrams, it is “a box” - but its physical form can vary depending on the architecture style and point of view. It might be a folder in a monorepo, a class module, a shared library, or a containerized microservice with its own database.

Regardless of form, a component has two essential traits:

Well-designed components also tend to be:

In other words, components divide complexity and create boundaries that make the system understandable and maintainable. They are the atoms of architecture.

Dependency (arrow)

Components rarely operate alone. They collaborate by calling each other’s interfaces, forming dependencies. In architectural diagrams, these relationships are shown as arrows: if component A uses component B, we draw an arrow from A to B.

The direction of the arrow is crucial. It tells us who depends on whom.

If we change A (e.g. adjust its logic or interface usage), only A needs to be tested.

But if we change B (e.g. modify its interface or data model), this may affect all components that depend on it, including A:

This makes B more critical in the architecture - it sits upstream, and changes to it have a wider impact. Components with many inbound arrows often need stronger contracts, better test coverage, and more cautious deployment strategies.

Transitive Dependency

Dependencies can be transitive. If A depends on B, and B depends on C, then A indirectly depends on C

In this setup, a change in C can go through B and break A, even if A has no direct connection to C. These chains of dependencies increase the system’s fragility and make reasoning about change more complex.

Circular Dependency

Circular dependencies are even more sneakier. If components form a loop A -> B -> C -> A - then each one indirectly depends on itself.

Just think how fragile it is. This breaks modularity. A change in any component affects the entire cycle. Worse, the cycle hides these effects, making them difficult to test or isolate. Circular dependencies should be avoided or broken explicitly through architectural refactoring.

Case Study: Website “Go Bananas”

Let’s apply our ideas to a concrete example. Imagine a grocery delivery website called “Go Bananas”. From a user’s perspective, it’s simple: they open the site, find a product, check availability, add it to the cart, place an order, pay, and wait for delivery.

But architecture is about perspective. For the end user, it’s just one system. For a UI/UX designer, it might break down into two broad areas: the UI and “everything else.”

A software architect, however, sees a more complex structure - a system made up of distinct components, each responsible for a part of the functionality. Let’s break the requirements down and map them to functional units:

From a single user actions sequence, we now have a system composed of six components:

Component diagram (boxes and arrows)

A component diagram is a visual representation of a system’s structure. It uses the basic architectural building blocks we’ve discussed: boxes for components and arrows for dependencies. It shows how different parts of the system interact and rely on each other to fulfill business processes. Such diagram is a key tool for analyzing architecture - it reveals dependency chains, coupling, and potential hotspots that affect maintainability.

Now let’s return to our components in the “Go Bananas” system and connect them with arrows to form a component diagram.

Here is the complete diagram:

This diagram captures both component structure and data flow, which are key to understanding how the architecture behaves during change. At this stage, we’re not judging whether this is “good” or “bad” architecture - we’re focused on mapping the relationships clearly. This sets the foundation for analyzing system maintainability.

Maintainability Use Cases

What happens if we change something?

We’ll walk through a few scenarios and highlight all components affected by the change, directly or transitively.

Case A: Change in ecommerce

Let’s say we update the UI layout, add a filter, or redesign how items appear to the user. This affects only the ecommerce component. Since it consumes data from other components but doesn’t expose its own interface, the change is isolated.

Impact: Low. ecommerce can evolve independently as long as its usage of other components remains unchanged.

Case B: Change in products

Now imagine we change the product schema - rename fields, restructure data, or split categories. This breaks consumers of the products component, namely ecommerce, orders, and assortment.

Impact: High. products is upstream of multiple components. Any changes must be coordinated and tested across the system.

Case C: Change in orders

Suppose we redesign the order lifecycle or adjust how order validation works. This affects only ecommerce (which sends orders).

Impact: Medium. Despite orders is a central component with many inbound and outbound connections, the way we designed it has pretty isolated changes.

Case D: Change in payments

We might update payment provider integration, add fraud detection, or restructure transaction handling. Since payments is used only by orders, the change is relatively contained.

Impact: Medium. Changes in payments may require minor adjustments in orders, but are unlikely to cascade further.

This type of impact analysis is a powerful tool for objectively evaluating maintainability. The more isolated changes can be, the more maintainable the architecture is. Components with high fan-in or fan-out are more expensive to modify and should be designed and managed with extra care.

“Hot” Components

Now that we’ve explored how changes in one component can affect others, let’s look at the architecture through a more quantitative lens. Some components are hotspots - they are connected to many others and become bottlenecks for development and maintenance. The more central a component is in the dependency graph, the more “expensive” it is to change.

We can start measuring this by calculating three metrics for each component:

These metrics help identify overloaded components - ones with high inbound or outbound coupling - which can signal risk, fragility, or the need for architectural refactoring.

Metrics for “Go Bananas”

Let’s apply this to our current component diagram:

Component     | IC (Inbound)                         | OC (Outbound)
--------------|--------------------------------------|-----------------------------------------------
ecommerce     | 1 (user)                             | 3 (products, assortment, orders)
products      | 3 (ecommerce, assortment, orders)    | 0
assortment    | 2 (ecommerce, orders)                | 1 (products)
orders        | 1 (ecommerce)                        | 4 (products, assortment, payments, delivery)
payments      | 1 (orders)                           | 0
delivery      | 1 (orders)                           | 0

Observations

Why This Matters

Overloaded components can slow down teams. A single change may require coordination with multiple services, broader test coverage, and longer release cycles. These components tend to accumulate complex logic, become harder to reason about, and resist refactoring.

By identifying such components early using simple dependency metrics like Inbound (IC) and Outbound (OC), we can:

In short, structural metrics turn architectural intuition into actionable insight - giving teams a way to spot problems before they become blockers.

mishadoff 30 May 2025
blog comments powered by Disqus