Blogg
Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn
Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn
This is a new blog series (and my first!) that I have christened The black t-shirt architect. I chose this title to conjure an image of an architect with a background as senior developer still very much involved in the code. I hope it also represents the mindset of a constant learner. Also, I think it sounds rather cool.
Software architecture is a very complex endevour and sometimes it is necessary to take a step back and remind ourselves of its core principles. In this blog series I aim to do that by taking a closer look at three fundamental rules of software architecture, each blog post covering one of the three rules. In this blog, the first of the series, we will make a deep dive into the Everything is a trade-off rule. In the subsequent blog posts we will continue by looking at The ‘why’ is more important than the ‘how’ and finally Evolution is inevitable rules. The background for this blog series is a combination of my own experiences and things I learned from this excellent course on Clean Architecture, taught by Victor Rentea.
A few years ago I assumed the role of architect for the first time in a project and as it were I would often be asked to make some decisions on one design aspect or other. The point is that I kept answering “Well, it depends…” to these questions whenever they first came up. I revisit this earlier episode of my career because it high-lights a fundamental problem with software design and the first rule of architecture rather well. Everything is a trade-off. There are no simple answers. Let’s try to embrace that!
Before we get to what all this means for us as software architects and how we can approach these trade-offs in a pragmatic manner, let’s just take a moment and go through some examples of trade-offs you might be faced with as an architect to make sure we talk about the same things.
An obvious example of architectural decision with significant impact on the end product is which architectural style to go with. Should we develop a distributed system with microservices or a monolith? Potentially gaining independent scalability and technological flexibility at the cost of increased operational complexity, greater challenges in keeping data consistent and probably significantly longer time to develop an MVP?
Having made that decision you will be faced with the next decision, how do you structure the code in your executable deliverables (i.e. microservices, monolith, modulith, etc.)? Do you go with e.g. a layered architecture or hexagonal architectural style? Layered architecture is probably the most intuitive architectural style for most backend developers, making it easy to adopt and understand, it provides clear separation of concern where each layer has its clear purpose, but compared to e.g. hexagonal it can be harder to isolate the domain from external influences which among other things affect how easy it is to test your core business logic.
The last trade-off decision I want to examplify is a central decision for how you design your domain. It is a decision on where you put the weight of your domain logic, the domain constituting the data and business rules of your, well, domain. Do you separate the data structures into value objects handled by service classes i.e. an anemic domain model, or do you incorporate the business logic with the data into rich domain object?
The trade-off in this case often comes down to a decision between a simpler domain with data objects that map nicely with your database and business logic encapsulated in service classes that should be easy to test or a richer domain model where data validation and state transitions in the domain are controlled by the relevant domain objects themselves making for a cleaner object-oriented design that typically maps nicely to a ubiquitous language of a domain driven application.
So, these are just three examples of trade-offs that have significant affect on the architecture of an application, but there are of course many more. I also want to point out that many of these trade-offs are of course not all-or-nothing, many times it is a question of which direction to lean towards. So how do we navigate these trade-offs?
There is a lot of truth in the saying “assumptions is the mother of all [explicit] ups”. Assumptions and pre-mature decisions makes us inevitably break the first rule of architecture by not properly evaluating the implicit trade-offs in our decision. Of course, in order to avoid jumping to conclusions we need to have a good understanding of the pros and cons implied by our decisions as well as the available alternatives.
This might sound like a simple execise of making a table of pros and cons for each alternative and determine which one matches the business and project requirements best. But that explanation ignores, in my opinion, the most important aspect of software development in general: contrary to how most people would characterise software development as a technical execise, I see it fundamentally as a social endevour.
I think jumping to conclusions is a social trap. We want the group to recognise our contributions so we are pushed to provide solutions to problems before we have had time to fully analyse the problem. We all also carry with us a strong bias to solutions that we have seen work in the past and if we are not conscious of these biases they can easily make us classify these solutions as “good design” and other alternatives as less worthy of our respect.
A time-tested countermeasure to many of the problems mentioned above is to involve others in the decision process. You might be the architect with capital ‘A’, but you don’t know everything. Invite other team members to go through and discuss the different alternatives. However, if you are the architect and ultimately responsible for the system architecture, make sure you own the decision. Bring others in to gather perspectives and aim to build a common understanding, but know that ultimately any decision involving trade-offs will have different people favoring different solutions.
In an earlier project I worked on we needed to make a decision: continue with the development of a new central platform that potentially would result in several important improvements for the business, even though the project had gone over-due and significant further investment would be necessary for it to reach completion, or cancel the project and loose all the time and resources already invested and instead steer those resources to improve the old legacy platform?
Ultimately the decision was a business decision, but it would depend heavily on what our team would eventually recommend. So how did we go about it?
First, it is worth noting the ‘we’ in that question: this could never be a one-man job. Both the scale of the problem but also the political aspects and concequences for different teams at the company made it essential to bring in different people with different perspectives and expertise.
Second, without going into too many details, we composed over a sequence of sessions a long list of pros and cons for either option. Finally, we added the ‘secret sause’ of decision-making: we iterated. By that I mean that we iterated over the list of pros and cons, discussing the different points openly and with the common understanding that this decision would need some time to develop. This is where the magic happens, although we in the team initially had different perspectives on the situation, after iterating the pros and cons and discussing each one openly for a number of long Teams™ sessions we would eventually converge on an agreed recommendation.
Was it the right one? Well, unfortunately we will never know, since no alternative universe where the opposite recommendation was made is reachable. But at least a decision based on a thorough analysis was made and everyone seems satisfied with that, so maybe that is good enough. Finally, when evaluating different options to any question, please remember: bring in different perspectives, and if the question is complex, allow for time to iterate over the pros and cons.
The first rule of architecture tells us that everything is a trade-off. This means there are no universally good or bad decisions. It is however extremely easy to jump to pre-mature decisions, sometimes because we are unaware of the implicit concequences of our decisions and sometimes because of psychological reasons: biases, fashion and trends etc.
Even if we are careful and take into account the various pros and cons of different options, reaching a decision can still be hard. However, as a black t-shirt architect it is useful to remember that as long as you do your due diligence in analysing the problem, listen to your co-workers and are conscious of your own biases… Then you are certainly ready for the next part of this blog series! In the next part we will deep-dive into the second rule of architecture: ‘The why is more important than the how’.