Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC - when SRP and DRY appear to conflict

My simplest ASP.NET MVC 2 controllers make calls to my service layer and map view models to entities using AutoMapper. Everything looks fantastic and there is no repeated code.

However, when I get into scenarios where I have similar behavior I have trouble balancing Single Responsibility Principle (SRP) with Don't Repeat Yourself (DRY). An example of this might be the need to add/edit vehicles where some properties/behaviors are shared while others are unique to a specific vehicle.

If I strive for really thin controllers (thus honoring Single Responsibility Principle), I end up having repeated code in both the views and controllers with minor variations (title, field labels, field visibility, dropdown values, selection criteria, etc.).

If I strive for non-repeated code I end up bundling too much logic into a single controller/view and it gets bloated.

What are some ways of addressing repeated code in controllers / views? I'm not talking about database code that can be factored out to a repository. Nor am I talking about business logic that can be factored out to a service layer. I'm looking for tools and/or rules of thumb that will help me produce the best solution in the scenario described above.

like image 306
Mayo Avatar asked Nov 12 '10 18:11

Mayo


1 Answers

You get:

  • partials
  • RenderAction
  • action filters
  • service layer and helper classes (not HtmlHelper)
  • model binders
  • base controllers
  • dependency injection

So your views can invoke shared partials/actions for similar parts, common data can be prepared by action filters, database access code can be hidden in smart model binder, or you can have parent controller that child controllers override with specific tweaks. And, of course, good old service layeres, where you just extract common code into helper/static methods, or, better, inject specific implementations.

That's nothing new, same old tricks.

Or, maybe, your controllers do too much works? This is where stuff above also helps. ASP.NET MVC has very good tools to hide infrastructure-layer code and move it away from controllers. And if it's not infrastructure - it probably belongs to domain layer. There you can use inheritance, composition and other OOP tricks.

Specific example. Suppose your controllers should set few properties in a different way.

  1. You can have your views to do this, if it's mostly formatting or choosing what properties to show
  2. You can have your entities to have virtual methods - i.e. refactor code to move decisions to domain layer instead of controllers
  3. You can have helper ViewDetails classes that will take your entities and get the data based on for what you need it; this is a bit of a dirty trick but sometimes useful; you delegate decision to another "strategy" class
  4. You can use action filters to add this data to ViewData, or to tweak specific ViewData.Model types (look for some interface of it).
  5. You can have abstract controller, where children pass implementation details to the base constructor like (): base(repository => repository.GetSpecificData())

And so on. I actually use all of them in appropriate places.

like image 108
queen3 Avatar answered Oct 29 '22 15:10

queen3