Over the last fifteen months, many electrons have been expended discussing the relative merits of the application architecture styles commonly referred to as microservices and monoliths. Both styles have their advocates, and the interesting aspect is not their differences, but their agreement on one core principle – modularity. Both camps seem to agree that “good” architecture is modular and loosely coupled. The disagreements lie more in the realm of whether the enforcement of modularity via physical distribution is worth the increase in complexity, latency, etc.

Structure and behavior are primary concerns for architecture in general and software architecture in particular. Given the pace of change, flexibility is a critical concern for software systems, especially in light of Grady Booch’s definition of architecture as “the significant design decisions that shape a system, where significant is measured by cost of change”. It follows that effective design can be characterized as design where the cost of change is in line with the nature of the change (e.g. simpler changes should cost less, extensive changes should cost more). In addition to initial effort, risk of side-effects and re-work needs to considered as part of the cost of change. As Charlie Alfred noted:

Cost of change and rate of change are concepts shared across a variety of types of architecture. Frank Duffy and Stewart Brand developed the idea of shearing layers to describe buildings as “…several layers of longevity of built components”: Site, Structure, Skin, Services, Space Plan, and Stuff. The key to flexibility in this model is minimizing the constraint of faster changing layers by slower changing layers. A recent tweet from Alistair Cockburn quoting Kent Beck illustrates that these concepts are applicable to software architecture as well:

The common structural patterns in application design are layers for technical concerns (UI, business rules, persistence), vertical slices for functional concerns, or a combination of the two (which I call dicing). Rate and cost of change should inform how the application is componentized, with the emphasis being put on enabling change with minimal effort and risk. Avoiding inappropriate semantic coupling (coupling via the sharing of concepts) is important whether partitioning logically (via namespaces) or physically (by package or by distribution).

The key to dealing with change is flexibility. The key to achieving flexibility is ease of replacement. Modular structure and loosely coupled associations enable that ease of replacement. Understanding and making use of shearing layers enhance our ability to create and maintain that structure. Good fences may or may not make good neighbors, but they do keep the neighbors from messing about in each others’ yards.