ASP.NET MVC - when SRP and DRY conflict

My simplest ASP.NET MVC 2 controllers make calls to my service level and map display models for objects using AutoMapper. Everything looks fantastic and there is no re-code.

However, when I get into a scenario where I have similar behavior , I have problems balancing the Single Responsibility Principle (SRP) with Do not Repeat Yourself (DRY). An example of this may be the need to add / edit vehicles, where some properties / behavior are shared and others are unique to a particular vehicle.

If I strive for really thin controllers (thus, observing the principle of common responsibility), I get repeated code both in views and in controllers with small variations (name, field labels, field visibility, dropdown values, selection criteria, etc. .).

If I strive for non-repeatable code, I end up adding too much logic to one controller / view and it gets bloated.

What are some ways to address duplicate code in controllers / views? I am not talking about database code that can be accounted for in the repository. I am not talking about business logic that can be taken into account at the service level. I am looking for tools and / or rules of thumb that will help me create the best solution in the scenario described above.

+7
asp.net-mvc dry srp controller
source share
3 answers

You get:

  • overtones
  • Render action
  • action filters
  • service level and helper classes (not HtmlHelper)
  • model bindings
  • base controllers
  • dependency injection

Thus, your views can trigger common partial actions / actions for similar parts, common data can be prepared by action filters, the database access code can be hidden in the smart model binding or you can have a parent controller that child controllers override with certain settings. And, of course, the good old service levels, where you simply extract the general code into helper / static methods or, better, introduce specific implementations.

This is nothing new, the same old tricks.

Or maybe your controllers work too much? The material above also helps here. ASP.NET MVC has very good tools for hiding infrastructure level code and moving it from controllers. And if it's not infrastructure - it probably belongs to the domain layer. There you can use inheritance, composition, and other OOP tricks.

Specific example. Suppose your controllers have to set several properties differently.

  • You can have your views if they mainly format or choose which properties to show
  • You can have your entities using virtual methods - for example, refactoring code for transferring decisions to the domain level instead of controllers.
  • You can have helper classes called ViewDetails that will accept your entities and receive data based on what you need; it's a little dirty trick, but sometimes useful; you delegate the solution to another strategy class
  • You can use action filters to add this data to ViewData or to configure certain types of ViewData.Model (look at some interface).
  • You can have an abstract controller where children pass implementation details to the basic like () constructor: base (repository => repository.GetSpecificData ())

And so on. I actually use them all in their respective places.

+3
source share

You are too worried about SRP and DRY. They are only principles and not always right. SRP and DRY are good if they make your code more serviceable, but if they interfere, then ignore them. MVC is similar. It is useful in simple small desktop applications, but not suitable for web applications. Web forms are much better for the Internet world, while MVC has been something since the 1980s.

0
source share

I recommend that you use SRP over DRY in these cases. I wrote a detailed answer here .

In short, these are rules that help keep your code operational. DRY is a mechanism with a low level of abstraction, and SRP is a high level of abstraction. By supporting the application, the structure of the high abstraction layer is more important than the low abstraction layer.

In your case, I do not think that you need to give up DRY.

An example of this may be the need to add / edit vehicles, where some properties / behavior are shared, while others are unique to a particular vehicle.

In this case, many design patterns can help. You can use a decorator, composition, etc ... in combination with builders for various types of vehicles.

0
source share