Success (or failure) is mostly about “small” decisions

For some, architecture is all about decisions. Once the biggest and the most important decisions are made, architectural work is considered done. Sadly, the success of your project rarely hinges on those “big” decisions. It is the “small” decisions, the ones we often ignore, where a project’s success lies. The biggest decisions are static; once made they will rarely change. It is the small decisions, the ones we make every day, that will actually determine how easy it is to support new functionality and how productive the team can remain as software evolves.

Let’s examine a few of these architectural decisions.

Big Technology Decisions

The “big” decisions are often technology selection decisions.

Choice of Technology Stack ranks as one of the biggest architectural decision. A few years ago the LAMP stack was the rage. The LAMP stack meant that you would use Linux and Apache. More consequentially it also meant that you would code in PHP and use MySQL as the database. As technologies evolve there are many more combinations today and choices are much more granular.

Choice of Backend is another big architectural decision. Let’s see the impact of choosing Nodejs: The coding paradigm will be event-based and loading sharing will be across multiple Nodejs processes. Most importantly, you will code predominantly in Javascript. You will depend on a number of Nodejs libraries for database access, caching, authentication etc.

Choosing a micro-services architecture is another big decision. Instead of selecting the underlying frameworks or languages, it is based on selecting the runtime architecture. It will let you build services in different languages. However, it will alter how services are developed and deployed.

Library Selections

Today’s development is critically dependent on open source libraries. This is particularly true for web applications. As a result, there are numerous decisions that will be made over the course of the project related to the selection of libraries. These are architectural decisions.

For instance, the choice of a charting library will affect everywhere graphs and charts are displayed. Depending on how much charting is done in the application, the impact can be pervasive.

The use of an ORM library for accessing the database is another such example. We use Bookshelf+Knex for accessing the PostgreSQL. Ultimately, this will limit our choice of databases if we wanted to move away from PostgreSQL to one that isn’t as well supported by our ORM library.

The popularity of open source libraries can be ephemeral. Over time, many open source libraries fail to keep up or their creators move on to bigger and better things. Redux-form was all the rage but now it has real competition. Many of the best choice today may not be the preferred solution in the future. Some may even fall by the wayside as their creators lose interest. It is unpredictable.

Modeling the business problem

Most of the decisions that we as programmers make every day are related to how we model the business problem. It is all about how we decompose and implement the solution to our business problem: how we define the relevant abstractions and interfaces; what goes into a class; how modules and classes relate to each other.

We have to define the organizing principle for our user interface and how its reflected in the code. We also have to define the organizing principle for our API and how it is reflected in the code. These are the real world architectural decisions that will determine the success or failure of our project.

How much thought goes into these decisions?

Stop blaming the big decisions

Big decisions are generally static. Once made these decisions rarely change. You aren’t going to go from PHP/Apache to Java/Tomcat or Javascript/Nodejs without a major rewrite. These decisions are often made long before most programmers joined the project.

Big decisions are often skill based (so much for architecture!). If you know Javascript well, you are likely to choose Nodejs for the backend along with a contemporary Javascript framework for the frontend. A few years ago GWT was popular with teams skilled in Java. If your team uses Microsoft’s .NET and C# chances are that the selection was made by folks proficient in Visual Studio or ASP or C++.

Big decisions affect multiple ViewTypes. What’s notable about these decisions is that they impact not just the programmers but also how the application is deployed and, at a deeper level, even how the application is perceived by the user.

Big decisions can sometimes (though rarely) be wrong. It is hard to generalize. So, yes, the big decisions can go wrong but that’s generally not the case. Most major frameworks are fairly comprehensive. Here are a few examples where good choices turned out not to be the case:

You selected ActiveX/IE and Microsoft lost its monopoly over desktop browsers.

You choose AngularJS (the old Angular) but found the complexity daunting. (Note: Angular 2+ is reportedly much improved).

You built your application on MongoDB and then discovered the need for transactions. (Note: Mongo 4.0 has transactions for replica sets now).

Often this happens when new technology isn’t mature or when old technology is transitioning. Note that this is not meant as a criticism because there are perfectly valid reasons for selecting old or even immature technology.

The decisions that are key to success are often made without much thought. The code evolves through new stories and bug fixes. We create new functions without thinking about what is part of business logic and what is part of utilities. We cut and paste without thinking about shared abstractions. These are “small” decisions because team-thought rarely goes into it. It is up to each developer to code as they see fit. There is no sprint task devoted to ensuring consistency of design, and code reviews simply overlook the issue. The net result is a tangled mess that is hard to understand and impossible to maintain over the long term.

One insidious reason why we don’t emphasize these decisions is that they are amenable to refactoring. The decisions can be changed and that change can even be incremental. If they can be fixed then why worry? Yet, how many projects will ever invest in these improvements?

Most often, the solution to the problems of code complexity lies in the very code we wrote. Fixing it should be part of agile development. It should be visible in our processes. For that to happen, we must first own it.