Brandon Sanderson's Laws of Software Architecture
You're either clicking this because you know who Brandon Sanderson is and you're surprised he has laws of software architecture, or you know what software architecture is and you're curious what prescriptions this Sanderson guy has for it. Either way my clickbait title will succeed in getting you to read it hahaha
Just hear me out on this one: software architecture is like magic in fantasy novels. Not perfectly, and maybe they only bear a passing resemblance, but so too do ERD diagrams and building blueprints. I will not explicitly propose that we retitle architects as wizards, but I also won't stop you from reading that into my post here.
Magic systems are created by authors of fantasy novels to provide a foundation for the narrative and parameterize how magic solves problems within the text. Corollarily, software architectures are created by engineers of applications or systems to provide a foundation for the solution and parameterize how architecture solves problems within the code.
QED, right?
Right?
Okay, I get that any two disparate concepts can be molded into being analagous on a whim; the point of drawing an analogy isn't to assert that the analogy exists, but to use the analogy as a tool to learn about its subject. How can this particular analogy teach us about software architecture? Apart from that software engineers are probably disproportionately well-versed in the fantasy genre, there has been quite a bit written about magic systems from the perspective of developing the magic system and the system's impact on narrative; carrying these aspects across the analogy reveals that these speak to relatively less-well-commented-upon aspects of software architecture.
The author Brandon Sanderson might well be the most-cited understander of magic systems, to the point that even the most cursory research into narrative magic will immediately uncover his Laws of Magic: three laws he developed to ground the development of these magic systems. I propose that these can easily be analogously understood to apply to software architectures, and that this exercise reveals some considerations we should probably keep more at the fore in our architectures. Sanderson's Laws, which I will recontextualize below, are (from Wikipedia):
- An author's ability to solve conflict with magic is directly proportional to how well the reader understands said magic.
- Weaknesses, limits and costs are more interesting than powers.
- The author should expand on what is already a part of the magic system before something entirely new is added, as this may otherwise entirely change how the magic system fits into the fictional world.
1. Our ability to solve problems with architecture is directly proportional to how well we understand said architecture #
"Well duh," I hear you thinking, "of course we need to tell our colleagues what the established architecture is!"
Certainly, the architecture should be documented. More fundamentally though, the architecture should be documentable. If you need to take two weeks to slop together a 100-slide powerpoint to teach me a system's architecture, I won't understand it. Similarly, if you find a way to encode an extremely complex architecture into a short description, I still won't understand it. If your architecture can be explained in Basic English in a well-contained blog post then I can understand it.
This seems like an obvious point to make, but I find more often than not that obvious points need to be made: if I don't understand your architecture, I can't use it to resolve my problems. I can't use it, I can't conform to it, I can't do anything with it.
2. Constraints are more helpful than prescriptions #
"Use algorithm X"; "ServiceY sould be used when..."; "Implement the Z pattern if..." and so on are prescriptions. Prescriptions are necessary, to be sure. They're not guiding though, even if they seem like it. They don't establish any boundaries for the architecture, they're never universally applicable, and interestingly they don't really convey the intent of the architecture.
Constraints, on the other hand - "Don't use System.Reflection in runtime code"; "Serializable models must be immutable" - are more powerful, applicable, and helpful. These give the real boundaries wherein the solution must fall. If I tell you that we can't use reflection at runtime, you know my intent is performance.
3. Elaborate on existing architecture before adding new rules #
Or, I could translate this one as:
- When writing code, just conform to the existing understanding of the architecture instead of trying to conjure new patterns, or
- Don't expand the arch docs until you really need to, or
- Be restrained in describing the architecture
No system needs an architecture with a thousand bullet points (remember understandability), and no set of future problems can be comprehensively predicted by any architectural prescription (remember constraint > prescription).
When you have some properties of your architecture, understand them, and let that be your architecture. You'll know when it becomes too limited to be a useful problem solving tool (meaning it needs expansion), and you'll know when it becomes a liability preventing appropriate solutions (meaning it needs altering or reduction). We don't need to anticipatorially add anything to the architectural canon, nor do we need to be too eager to edit it.