I accepted a new project this week to write a job tracking application for a company. The company has 5 satellite offices that bid on projects. All these projects are entered and tracked via a web application that is hosted with a 3rd party web host. The application is a text book 2-Layer ASP.NET Database-Driven Application. There are no business rules to speak of other than validation rules, which can simply be added to the presentation layer or database entities for simplicity sake. To add another layer to this application would be a dis-respect to your 2-Layer Database-Driven ASP.NET Application. This is a simple data-in / data-out application via a SQL Server Database. To convolute the application with various low coupling design patterns would be overkill in my personal opinion.
Code Smells and Design Debt Noted
Code smells are a warning. They signal a less than perfect design in an incredibly imperfect world, similar to the extra 10 pounds that I wish would fade away by some miracle around my mid-section. Realistically, all code smells aren't worth fixing. They carry a design debt, which needs to be noted and perhaps eventually paid, but needs to be weighed in the present given the budget and time constraints placed upon the project.
A 2-Layer ASP.NET Database-Driven Application is "expected" to have some code smells and design debt. These are typically low budget ( fixed price ) and quick turn around applications with few business rules. Adding another layer, even a small application layer full of application controllers, could be considered overkill. There is no reason to add a complete application layer ( perhaps called service layer ) to eliminate a handful of code redundant and long method code smells. Note the imperfections in code comments and move on!
The Application Layer or Service Layer
If you have embraced the world of code generation and O/R Mappers, adding an application layer or service layer is a real possibility, because you are handcoding little to nothing. Grab you favorite O/R Mapper ( LLBLGenPro, WilsonORMapper, Codus, NHibernate, Gentle.NET, Retina.NET, Dlinq) as well as you favorite Template-Based Code-Generation Tool ( CodeSmith ) and generate a Presentation, Application, and Database Layer for your simple web-based application.
The only purpose of this application layer ( or service layer ) is to eliminate your code redundancy that may appear in your presentation layer. In this layer you will consolidate calls to your database CRUD activity as well as cache your data if necessary. Again, there is little-to-no business rules here. Simple validation can be done in this layer and/or in the set statements within the entity properties. If you don't create this layer, the presentation layer can do the simple validation as well.
Patterns of Enterprise Application Architecture and Domain-Driven Design
Before you pass negative judgement on this type of application, please consult your bibles, Domain-Driven Design by Eric Evans and Patterns of Enterprise Application Architecture by Martin Fowler. Both of these books accept and acknowledge these type of applications and suggest simple design patterns and code generation for completion.
Two-layer Database-Driven Applications deserve respect, and people who have the wisdom to understand that an application can be better understood and maintained by eliminating a business layer or application layer need to be applauded.
Although I have spent a number of posts describing GRASP Patterns and Object-Oriented Principles, there are applications that are cut-and-dry and don't deserve the purist of concepts such as high cohesion and low coupling. Let's realize that a significant population of developers are not enterprise developers and spend their time building applications for small businesses that need a custom solution to a specific problem that will rarely need to adapt to new technologies.
Low Coupling Design Hell
If you look at the number of object-oriented principles associated with class design spelled out in Agile Software Development Patterns, Princples and Practices by Rober Martin as well as GRASP Patterns mentioned by Craig Larman in Applying UML and Patterns, you will notice a FIXATION on low coupling. Applications should only be dependant on abstract classes and not concrete classes. Various Object-Oriented Principles like Single-Responsibility Principle and Open-Closed Principle as well as GRASP Patterns like Pure Fabrication, Polymorphism, Indirection, etc. only exist when your application commands low cohesion and loose-coupling. There are times when you shouldn't give a damn about such practices, and 2-Layer Database-Driven Web Applications can be such instances.
ASP.NET Best Practices in Perspective
When you look at various ASP.NET Best Practices and various blog entries that suggest X is better than Y, you need to put this in perspective. Most of the developers blogging are enterprise developers or product developers that need to care about fluctuations in technology and need extensibility based on customer demand.
A new developer who follows these enterprise practices religiously but does not develop these n-layer and pluggable web architectures will come to a painful realization - these practices will not allow you to compete on low budget, fixed price, and quick turn-around applications with people and firms who have mastered the art of 2-layer database-driven applications using Code Generation and O/R Mappers.
Conclusion
A wise developer is one who knows when to apply OOP, best practices, and design patterns to their applications and when to note a design “imperfection” and move on. Some applications, such as 2-Layer Database-Driven Applications targeting a specific niche, have an acceptable level of code smells and design debt. Two-layer Database-Driven ASP.NET Applications should be respected for what they are and should not be judged based on the same standards as other applications that require more extensibility and adherence to best practices.
Drinking: Matcha Green Tea