Debate: The Annoying Detail
Uncle Bob and Simon Brown debate on the infrastructure’s role in drawing a system’s architecture.
In an earlier post entitled Screaming Architecture, Robert Martin (a.k.a. Uncle Bob) drove home the point that the architecture of a software product should make it obvious for everyone what purposes that product is supposed to serve, adding that the architecture of a system is supposed to reflect the use cases of that system and not the frameworks it uses:
Architectures are not (or should not) be about frameworks. Architectures should not be supplied by frameworks. Frameworks are tools to be used, not architectures to be conformed to. If your architecture is based on frameworks, then it cannot be based on your use cases.
Furthermore, a good architecture should allow one to defer almost indefinitely decisions related to frameworks, databases, web servers, etc., according to Uncle Bob:
A good architecture makes it unnecessary to decide on Rails, or Spring, or Hibernate, or Tomcat or MySql, until much later in the project. A good architecture makes it easy to change your mind about those decisions too. A good architecture emphasizes the use-cases and decouples them from peripheral concerns.
Uncle Bob goes on taking a look at the Internet and wondering if it should be considered a marginal concern, concluding that the web is also a “delivering mechanism”:
The Web is a delivery mechanism, and your application architecture should treat it as such. The fact that your application is delivered over the web is a detail and should not dominate your system structure. Indeed, the fact that your application is delivered over the web is something you should defer. Your system architecture should be as ignorant as possible about how it is to be delivered. You should be able to deliver it as a console app, or a web app, or a thick client app, or even a web service app, without undue complication or change to the fundamental architecture.
The conclusion of Uncle Bob’s post is that “Your architectures should tell readers about the system, not about the frameworks you used in your system.”
Simon Brown, a Software Architect, commented on Uncle Bob’s conception regarding the “delivery mechanism”, calling it “an annoying detail”. He agrees with Uncle Bob that the architecture of a system should not be about the frameworks used, but added that he would “like to see a software architecture grounded in reality, and that includes technology choices.” When it comes to deferring infrastructure decisions, Brown says: “Surely if there are some key technology choices that need to be made, then they should be made, right?”, then asks: “If I don't or can't defer decisions, does this mean that I have a bad architecture? Shouldn't deferral be a conscious decision rather than a rule?”
While Uncle Bob takes into consideration from an architectural point of view only the core domain of the system, Brown has a different approach considering that the “delivery mechanism” is quite a large chunk these days and should be integrated into the overall architecture, as shown in this picture:
For me, architecture is about more than just what's contained within "the application". Structure is very important, but what about that tricky stuff like non-functional requirements, the actual delivery mechanism (technologies, frameworks, tools, APIs, etc), infrastructure services (e.g. logging, exception handling, configuration, etc), integration services (internal and external), satisfying any environmental constraints (e.g. operations and support), etc. For me, this is what "architecture" is all about and *that's* "the whole enchilada".
The debate did not stop there. Uncle Bob reacted to Brown’s position in another blog post, Clean Architecture, saying that no matter how large the UI and database sections are, the architecture of the system should not be oriented towards those “larger elements”, and “the other parts should be decoupled from it.” He goes on explaining that it is very important to decouple the core domain from the delivery mechanism, explaining that he does not artificially postpone and stop making any decisions on the frameworks involved, but that the architect should always keep a clear separation between the two parts even if they evolve simultaneously:
One of the more strident comments I’ve made about architecture is that a good architecture allows you to defer critical decisions like the UI, frameworks, database, etc. One point made by several people is that customers don’t want the UI deferred. DBAs don’t want the database deferred. From iteration to iteration they want to see the whole system working, including the UI, the Database, and the frameworks. They don’t want an iteration to be spent solely on business rules. Indeed, good agile practices specifically demand long skinny slices through the entire architecture.
Of course I agree with all of that. However long skinny slices don’t have to be coupled. A good architecture allows you to defer critical decisions, it doesn’t force you to defer them. However, if you can defer them, it means you have lots of flexibility. For example, you could create an interim simple UI for the first few sprints, and then replace it with a more capable UI later.
Uncle Bob concludes: “there’s nothing wrong with working on the annoying little details first, so long as you decouple your business rules from them.”
Brown responded in RE: Clean Architecture, agreeing with Uncle Bob on decoupling but he takes a different position on dealing with infrastructure concerns: “The delivery mechanism is NOT an annoying detail that can be deferred or ignored ‘right off the end of the world’”, as Uncle Bob affirms. Brown concludes:
- Decoupling application code from technology is good and certainly something we should all strive for. The result is code that is easy to unit test, easy to substitute, easy to maintain, easy to change, etc.
- Software architecture is about the big picture and application code is only one part of that big picture.
- You run the risk of your software project failing if you continually defer significant decisions about the "delivery mechanism" and don't consider how to address your significant non-functional requirements and/or constraints.
Uncle Bob and Brown are not really on opposing positions here. They both support a clear separation between the core domain and the supporting frameworks, but while the former focuses on the domain, the later considers that the infrastructure should be considered and taken into account. What is your approach?
A real world example
Exactly what inconsistencies end up existing in your system depends heavily upon the architecture. Is data stored immediately, or put in a queue to be stored later? Are synchronous requests made between services, or asynchronous messaging? How much is the data denormalised, and what data is denormalised? Is there any caching, and under what conditions are the caches expired? The thing to realise is that the answers to these architectural questions all depend on what technologies you are using, and what their capabalities are, you can't make a decision about whether data should be stored immediately or queued to be stored later unless you know whether one or the other is going to be performant, and you can't know that without taking the technologies used to implement it into consideration.
Where I work, if you haven't made some decisions about technologies as part of your architecture, then you have no idea if your architecture is even technically possible, and it probably isn't. If you come up with an architecture that doesn't address these concerns, your architecture will be no more than a diagram that says data goes in, data comes out, and will be completely useless.
More heat than light here
1. The domain (as in Domain Driven Design). While I'm a big fan of DDD, I'm currently building my first non-DDD application for a big bank. It is a big data analytics project that doesn't even have a UI, just a bunch of math transformations on many input sets. Is it wrong for us to build a non-DDD application so that we can meet the timing requirements? Of course not -- the client may prefer us to choose processing speed vs. maintainability (we probably could do it with DDD but would need a bunch more hardware).
On the other hand, DDD and N-tier systems (the implicit architecture in the article) are a great fit for most IT applications. You'd likely not use DDD + N-tier to build an embedded system like a thermostat or the brake controller for your car. My point is: embedding the domain in your code is just one of many architectural choices (a choice that helps maintainability) but it is not always the right trade-off.
2. What counts as architecture. Some people think architecture is just the big blocks, some think it also lives in the little details. Smart people will disagree. Arguing about what counts as "architecture" vs "design" is orthogonal to whether or not something is good software development practice or a good choice on any given project.
Personally, I've been using a definition of software architecture that's compatible with James Roper's story, where something counts as architectural if it influences a quality attribute (ie "an -ity" or "extra functional requirement") that you are focusing on. The problem with this definition is that almost anything can become architectural. But if you evaluate the system wrt a small set of quality attributes (eg must complete batch cycle in 4 hours or new postings must be available within 5 seconds / consistent within 5 minutes, ...) then that small set limits your mental model of the system and which details are architectural.
Author of Just Enough Software Architecture
Who said or wrote that technical details don't matter?
I have serious doubts that this cluttering is really necessary. An example: I have never seen a case where the performance penalty was too high to hide away database access behind a façade.
Technical details that are relevant for decisions inside the domain need to be translated into the language of the domain. The rest of the technical stuff can be hidden behind some façades such that the domain code reveals what's really going on within the domain. Yust ask yourself "How would I explain this technical effect to an experienced domian expert without technical skills?"
That said, it's often crucial to have a profound understanding of how technical details affect the domain in order to fully understand it. Otherwise you might make unrealistic assumptions about the technical details and this can for sure lead to problems.
An example of the mentioned translation process is the interpretation of error states in various parts of an application...
Re: More heat than light here
Huh? How do you want to write a banking application if it must not have domain logic of the banking business inside?
The domain logic is always there. It's just a matter of how it's written. As code where you can easily identify this logic or code that is so cluttered with technical details that you cannot tell if it's a banking application or an obfuscated O/R mapper.
No medium will scream all the details at you all the time