As mentioned in the first blogpost of this serie related to the Clean Architecture, any Software System can be divided into Policies (ie. high level elements of the system) and Details (ie. low level elements of the system that define how the Policies are actually implemented).
In this last article, we will discover 3 famous examples of Details in a software system : the database, the web GUI and the frameworks.
What are Databases?
Because it holds the physical representation of a Model (which in turn is critical to the existence of a software system), the Data is certainly very important. When Edgar Codd defined the principles of Relational Databases back in 1970, everybody was excited about this new cool technology that provides an elegant, disciplined and robust way of accessing data. But not matter how good or brilliant a technology may be, it remains technology – and that means it’s just a detail.
While Data is critical to the existence of a software system, how the Data is accessed is not. One of the biggest mistakes made during the last decades was to put Databases at the core of software systems which, in other words, means that system would solely rely on details (i.e. how to access data) and not on policies (i.e. what is the actual data).
If we really think about it, there is nothing exciting about Data being arranged into rows within tables. At the end of the day, the Database is just a piece of software and thus, by definition, it should be easy to change / replace. Considering database rows to be the model of our Application is an architectural error that cause business rules, use cases and even some parts of the UI to be tightly coupled to the relational structure of the Data. The Database represents just a mechanism for accessing data from a persistent storage (i.e. non-volatile memory), but from an architectural point of view, this is a low-level detail that should be deferred for as long as possible. Thus the Database is to be decided later upon and should not pollute the early architecture of a system.
Why do relational Database Systems seem to be everywhere?
The reason why database systems are so prevalent today is because of rotating magnetic disks, which have been (and to a certain degree, still are) the industry standard of persisting data for more than five decades. While these disks have evolved over the years, allowing more data to be stored on less space, there is one technology trait that has remained the same: disks are slow (i.e. at least 100,000 time slower than RAM when comparing access times).
To mitigate this time delay imposed by disks, you need special data structures called indexes, caches and optimized execution plans and query schemes – in a word, a Relational Database Management System (RDBMS – e.g. Microsoft SQL Server, MySql, Oracle DB). These systems are content based, which allows them to provide a natural and convenient way to find records based on their content. Additionally, each of these systems eventually brings some data into memory, where it can be quickly manipulated.
But what if there were no disk?
Then, we wouldn’t need SQL at all ! As popular as they have been, disks are will soon be going the same way as floppy and CD did. They will eventually be replaced by RAM. And when this will happen (which will happen pretty soon, given AMD Epyc servers holding up to 4TB RAM and Intel Optane SSDs offering non-volatile RAM-like performance), RDBMS will die along with their beloved Relational Model.
And what kind of data structures will programmers use then? As surprising as it might sound, programmers will use the same data structures that they will have been using until then, namely lists, hash sets, stacks, queues etc. The reason behind this is that we, as programmers, rarely leave the data in form of rows or tables – we usually load it up into memory and rearrange it according to our needs. At the end of the day, databases are all about moving data from RAM to disks in an as efficient way as possible. From an architectural point of view, this is irrelevant and indeed, we should not care about the existence of disks at all. As important as the performance of a system may be, it should be clearly separated from the business rules, as it has nothing to do with the overall architecture of that system.
To conclude with, the Business Data Model is architecturally important, while the technology and systems that manipulate data on rotating magnetic surfaces are not. Data is significant – SQL is not.
For many of the today’s systems, the Web is the way to go. Want to build a new application ? You would want it to be delivered over the Web, of course, because this is what everybody else is doing, right ? Wrong. GUIs are a manner of sending (and sometimes getting) the information to (and from) the user. It has nothing to do whatsoever with the business core of the application and therefore should be regarded as a detail.
In how many ways can a system be delivered ? Well, the simple answer is endless. However, the most popular ways of delivering software systems are in the form of a Desktop Application, Web Application, Mobile Application or as a Pure Service. As we can see, the Web is a GUI. And GUIs are details that should be kept separate from the business rules. When the Web was introduced back in the 1990s, it completely revolutionized how software systems were built and deployed. Everybody was throwing away their beloved client-server architectures and were rapidly embracing the new cool kid in the town. Today, many of us think that the Web changed everything.
It seems like the Web changed a lot…
All these oscillations – they’re making me crazy!
Unfortunately, all these oscillations cause harm to applications depending on them. The long term solution is to create an architecture that is oscillation resilient (i.e. whose core functionality remains the same, despite trend changes). The only way to resist to these changes is to push trends such as the Web as far as possible from the central core of the system by decoupling Business Rules from the UI.
But today’s applications seem so be so closely tied to their GUI !
It may not be easy to make a clear distinction between the UI and the Application, but another layer of abstraction can and should be put in place. If we can think about the Application as being a suite of Use Cases which perform computations on behalf of the user, we could also think about the GUI providing and showing data from and to the user.
To conclude, though it may take several iterations to get this kind of decoupling just right, the benefits of applying the Separation of Concerns principle will save everybody lots of headaches and sleepless nights.
Frameworks are details!
Frameworks are good things – they can relieve you of great pains when developing software. However, committing to a certain framework is like marrying that framework (i.e. you’re bound to using it for the rest of the life cycles of that application). Like uncle Bob put it: “For better or for worse, in sickness and in health, for richer, for poorer, forsaking all others, you will be using that framework!”. Using a certain framework is an important decision that should not be taken lightly.
The use of Frameworks have become more popular nowadays and for a good reason. Generally speaking, people of the community write frameworks that are relevant for themselves and their co-workers because they want to help and give back. They have encountered difficulties and now are ready to share their knowledge of overcoming these difficulties with others.
The most important thing to note about Frameworks is that they are good given a specific context, and should not be considered Architectures. One great mistake that developers do is to commit to a certain framework and build their application in and around that framework – a place where the Architecture solely must be.
Frameworks are not architectures – and they do not have your best interests at heart, because they have been built with other purposes in mind; namely, to solve the problems of the creator of that framework and of those close to him.
We can think of the relationship between the developer and the author of a framework as being an Asymmetric Marriage (i.e. one-directional). That is, you make a huge commitment of using that framework, but the author of the framework makes no commitment whatsoever.
Wrapping the architecture of your application around a framework has a huge effect on the overall coupling of the system. Polluting the business objects with framework-specific elements such as attributes or certain fields is a mistake lots of programmers do and puts their effort at great risk.
Suppose the framework makes it easier for you to start building your application, but what after? As the product matures, you will often find certain features of that framework to not help you as much as they did in the beginning. Moreover, as time passes and new versions are released, you will probably find out that old features, which you made use of, have disappeared. Even more painful is when another new and shiny framework is released and you would like to try it out, but you can’t because the core business logic of your application depends on that old rusty framework of yours! Not to mention that if the framework becomes unsupported and dies, your application will fall along with it.
The best solution is to to use the framework, not to marry it. Date it a few times, see how it behaves in different circumstances, decide what you like about it, what you don’t and take action. If it corresponds to your need, keep it. If it doesn’t, replace it or don’t use it at all.
A Framework does not influence the architecture of a system. It should be treated as a detail and kept at distance from the business rules.
Let’s take a few examples
The Spring framework is one of the most popular dependency injection frameworks for Java. Its power to autowire dependencies comes in handy on most projects. But a good Architect will not pollute the Business Objects with autowire attributes. In fact, Business Objects should know nothing about your application using Spring.
One of the most popular ORM Frameworks for .NET is Entity Framework. Many architects make the mistake of specifying this framework as the default way of accessing data. Despite being a well written and flexible framework, it is just a mechanism of accessing persisted data – thus it is to be considered as a detail and should be kept behind a well-defined data persistency interface.
To conclude, frameworks (examples: Spring, Entity Framework, Ninject, Moq) are details and using them should be a decision, not a given. In a good architecture, frameworks are separated from business rules and use cases and belong to the outermost layers of the application.