Creeping logic

Developers struggle with where to put their business logic.  We all know at an intellectual level that we should be keeping business rules and logic in some kind of a business layer, but I don't see it in practice that often.  I do see a lot of business layers that turn around and call data layers.  There's often nothing business-y about them.

Instead, the logic is sprinkled throughout the other layers, sometimes to take advantage of a technology, sometimes because of the strengths of the developer who wrote the code.

Validation controls in ASP.NET Web Forms are an example of business logic in the UI layer.  Another is an ASP.NET Web Forms code behind event that calculate discounts for preferred customers on Page_Load.

ASP.NET MVC isn't immune from this either, although the validation logic story is better with Data Annotations letting validation rules flow up to the UI.  Controller actions can be mistreated just like code-behind and often contain more business logic than they should.

And putting more logic in stored procs doesn't make your app dev teams more agile.  It makes the data team the bottleneck for logic changes.

Journey to the Center of the App

A better approach is to lift that logic out of those layers and put it in your business/domain/core layer in C# POCOs.  In many apps, this logic is what makes the app worthwhile.  Sometimes, it's what gives the company a competitive advantage.  It should be clear, expressive, and long lived code.  It should not be coupled to any particular technology.

These can be tricky changes to make once an app is partly finished or already up and working in production.  There can be a lot of refactoring.  But the effort can pay off in making the code more clear to anyone working on it and letting you make complex changes much faster because the logic is centralized and expressive.

How do you do this?

One test I like to use for where the logic goes is, "What if the technology changed?"  What if I wasn't able to use Web Forms or MVC, but had to use Silverlight or any other future technology?  What if SQL Server went away?  What if we switched from stored procs to NHibernate and then again to Entity Framework?  If we've got business logic wrapped up in our tools, no matter what the tools are, we can be sure the logic will need to be rewritten when the technology changes.

It's great to take advantage of new tools, but your code needs to keep it's distance where possible.  Wrap the tool with an interface or something so the tool is decoupled from your logic, and you can replace the technology if you need to. I've written about this interface wrapping technique before.

Another great technique is using TDD or other test-first approaches because your code will be written with an eye toward how it will be consumed. You'll end up with lots of small classes and methods with expressive names. This outside-in approach to coding really guides you toward creating a clean API for the app's first customer - your test code.