Ultimamente, tenho lido o Clean Code e vários artigos on-line sobre o SOLID. Quanto mais leio sobre isso, mais sinto que não sei de nada.
Digamos que estou criando um aplicativo da Web usando o ASP.NET MVC 3. Digamos que eu tenha um UsersController
com uma Create
ação como esta:
public class UsersController : Controller
{
public ActionResult Create(CreateUserViewModel viewModel)
{
}
}
Nesse método de ação, quero salvar um usuário no banco de dados se os dados inseridos forem válidos.
Agora, de acordo com o Princípio da Responsabilidade Única, um objeto deve ter uma única responsabilidade e essa responsabilidade deve ser totalmente encapsulada pela classe. Todos os seus serviços devem estar estreitamente alinhados com essa responsabilidade. Como validação e salvamento no banco de dados são duas responsabilidades separadas, acho que devo criar uma classe separada para lidar com elas dessa maneira:
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);
}
}
}
Isso faz algum sentido para mim, mas não tenho certeza de que esse seja o caminho certo para lidar com coisas assim. Por exemplo, é perfeitamente possível passar uma instância inválida CreateUserViewModel
para a IUserService
classe. Eu sei que poderia usar o DataAnnotations incorporado, mas e quando eles não forem suficientes? Imagem que meu ICreateUserValidator
verifica o banco de dados para ver se já existe outro usuário com o mesmo nome ...
Outra opção é deixar que IUserService
a validação tome conta da seguinte maneira:
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;
}
}
Mas sinto que estou violando o Princípio da Responsabilidade Única aqui.
Como devo lidar com algo assim?
user
classe não deve lidar com a validação? SRP ou não, não vejo por que auser
instância não deve saber quando é válida ou não e confiar em algo mais para determinar isso. Que outras responsabilidades a classe tem? Além disso, quando asuser
alterações a validação provavelmente mudar, a terceirização que para uma classe diferente criará apenas uma classe fortemente acoplada.