Zlatin Stanimirov
3 min readOct 4, 2023

Code Architecture as Diagrams Part 1

Diagrams have been here for a while and are here to stay.

Using diagrams to showcase software architecture is nothing new.

You have several language models like UML and C4 that focus entirely on that. These diagrams are usually written and maintained by architects (regardless of the kind) and are done before development begins. Their goal is usually to show something specific, so several diagrams for the same thing may exist, usually showcasing different aspects.

Maybe the communication flow, maybe the entity relationship. Maybe it is a high-level functional flow or a lower-level technical implementation.

Many attempts have been made to then generate code blueprints and boilerplate based on these diagrams. Although there are some successful attempts I have seen, unfortunately closed source, most of the time this was unsuccessful.

Diagrams don’t reflect the truth.

Diagrams don’t really reflect the truth; they reflect a version of the truth — the initial design and what actually gets implemented are fairly different things. There are many reasons for that, the most common are changed requirements, misunderstanding on the architect’s side, changes that decrease development time/time to market.

Don’t get me wrong — these diagrams are very useful in the early stages of development and somewhat useful when onboarding a new team member. I was wondering if diagrams can be useful throughout the entire software development lifecycle.

So far the answer is: “Yes, but not drastically”.

In this article series, I will share my journey of experiments trying to find a way to simplify software development with diagrams.

If a picture says 1000 words…

The assumption I am working with is: “If a picture says 1000 words, then being able to automatically generate the correct diagram should simplify significantly things like bottleneck discovery, code review, refactoring decisions, and estimates.”

Experiment 1: Periodic Snapshots to view how the landscape has evolved.

At the time, I was working on a heterogeneous microservice landscape. We had Python to host our machine learning models and TypeScript to host the business logic.

The Python services were mostly static once they hit version 1.0. On the other hand, the TypeScript microservices were changing constantly, as business logic usually does.

Furthermore, if you have correctly composed the data science services, the small pieces that do the complicated stuff will change rarely, whereas the flows will change much more often. I experimented with dependency-cruiser, the popular JavaScript and TypeScript library that draws the dependencies.

Note that dependencies in this case mean what file does A use, not what external packages. It is a convenient way to view the high-level code architecture.

Working with dependency cruiser is very easy. I created an npm script that I ran once every 2–3 weeks and stored everything in Confluence.

I know, it is not perfectly automated, but I couldn’t justify the automation without knowing what business value it brings.

The experiment lasted for around 5–6 months before I switched teams and roles in the same company. During the time the experiment was ran it was useful for me to self-audit the direction where we were headed.

Things like circular dependencies and modules on different levels of abstraction calling each other were yellow flags for areas that should be refactored, or you should be careful with.

This ultimately turned into automatic validation again using dependency-cruiser. You can see an example repo here. Figuring out a working way to enforce architecture rules was great.

To my knowledge, the validation rules are live in the project to this day, although they have evolved over time.

This is a practice you likely want to include in your own project if you haven’t already. Think of it as a lint of the high-level architecture.

Appetite comes with eating.

As we should favor more and smaller files than fewer and big files, the graphs for even mid-sized projects looked scary, let alone big monoliths (modular or not) that have been worked on for several years. The next topic I decided to explore is if we can use these diagrams in a way to simplify code review. More on that next time :)