Software architecture is like dominoes

Software architecture is like dominoes.

Tightly coupled dependencies form a sequence of pieces, and if one collapses, it can bring down the entire set.

We employ design patterns and other architectural strategies to ease the friction around change, and to reduce the likelihood of the aforementioned scenario.

Isolating code via techniques like information hiding, interfaces, and the usual set of SOLID principles effectively put a gap between your dominoes.

Breaking up a large business application into many small isolated components allows you to work on one part of the application without worrying about the side effects it may have on another part.

This is one reason I like vertical slice architectures.

Think about the last time you added or updated a feature, or fixed a bug. How often do your code commits touch the entire stack?

A new field needs a DB column, adjustments to the backend persistence logic, supporting fields in the view, and some html and css to top it all off.

Vertical slice design says hey - the entire stack changes together with this feature, so we can couple it together and isolate it from everything else.

They couple an entire feature from front to back like a single line of dominoes, separate from any other feature. When it’s time to enhance or fix a feature, your attention can focus solely on that slice.

You never need to worry about cross-slice interactions - I.E. modifying certain datastructures or algorithms that are used in another slice and hoping your change is compatible.

The decision to reuse any of the infrastructure within that feature is usually dismissed, as it would couple them together (add a domino path) in ways that would require developers to play hot potato with the requirements in both features - the doorway to a ball of mud.

Vertical slice results in less things to worry about and less information to process and recall whilst we do what it is we do as developers.

Our apps then become user interfaces that tie together many tiny services (dare I say ‘micro’?).

Each string of dominoes being tailored specifically for its task rather than forced to fit into the hardened crust of its legacy story.

Breaking up your app like this also allows room for future expansion, if that ever is needed. A comforting benefit, although I’ve found it often doesn’t go that far.

In fact, it’s this breaking up, that often drifts towards over-engineering.

Developers lacking a lot of real world experience tend to go YOLO on design, wanting to employ the latest sexy techniques to test their chops and impress their peers, until (hopefully) reality puts some gristle on their bones, along with a much needed sense of YAGNI.

The quintessential ball-of-mud architecture that results from having no design cohesion at all is like a set of dominoes filling a circle, with each piece angled towards the center.

One false move can cause a week or more of regression testing and fix iterations. An unsafe change in one area causing a chain reaction of issues, expanding outward like the red tendrils of a blood-shot eye.

The ever-present onion architecture is another attempt at lining up our dominoes for stability and ease of change.

Designed more like an automobile - encased in layers of swappable parts and an engine in the center.

I think it works well enough, but as it ages it can drift into incoherence if the boundaries of the architecture are not well-kempt by detail-oriented and consistent dev teams. And like a flat tire, unintended side-effects from coupled components can occur.

How many of us join a company with an existing system that lacks the original devs (along with their original design intent)?

How do you line up your dominoes?