How to implement business rules or system rules using Domain Driven Design in C#?

Asked

Viewed 2,089 times

8

I’m having doubts on how to separate business rules from system rules with the DDD.

If I have for example a Class Usuario with id,nome,login,senha as properties. A domain rule would require a password for the user, which would be a specification within the domain layer.

Now, a rule that would be: for the user to register the password, he must enter twice to confirm the password typed:

Would that be a rule within my domain layer? Or would it be in another layer?

3 answers

4

This is not a domain rule so it should not reside in the domain layer.

Login and login details are rules of application and not business.

Security, in general, are non-functional requirements (unless it is precisely security software, such as an integration tool with Active Directory).

In DDD, domain rules are defined by business experts. You can see a business expert talking about Pay Bills, for example, and at the same time asking to have to fill in two password fields instead of one?

In fact the business expert will not even ask for a login screen. He would rather not have to login if allowed.

Login and details of how to log into the system are definitely not business rules, so in DDD this does not belong to the domain layer.

You should write these rules in the application layer.

Eventually authorization* can be a domain rule if separation of duties is essential for business (sometimes even regulatory requirements).

Authorization* is the definition of how a user can interact with the system in the sense of what he can see and what he can modify.

In such cases, if the project core Domains and Generic subdomains, the authorisation belongs to a Generic subdomain.

3

This example is a little tricky to put in your domain class because you would have to have two password properties in your class, which would be weird. In that particular case you could put that rule somewhere else.

A clearer example would be something like checking if the customer has already paid for all previous purchases to complete a new purchase, it would look like below:

public class Cliente
{
    public ICollection<Compra> Compras { get; set;}
}

public class Compra
{
    public int Id { get; set; }
    public ICollection<Produto> Produtos { get; set;}
    public Cliente Cliente { get; set; }
    public bool Pago { get; get; }

    public void Fechar()
    {
        if (Cliente.Compras.Any(c => c.Id != this.Id && c.Pago == false))
            throw InvalidOperationException("Não é possível concluir a compra pois conta pagamentos em aberto");

        //TODO: código de fechamento de vendas
    }
}

2


The rule itself would stay in class Usuario. But you wouldn’t need to validate the password Usuario twice in the domain class, for when you say:

Now, a rule that would be: for the user to register the password, he must enter twice to confirm the entered password

This is more of a front-end validation, no need to also do it in the back-end (in the class Usuario).

Continuing the answer, in your case, you first need to check where to place your class Usuario within the system.

In the context of the DDD, it could be in a project of Domain (domain classes), in the context of the User (Usuarioctx) and within a User aggregation (Usuarioagg):

Projeto.Domain/UsuarioCtx/UsuarioAgg/Usuario.cs

The rule could be in a method within this class. But, however, until you get to your domain class, you’re expected to pass some Controller class. But, you also need to properly separate your project to house this controller class. One possibility is that it is in another Interface. If you are using REST, a suggestion would be:

Projeto.Interface/Services/Rest/UsuarioCtx/UsuarioController.cs

There, finally, you could have a service to register the password. As I said before, you can call this service after you validate, on the front end, if the user entered 2 identical passwords. Validated this, call a correct REST service (a PUT, as it is an update), as a cadastrarNovaSenha (method name in class, not service name! ) in your UsuarioController.

In the UsuarioController, make other relevant validations that, preferably, may be in the User domain class (example: check if the password is equal registered is equal to the new password, comparing the hash). Always taking care, of course, not to pass classes of Repository into your domain class to perform searches...

If you really want to validate the same form passwords back-end, you can use a simple method like this on Usuario.cs, being called the UsuarioController.cs:

public bool VerifySenhasIguais(String senhaNova)
{
     //TODO comparação com a senha atual
}

Once the necessary validations have been made, update the user with the new password and save again. This stage has more details, but I think your question does not cover this.

Remembering that I’m not getting into the merit of the discussion that you need all this to get what you want, but I’m giving you an example of what it could be.

  • I understood what you meant perfectly, it’s exactly how I thought you thought, although the way you answered it is different from the point of view of the question, I could understand what you meant by the separation of services implementations, interfaces, and also the care with the repositories, because the domain layer only has interfaces of repositories and not the concrete classes themselves....

Browser other questions tagged

You are not signed in. Login or sign up in order to post.