Enterprise Application Architecture Patterns & the Immutable Laws of Change
The book “Patterns of Enterprise Application Architecture” was written by Martin Fowler 20 years ago (in 2002), and while I was reading it from cover to cover during my PTO days, several thoughts and revelations crossed my mind. First of all, Martin Fowler, together with people like Bob Martin & Kent Beck are what I like to refer to as “American Gods” of software engineering. Not because they are American (Fowler was born in England) or because I consider them as gods, but because they seem to adapt, evolve and grow with the industry, seemingly unhindered by its various phases and hypes, much like the characters of the Neil Gaiman’s fantasy novel. As engineers and architects, we are truly standing on the shoulders of giants like him.
Fowler has composed the book with two logical sections, the first part is a set of narrative chapters on a number of important topics in the design of enterprise applications. The second section is more of a reference on the various design patterns and their implementation details. Some of these are still valid, relevant & indeed widely used in the industry. But several patterns, unfortunately, have not taken well to the winds of change. And a subset of these, tragically, have lived long enough to become anti-patterns. The main focus of this article is to look at these anti-patterns, while briefly mentioning the good ones.
Looking at the patterns that have aged well, patterns like “Unit of Work”, “Identity Map”, “Lazy Load”, “Data Mapper” and “Optimistic offline lock” have done so well that they have been integrated to popular ORM frameworks like Hibernate and Sequelize. Even though developers are no longer required to specifically implement those, it is essential to have an understanding on these patterns. Patterns like “Service Layer”, “Repository”, “Model View Controller” and “Data Transfer Objects” are widely used in building both large and small scale enterprise applications. The significance of the pattern “Domain Model” was highlighted in a recent project where getting the model correct was crucial for the implementation of the domain logic and the integration with legacy systems. Most modern REST APIs can be considered as “Remote Facades”, even though the author was considering these for inter process communication within the same machine 20 years ago, this pattern lends itself well to distributed system integrations. In fact, it was surprising to see most of the patterns and their derivatives still in use today.
Out of the patterns that have not aged well, “Transaction Script” is one of the main once. Definition: “Organizes business logic by procedures where each procedure handles a single request from the presentation”. This pattern essentially instructs you to have a single method which does everything (request handling, business logic, DB access, response formatting) for a single user request. Even though I have seen this done in AWS Lambda based REST APIs as a quick and dirty solution for time critical projects, I would consider this to be a strong anti-pattern for the enterprise space, where the longevity and maintainability of the code base (i.e., minimal cruft) is key.
“Serialized LOB” is another pattern which is hard to justify in the current technology context. Definition: “Saves a graph of objects by serializing them into a single large object (LOB), which it stores in a database field”. This pattern suggests that you should serialize (either binary or text based format) a collection of inter connected objects and store them in a single database field without saving the objects separately in tables as normal. With the difficulties in managing the size of the field, managing schema changes and accessing the data, it is hard to imagine a scenario which this can be justified in. If the complex structure of the objects is the problem, they can be stored in a NoSQL DB, or with a Relational/Non-relation hybrid DB approach. If the relationships are significant to the business domain, they should be stored in a relational DB, despite the increase in the complexity of the data model.
The usage of patterns like “Page Controller” and “Front Controller” have indeed become anti-patterns. The backends of modern enterprise applications are often built with client agnostic REST APIs. These can be used by front ends, internal components or external B2B or B2C integrations. Including front-end specific logic and structure in a backend controller is generally not a good idea. However, you can use a BFF layer (which is a part of the UI codebase itself) and implement the UI specific controllers there.
“Active Record” is a controversial pattern in my opinion. Definition: “An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data”. I consider the “Row Data Gateway” to be a truly good pattern,” An object that acts as a Gateway to a single record in a data source”. But adding domain logic to that same object breaks single responsibility, i.e. the class would then have multiple reasons for change. In a sense it can break layering as well, If the Active Record object has to be passed from one layer to another, you would be passing the business logic code with it.
I can keep on analyzing each pattern and have a rant that would be considerably long and considerably boring. But this gist of it is, at least 75% of the patterns described by fowler in his book are still relevant and indeed should be studied by any aspiring software architect. The other 25% has either been made irrelevant by changes in the technologies used or the changes in architecture thinking patterns. i.e. The immutable laws of change. But if you can write something in the field of software engineering that would still be mostly relevant in 20 years, that by itself is a great feat. My only hope is that at least one person who is reading this, goes on to read the book.