Every pattern has its cost - An approach to simple systems design

Michael Seifert, 2020-04-20, Updated 2020-10-01

I recently stumbled over a question on a popular Q&A site. The author decided to use the Backend-for-Frontend pattern, because they expected numerous different Frontends and wanted to keep the system easily extensible. The author wondered how to prevent code duplication accross different backends, but ruled out adding additional packages. Here is the thing: Every pattern comes with a benefit, but also a cost. When I decide to use the Backend-for-Frontend pattern, the benefit is that individual frontends can be developed independently from each other. The cost is increased operational complexity. From what I can tell, the author's decision to use the Backend-for-Frontend design pattern was more based on cargo cult than on a cost-benefit analysis.

When I design software systems from scratch, I personally start with the simplest possible solution. Trivially, the simplest solution is having no software at all, but I generally start with a monolith. In the initial draft, the monolith supports all business processes. At some point, there might be different non-functional requirements for different processes. For example, one process needs to be highly available, or one process will be supported by an additional development team. At this point, we can start talking about extracting a service from the monolith. The description of the decision making process is exactly what should go into the decision log of the architecture documentation. If you cannot argue why a specific design decision was made, you have probably made it for all the wrong reasons.

Software is complicated enough on its own. It is the responsibility of the architect to only apply design patterns whose benefits outweigh their costs. A simple design will result in lower development, operational, and maintenance cost compared to a functionally equivalent complex design.