AKA “Copy-paste Architecture”
I recently read a great answer to the question: “What is architecture?” Or rather, “What elements are architectural?” It’s an important question, and one seemingly impossible to answer: where do you draw the line between architecture and design? Architecture and just good practices? Architecture and “that’s just the way we did it”?
The answer is both obvious and disappointing: architecture is in the eye of the beholder. To an Enterprise Architect, the broad business concepts (domain entities) and system capabilities are architectural. To an Applications Architect, modules and layers, component interfaces and connection protocols are all architectural. To a Network Architect, network topologies and hardware are architectural. There is some overlap in what each cares about, but the point is that each type of architect, each software design and each developer has their own opinion about what is important to know.
But don’t despair! There is a way of defining exactly what is architectural to YOU! You see, what an architect does in the end is specify enough of the elements, patterns, technologies and structure of the system (or systems, or subsystem…) to guarantee that the implementation work that follows will satisfy the functional and non-functional requirements that it is supposed to. The rest is just design details that you can let a designer or developer decide for themselves – what’s important is that the performance, scalability, extensibility and all the other -ilities have been taken care of.
And that’s a healthy thing: to make all decisions up front for everyone else is not only boring, it would take forever, and take up volumes of hard-to-use and impossible-to-maintain documentation. What’s more, you run a big risk of overdesign.
Another definition, or characteristic, I have heard of architectural elements is that they are not generally one-off decisions regarding a specific implementation. What separates an architectural element from a design element is that the former represents a pattern that is meant to instruct and guide the design and implementation. Architecture in this sense is “reusable design”.
So what does all of this have to do with the decay of an application’s code base? Well, let’s say you’ve gone ahead and done your duty to specify those elements of your application that are architectural. Now it’s time for the team to write the software according to their whims, but within the constraints you have imposed. During this time, developers will naturally make decisions about the implementation. “Where should I put this class?” “Which package should I use?” “What should I call the class?” “Should I use a design pattern here? And which?”
Of course, none of these decisions are (you hope) important to the overall architecture of the system. But many of them are to solve common problems, and will likely need to be made again by other developers as they create and maintain the application. So, let’s say we have a simple “8-ball decision” (cf the commandment “Be decisive”) that a developer is making regarding the name of their Data Access Object for saving “Foo” to the database. It has an interface, but let’s say this particular implementation uses Hibernate to get the job done. Our hero could name the class:
- and so on…
So, our hero decides he likes option #4 because it sounds like an answer to the question “WHICH FooDao?”, and because all-caps acronyms run the risk of run-on acronymtences (Note: it’s always good to keep a justification for a Magic 8-ball Decision in your back pocket, because it ends arguments quicker than, “The 8-ball said its sources say yes.”). The next time our hero makes a DAO to save Bars, you can bet he’ll call it a “HibernateBarDao”.
In the following iteration (your process has iterations, right?), our heroine finds that she, too must write a DAO to save (you guessed it) Bazzes. Fortunately, she noticed that our hero has already done this before, so she copies over the basic code, kindly extracts any commonalities to a base class (you go, girl!), and calls her new implementation a “JdbcBazDao” (say it 10 times fast!). Although this was never specified in the original architecture, you now have the beginnings of a standard AND a framework:
- All Data Access Objects should follow the naming convention: Implementation approach + Object type persisted + “Dao”
- Common data management code is implemented in a BaseDao class, which all other DAOs should extend
Remember the previous definition that the architecture is “reusable design”? This is more or less what is happening here, even though it wasn’t intentionally specified by the architect. I call this “Architecture by Accident.” I also call this “Copy-paste Architecture” due to the way these implicit conventions often occur. But don’t get me wrong: there’s absolutely nothing wrong with the example I just gave you. It’s fantastic when standards and architecture and evolve properly on their own.
But let’s say a third developer, our sidekick, needs to write a DAO to save XPTOs. Because these “standards” were never made official, it’s quite possible the sidekick never got the memo. And after consulting his own Magic 8-ball (the official High School Musical edition! Wow!), decides to call his DAO “XPTOJDBCDAO” (DON’T try to say that one out loud). And one more for good measure: what better for saving XYZPDQs than an “XYZPDQJDBCDAO”?
Now enters into the story our villain. Actually, he’s not such a bad guy, but he does have his own incredibly important and convincing reasons for why his DAO must be called a YoMamaDataAccessObjectHibernate.
Our simple application now sports the classes:
Confused yet? This is the problem with a “Copy-paste Architecture”. It isn’t so much who is making the decisions, or even why. The problem is that they aren’t being made consistently. As a result, your code base starts to rot. Clarity goes out the window. It’s hard to find classes you know are there because you can’t begin to guess what they’re called. You can’t do any generalized analysis, conversions or rule enforcement because there’s no one rule that can cover all the possibilities. And we’re just talking about the class names!
Of course, Architecture by Accident isn’t limited to just naming conventions. Design patterns, layering structures, library classes and infrastructure solutions are all at risk of having their wheels reinvented if there isn’t someone looking out to identify these patterns and maintain consistency. We’re all familiar with the results: increased complexity, reduced clarity and diminished productivity.
The only solution to this problem is collaboration. The whole team needs to recognize common patterns and solutions as they evolve, make them explicit, and let everyone know. But take my word for it: it won’t happen by accident.