Mastering the Fundamentals: Five Principles of Software Architecture
Written on
Chapter 1: The Role of Accountability in Architecture
When it comes to software architecture, the individuals responsible for its design should be the ones who will be on call for its performance.
Software architecture can be an engaging field, attracting numerous talented individuals eager to share their insights. Throughout my engineering leadership journey, I have received countless unsolicited architectural proposals from enthusiastic engineers who genuinely believe they have discovered the perfect solution to a challenging problem I manage. My immediate question is often, “…will you be taking calls for this?”
This question effectively curbs the enthusiasm of those who are only interested in offering opinions without any personal stake in the outcome. Those who agree to be involved are usually welcomed into the core decision-making group, but such individuals are rarely found.
Ultimately, the architects of the technology should be those who are prepared to respond when issues arise at inconvenient hours. While accountability is crucial in any workplace, it becomes even more vital in engineering.
Many engineers fall into the misconception that there is a singular correct way to approach a project, leading to disputes over technical accuracy. Such disagreements can be complex enough within the on-call team; additional voices clamoring for victory without facing the consequences are unnecessary.
The key to successful architecture lies in ensuring that the team responsible feels confident managing it. Addressing all other concerns comes afterward.
Section 1.1: Starting Simple
"Build it the simple way first." Many efforts to create systems that are scalable and resilient from the outset rely on unrealistic assumptions about operating conditions. This often results in unnecessary complexity that ultimately hinders progress, all due to the fear of appearing incompetent.
From my perspective, it is wiser to initiate with a straightforward and basic design, identify potential failure points theoretically, and monitor them before making adjustments. By doing so, you avoid the complications that arise when a system scales in unexpected ways and can instead benefit from the simplicity of your initial design.
Those legendary tales of the 10x engineer who effortlessly created a system that flawlessly scaled for a decade? Let's be realistic: they are myths. No one achieves that level of perfection, and it is an unrealistic expectation to impose on oneself. The individuals in these stories often remain distant figures—colleagues of colleagues or consultants who have long since moved on. The truth is, these systems are rarely left untouched for ten years; they involve ongoing maintenance and iterations from entire teams.
Keep your architecture simple and address only the issues you currently know exist.
Section 1.2: The Dangers of Over-Optimization
"Optimization can lead to failure." This principle is similar to the previous one, but it often relates to automation. While automating tasks is generally beneficial, each automation introduces a degree of fragility to the system. This fragility arises because optimization depends on generalizing steps or interactions.
As you streamline processes to enhance speed, efficiency, or reduce human input, you risk creating vulnerabilities. The more you optimize, the greater the chance that edge cases will result in unexpected failures. Eventually, if the edge cases proliferate, the system may become so brittle that it fails regularly.
People often assume that all optimizations are advantageous, but any alteration to system boundaries or capacities carries a cost. Establish service level objectives (SLOs) to determine whether further generalizations align with your system’s goals.
Chapter 2: Understanding Graph Databases
"Graph databases can be misleading." I often expect this concept to fade away, yet it persists. I appreciate the power of graphs, but discussions around graph databases frequently come with claims that no other data storage method can suffice.
In reality, the underlying data storage in a graph database is often just a table, typically in Postgres or, in some cases, Cassandra. Thus, if we can utilize a graph database, we are indeed capable of storing the data in a conventional table.
The real issue isn't whether graph databases are beneficial; it’s that engineers frequently idolize technologies they don't fully understand while disparaging those they do. Individuals who argue that graph databases outperform relational databases may lack the knowledge needed to manage them effectively in production. While graph databases have their place and can offer value, you should only opt for one if you can clearly articulate its advantages and limitations.
Be wary of anyone who cannot provide a comprehensive list of pros and cons alongside their recommendations.
Section 2.1: Ownership of Logic in Software
"Don’t let dependencies dictate your logic." This insight is relatively new to me. Like many engineers, I have typically worked in environments where I had direct control. However, my current deployment experience involves a mix of environments I manage, those I do not, and others that are quite complex—often outdated, slow, or resource-constrained.
This experience has taught me a crucial lesson: understand the value of your software and where the logic that delivers that value resides. Make certain that you maintain control over that logic.
In simpler terms, if your software’s core functionality relies heavily on an AWS-managed service, migrating your software away from AWS will be challenging. While managed services and Software as a Service (SaaS) can be beneficial, your initial architectural design should prioritize avoiding dependency locks. Once you identify where the value-creating logic lies, you can confidently integrate managed services.
Owning that logic doesn't necessarily mean you have to write the code yourself. Utilizing open-source solutions is perfectly acceptable—just be mindful of your licenses! Many engineers, myself included, often overlook licensing issues, assuming that anything available on GitHub is free to use in any manner, which is not the case.
Section 2.2: The Challenge of Building Software
Creating software is inherently challenging, and the pressure to do it correctly can be overwhelming. Unfortunately, many of our instincts about how to achieve success can lead us astray.
You should refrain from proposing brilliant ideas unless you are willing to take ownership of them. Keep your designs as simple as possible until you have a clear understanding of your usage objectives. Avoid assuming that technology you don't comprehend possesses some hidden advantages. Lastly, be cautious about relying on third-party products and tools until you fully grasp the value your software offers.
Chapter 3: Video Insights
This video discusses the principles of software architecture, highlighting the importance of accountability in design and decision-making.
In this video, Mark Seemann explores the concept of functional architecture, providing insights into achieving success in software design.