Optimal Software Architecture

28 Aug, 2018

How much time have you spent contemplating the architecture of the code you’re about to build, minutes, hours, meetings? All too often we end up spending hours exploring new architecture ideas and patterns that we all too often only partially understand before we dive into building something. We talk about how magically scalable the code is, and how we could easily hot-swap this piece for that, and how by taking these three parts and making them into packages we maximize the reuse of this code. We spend hours debugging code that holds three degrees of abstraction from the original task it was designed to solve. We ache over these details attempting to show the world just how smart we are. Though this is certainly a bit of a crass view, I’m sure that many developers can relate to one degree or another.

So what then is the best way to determine the architecture of an application? I believe that the only true way to find good architecture is to follow the path of least resistance and replicate the evolutionary process as much as possible. When we look at the process by which organisms evolve we can see that there is nearly no ‘rationality’ to the process. There is no definitive end goal except to serve a purpose. Take the human eye for example. In actuality its a terrible design, it actually creates a blind spot in its centre which the brain has to ‘fill in’. There is no fundamental rationality to this. As such I think code should be developed in the same manner.

A project should begin by examining and understanding the end goal of the project. What functionality is mandatory for this application to achieve its goals. From there, code should be developed in a MUST HAVE manner, and should be written in the simplest form possible. Not straining over things like typecasting, facades vs injections, and how many layers of abstraction you think is ideal. There is no IDEAL amount of abstractions. Code should follow style standards and should at all times be concerned about readability. On the initial build of a functionality, efficiency should be the LAST concern of the developer. This isn’t to say that one should negate all possible efficiencies and write poorly constructed code, a developer should write what they feel works well, while not over-concerning themselves with minor gains that take significant time. The main concern of a developer when first building something should be to make sure that another developer can easily understand what this piece of code is trying to do. Its not exactly that the goal should be to build ugly code, but, that its ok to have ugly code in the initial steps of development. Though you should have some degree of testing coverage, its ok if its covered by another overlapping test. Initial development is a prototyping practise.

The industry as a whole has attempted to escape this scientific process and leap to the perfectly rational flawlessly architected solution that should be built from day one. In my entire career I have never seen this be a reality. Every project I have ever worked on, in enterprise companies and small marketing firms has had to be refactored largely to adapt to the new demands put upon it. Though there are general practises that can make this process easier such as modular design, and micro-services but these are simply paths of least resistance for code to evolve through. Refactoring is an inevitable component of developing high quality code. Rather than forcing the selection of an ideal code architecture at the initial build of a project, build using evolutionary processes.

The only certainty in this world is that all things change. It’s best to accept that whatever code you write today you’ll likely refactor or delete tomorrow.

Written by: Matt Lantz