Having been writing about and practicing software architecture for some years, I’m going to start by loosely describing a “fast start” software architecture plan, from requirements to code.
Firstly a warning. This fast start will work perfectly well in 10% of cases. Only 10%. There’s a reason for that, and it’s because in about 10% of cases a software architect joins a project at the very beginning and is given a set of requirements, user stories, use cases or similar, and is allowed to architect and design the system from that point onwards. Yes in my experience that only happens in about 10% of cases and that is the “first world” or “happy case” scenario I’m going to cover here.
To be honest, and somewhat blunt, this does not happen in the other 90% of software projects. In 90% of software projects, there was an idea for a project and some developers got together, maybe with a bit of funding, and started hacking on some code until they had something that basically worked some of the time. In the startup world we call that a “MVP” or “minimum viable product”. Once the project has been running for a few years, perhaps when the original team has left and the project owners now realise that the code is an unmaintainable mess that is full of bugs, they will call in a software architect to “fix stuff”.
That case covering 90% of projects is a whole different set of topics and I’m not going to cover it in this article, I have a further article in preparation with that case in mind.
I use the term “requirements” to cover, loosely, a big range of possibilities. You could get hold of a big book of requirements. You could be in receipt of a bunch of smaller business requirements documents (BRDs), each describing one small part of the system. You could have a bunch of use cases, or user stories, describing various interactions that users have with the system. Or, as frequently happens in start-up land, you could have a product owner, founder, project manager, or even a 17 year old kid chatting down the phone at you for a couple of hours describing their great new idea. Somehow you have to build something out of this.
The first step is of course to stop, step back, and look at what the whole system is trying to achieve. A simple product goal statement or something like that, to give you a bit of context for the system as a whole.
The first question to ask is “why?”. It’s important to ask this about any software requirement. Let’s say that you have someone come to you and ask you to build a bridge. You could start on the bridge building project right away. However, you could also stop and ask “why do you want a bridge?” — and in response you might get an answer like “because I want to get people across a river”. Now let’s imagine the scenario where there’s a shortage of construction materials, stone, concrete, steel and all of those other materials that you need to build a bridge are in short supply and very expensive. However you do happen to know where to get hold of a number of very cheap and well equipped boats. So by asking the question, looking for the rationale behind the requirement, you can achieve the same goal but at a lower cost. This questioning of the rationale is something that you should always continue to do at every stage of the requirements process.
It’s important to understand that the job of the software architect is not to write the requirements, but it is the software architect’s job to read, analyse, and understand the requirements.
An important first step in this process is building a project glossary. I have already covered this step in an article “What is a Project Glossary?”. It doesn’t matter what stage of a project that you’re at, building a project glossary is a huge benefit in being able to understand both the meaning and the rationale of the requirements.
Now it’s time to make a few decisions.
Which path is the development taking? Are we going to have microservices or are we going down the path of a full stack application? Do we need a message bus of some kind?
What languages and frameworks are we going to use? How are we going to scale this application, and how important is performance? Do we need to squeeze every last drop of CPU performance out of our hardware (C, C++), do we consider performance to be critical but still want flexible code (Rust, Golang), do we need good performance and ability to scale but more critically we need to be able to maintain this application longer term (NodeJS, Java), or are we prepared to sacrifice performance so that we can build the system as quickly as possible (PHP, Ruby, Python)?
A lot of these decisions are going to come down to your experience as a software architect. You don’t get to put “architect” in your job title or print it on your business card without getting a few grey hairs along the way.
The next decision to make is about software modelling. Should you do it or should you not do it? What is to be gained from it? Which modelling approach should you choose.
Effective software modelling is a complex topic, and not one that you’re going to become an expert in by spending 20 minutes reading a blog post. You’re going to need to put in some serious research and study here, about the different modelling techniques and what they have to offer.
I have already dived into both ICONIX Process and C4 Modelling in previous articles. If you’re unsure as to which approach to take, I suggest a bit of both. As a starting point I would begin with the very first model of the ICONIX process, being the Domain Model. In many cases I would stop there — the hybrid dynamic / static modelling approach used by ICONIX is far too heavy for most software projects.
If you’re considering a microservice approach for your application, I would then consider building the first two models of the C4 model, those being the context and then the container diagrams. The context diagram allows you to see where your system sits in relation to the rest of the world — external interfaces, etc. The container diagram allows you to map out the software components in relation to each other. Once again, I would stop there — unless you are a dedicated waterfall team (and who is these days?), the remaining diagrams in the C4 model are too heavy and detailed for most agile projects.
Microservice vs Monolith
The next decision is relatively straight forwards — microservice vs monolith. A lot has been written about this already, for example:
It’s important to understand that it’s not just a battle of the “old way” monolith vs the “new way” microservice. In fact, for many applications, a bit of a hybrid approach may be the solution. That’s the approach that I take in many applications these days.
Let’s say you’re building a customer facing application, with an “admin” side which only a few people need to see (the site administrators). We know that applications that are microservice based with a separate front end application are frequently more performant than monolith / MVC applications, and that’s because the load of rendering the front end pages are spread to the browsers of the customers who are using the application. So in this case it makes more sense to have a microservice based application.
However the administration side does not necessarily need to have great performance or scalability, and that’s because there are only ever going to be a few staff using that. So it may be better to take a rapid application development framework of some kind, even PHP / Laravel, and build this administration interface. There are many ready-to-use kits out there that can assist in building out a simple administration application, usually in languages like PHP, Ruby, Python, etc. Use whatever you are comfortable with, and don’t stress too much about performance.
There is an important mantra to remember when tackling the question of software design: It is not the role of the software architect to do the software design. It is the role of the software architect to guide the software design. However, in many cases, you may find yourself filling the role of both software architect and software designer, and so it’s important to understand how all of this design comes together.
About now is the time to tackle the question of domain driven design (DDD) and why I believe that you should be doing it. Other than that you have already built a domain model, and so you’re half way there, I believe that DDD is important for the following reasons:
- In a microservice based system, it clearly defines how and why to separate your microservices.
- In a monolithic system, it defines how and why to separate your code into modular components.
- Overall, it produces better code structure than traditional MVC (see the article MVC is Dead for some of the issues with MVC), which reduces future maintenance costs and builds the software with lower costs overall.
I won’t do a full explanation of DDD here, but instead I will point you at some articles which you should read through:
- https://medium.com/swlh/domain-driven-design-and-microservices-c62255790c3b — explains the building blocks of DDD and how they apply to microservices.
- https://medium.com/@charly8182/domain-driven-design-for-humans-context-subdomain-and-relationships-bad2614325f9 — has a good human-readable explanation of what DDD is and how the various “contexts” within DDD hang together.
- https://medium.com/swlh/microservices-poweredby-domain-driven-design-6160fcac5409 — gives some more detailed explanation of the components of DDD.
One key feature of modular architecture here that I believe is important, that has not been covered by the above articles, is that the domains, contexts, etc, within DDD should be based on the Domain Model that you have already drafted, based on the initial Project Glossary.
Mapping is the process by which one entity is marked as connecting to another entity.
By “mapping”, in modular software architecture, we usually mean the mapping of requirements onto domain model objects, and also the mapping of domain model objects onto code.
In Domain Driven Design, it’s important to extend that design into code by taking the following approach:
- Mapping the domains and subdomains into “modules” within your code. That means steering away from the traditional MVC code structure towards a code structure that implements the DDD design that you have planned. As I discussed earlier in the article MVC is Dead, the code structure should look like this, and not like an MVC code structure:
- Mapping the requirements into design and then into code. How this is done may depend on what format you have your requirements in — for example if you have user stories, then you would make a mapping of which user story (or stories) are going to be implemented in which of your domains and subdomains within the code structure. Making this clear to the developers and to the project team is important for 2 reasons:
- (1) It tells the developers what to code, and where.
- (2) It provides a level of proof, to the project team and product owners, that your code meets (or at least intends to meet) all of the functional requirements that they have listed for you to meet.
Modular architecture is all about mapping. You need to understand the mapping process, how it works, and why to do it.
There are some software tools out there that can greatly assist with mapping to this level — Enterprise Architect by Sparx Systems for example. Or simply you can use a spreadsheet with columns for domains and rows for user stories or other requirements.
Documenting and Presenting
I worked at an organisation recently where the solution architect had done some excellent modelling, based on the C4 model. His diagrams were detailed, well laid out, consistent, logical and had a lot of work put into them.
During a review meeting, I put up one of the diagrams on the screen in front of the audience, which was all of the engineering team leads. I’m not going to replicate the exact diagram but it was a container diagram, not dissimilar to this one from c4model.com:
I then asked the audience “what does this diagram mean?”.
After a few moments of head scratching, one of the team leads finally answered “I don’t know”.
There is an important lesson to be learned there: Always write something from the point of view of the reader. Never write something from your own point of view.
I understood perfectly what that diagram meant, as did the solution architect. The software engineers had no clue, and that was the problem because the audience, the reader of that diagram, was the software engineering team. So each and every one of your diagrams needs to have a level of explanation and presentation that is sufficient for the audience of that diagram.
We have software architects for one reason — software architects have ONE JOB. If you’re not documenting, presenting, explaining and detailing your architecture to the audience, the readers of that architecture, then you are not doing your job.
As I said at the start, this article is a “happy case” of software architecture which we know that, out in the real world, will not happen 90% of the time. However it’s important to understand at least this much before we discuss diving into the hot mess that is 90% of software projects in the real world.
Take away from this what you will.