Últimamente he estado leyendo Clean Code y varios artículos en línea sobre SOLID, y cuanto más leo sobre él, más siento que no sé nada.
Digamos que estoy construyendo una aplicación web usando ASP.NET MVC 3. Digamos que tengo UsersController
una Create
acción como esta:
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
En ese método de acción, quiero guardar a un usuario en la base de datos si los datos ingresados son válidos.
Ahora, de acuerdo con el Principio de Responsabilidad Única, un objeto debe tener una responsabilidad única, y esa responsabilidad debe estar completamente encapsulada por la clase. Todos sus servicios deben estar estrechamente alineados con esa responsabilidad. Dado que la validación y el guardado en la base de datos son dos responsabilidades separadas, creo que debería crear una clase separada para manejarlas así:
public class UsersController : Controller
{
private ICreateUserValidator validator;
private IUserService service;
public UsersController(ICreateUserValidator validator, IUserService service)
{
this.validator = validator;
this.service= service;
}
public ActionResult Create(CreateUserViewModel viewModel)
{
ValidationResult result = validator.IsValid(viewModel);
if (result.IsValid)
{
service.CreateUser(viewModel);
return RedirectToAction("Index");
}
else
{
foreach (var errorMessage in result.ErrorMessages)
{
ModelState.AddModelError(String.Empty, errorMessage);
}
return View(viewModel);
}
}
}
Eso tiene algún sentido para mí, pero no estoy del todo seguro de que esta sea la forma correcta de manejar cosas como esta. Por ejemplo, es completamente posible pasar una instancia no válida CreateUserViewModel
a la IUserService
clase. Sé que podría usar las anotaciones de datos integradas, pero ¿qué sucede cuando no son suficientes? Imagen que mi ICreateUserValidator
comprueba en la base de datos para ver si ya hay otro usuario con el mismo nombre ...
Otra opción es dejar que IUserService
se encargue de la validación de esta manera:
public class UserService : IUserService
{
private ICreateUserValidator validator;
public UserService(ICreateUserValidator validator)
{
this.validator = validator;
}
public ValidationResult CreateUser(CreateUserViewModel viewModel)
{
var result = validator.IsValid(viewModel);
if (result.IsValid)
{
// Save the user
}
return result;
}
}
Pero siento que estoy violando el Principio de Responsabilidad Única aquí.
¿Cómo debo lidiar con algo como esto?
user
clase manejar la validación? SRP o no, no veo por qué lauser
instancia no debería saber cuándo es válida o no y confiar en otra cosa para determinar eso. ¿Qué otras responsabilidades tiene la clase? Además, cuandouser
cambien, la validación probablemente cambiará, por lo que la contratación externa a una clase diferente solo creará una clase estrechamente acoplada.