- We design and build extraordinary applications for companies looking to make the next great idea a reality.
- learn more
Layered architectures & other abstractions.. revisited
Speaking in terms of abstractions can cause a peculiar kind of paralysis to occur by letting developers avoid the specifics longer than necessary. You might have been part of a discussion in the past where your team struggled to define the names of each layer in a system or wrestled with the impedance caused by conflicts between the logical versus physical aspects of layers in an application. These are symptoms of what I am referring to.
Suppose, for example, you have the following system-- business logic contained in a service layer, and a less well-defined set of classes that communicate with some external system(s). The fact that the classes in this latter group serve a common function may let you talk about these classes as comprising a distinct layer in the system-- but it is just as likely that concerns such as transaction management, persistence or packaging considerations drive the need to make exceptions to an otherwise clear-cut boundary between these two layers.
As the code matures, the service layer may start to know too much about specific components in the newer layer, and this new layer may start to rely on knowledge of (and code for) certain paths through the service layer. This may sound like a recipe for disaster, but often this kind of coupling is just an unintended consequence of developers realizing that the most expedient way of working with the system runs against the grain of the layered architecture-- which itself is an odd thing to confess, since one measure of a layered architecture's worth is in how well it provides a path of least resistance to normal development.
Two camps emerge when this kind of problem surfaces. On the side of expediency, team members begin to suspect that maintaining a strict separation between these layers requires too much overhead either during the design of new features, or in refactoring of the existing code base-- they push to allow the layers to co-mingle. In the other camp are developers who believe such co-mingling should not happen (to take the purists perspective), or that it is inherently unsafe (future-proofing the architecture against factors they expect to change, such as transaction management, clustering strategies, security considerations, etc). Oddly enough, the one thing everyone seems to agree on is that the distinction between these layers should still exist-- at least on paper. So instead of changing their definition of what constitutes a "layer" proper, they either rationalize the need for exceptions to the rule, or enforce the separation of layers despite the added cost of maintenance.
Rather than discuss all the kinds of arguments that arise in these cases, I believe it suffices to use the example above as in introduction to something more fundamental. This more fundamental issue deals with why and how developers place such a high level of importance on abstraction in the first place, even to the detriment of otherwise good design.
Abstractions reflect the way we like to think about the construction of a system once it is in place, but I don’t believe they always reflect how teams most effectively work and live within those systems once they are built.
Take object-relational mapping frameworks for example. We like to think that a good object-relational mapping framework shields developers from having to think about the database-- and, during the inception of a project, this is normally true. But as the application matures, the number of caveats in the system increase-- changes to the relational side occur in lockstep with changes to the object model, and quirks on one side need to be understood, even if they don't directly manifest themselves on the other end as problems. The less an object model is explicitly bound to a database implementation, the more likely the team itself needs to become well-versed in how the underlying ORM works, and must therefore retain this knowledge throughout the life of the application. So, with this additional level of abstraction, you have effectively changed what used to be a code maintenance tax for the life of the application to a more subtle, but (in some cases) costly mental tax on the developer for the life of the application.
Don’t get me wrong-- this is not to say that abstraction itself is a bad idea, nor that layered architectures are inherently bad. Rather, I believe these kinds of abstractions work best when the cost on the development team for the life of the project (which, unless you are lying to yourself, is never ‘zero’) is less than the hypothetical cost of maintaining a larger code base by reducing the number of abstractions.
Topics: Agile Development
Leave a comment
About Pathfinder
Recent
- Pimp my jQuery: Five plugins to replace the features Prototype and Scriptaculous users expect
- Thanksgiving 2008: What We’re Thankful For (In Rails)
- iPhone SDK: Testing with TextMate & GTM
- GWTQuery - JQuery-like Syntax in GWT
- Ask the readers: How do I fire native browser events in Prototype.js?
- News Rollup for the Week of November 17, 2008
- Rails ThreatDown!
- Automated Deployments Rock
- Bandwidth profiling Flex projects and more with Charles
- iPhone SDK: UIViewController Testing & TDD
Archives
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006

