How to avoid the use of setters in such cases?

7

In general object orientation it is advisable to avoid the use of setters. The usual justification for this is that logic that modifies the state of an object must be encapsulated in the object. Therefore, the ideal is the object to expose behaviors, and these behaviors have as a side effect their state modification.

The traditional example is a class representing a bank account. Instead of using a setter to modify the balance, the balance is modified as a side effect of transactions such as transfers. It would be something like

public class ContaBancaria
{
    public Saldo { get; private set; }

    public bool Transfere(decimal valor, ContaBancaria conta)
    {
        // Logica de transferencia
    }
}

It turns out that in some cases it is easy to identify the state change as a side effect of an object behavior. In the case of the account, the balance is modified when banking operations are performed. In the case of a product that has its quantity controlled in the stock, the quantity would be modified in processes of purchase and sale, etc.

The problem is that it has situations that it is really complicated to identify the state change in this way.

Some examples: a class that models a client, a class that models a user, a class that models a company.

In general these classes are part of the domain . They are concepts of the problem space, are terms of the ubiquitous language and are necessary for the operations of the domain. More than that, in general these classes have several properties.

For example: a customer has a name, has a CPF, has an associated email address, has a phone, an address, etc.

And that confuses me. Why you need to expose features to modify this state: change the name, the CPF, the email, the phone, the address, etc.

The problem is: what behavior is responsible for these changes? I think a lot and do not have it. When trying to name the method that changes the name for example, I have no idea what it would be.

If I go this way, I'll end up creating a ModificaNome method, but this is totally equivalent to a setter.

In these cases, where we can not initially identify a behavior responsible for the state change of a set of properties, how can we avoid using setters and get good object-oriented design?

    
asked by anonymous 28.07.2016 / 05:43

3 answers

7

The good design oriented object solves problems as best as possible. When it is used to meet nonsensical rules, it is not good design . If someone told you that you need to do this, it is better to review your influences (which is a right for you to choose them, not least because who will have to deal with the consequences is yourself).

As a side note perhaps this is due to obsession with a methodology that says something ideological.

Do the setter and you're done. There is something that is the modification of the pure and simple state, there is nothing to invent. Or nor do the setter if it really is not needed . And it's not always . This seems a heresy to some, but it is a valid solution when you know what you are doing. The links show a little more when you avoid it. Even if you do not want to opt for it because who knows, maybe one day, maybe you will need it and the DDD told me what to do, so use 0.

I do not know if the DDD says to avoid the setter , if it does it's just one more reason to put it away. Remedies help you, drugs consume you. I even agree that if it is natural to avoid it, do so, but do not let artificialities determine your path.

It has a methodology that is a collection of good practices that, as this question shows, bring more problems than solutions. The only good practice is to do the right thing in every situation. Either accept this generic fact to guide you, or analyze the concrete case to get a response you need. Trying to find concrete, standard answers in abstract cases does not usually work, because it generates such good practice.

So in the more or less concrete case presented in the question. What is the problem with having a property Nome of Cliente that does nothing special? If you can not answer this question definitively and simply, you are looking for a horse's head horn.

    
28.07.2016 / 11:46
3

Leonardo, your question is good and a specific part caught my attention:

  

The problem is: what behavior is responsible for these changes?

Realize that sometimes changing a simple information is a great behavior in itself. Who will tell you whether or not it is you will be the specialist in the business yourself.

Since you cited the CPF as an example, what would be the process in your business to exchange CPF?

  • Is it necessary to check if there is already another customer using this CPF?
  • Is this CPF not required to be on the bad debtor list?
  • Need to ensure that the CPF matches the name you've been informed?

Note that if at least one validation is required we can say that changing a CPF is dangerous and involves complexity, becoming an expected behavior of your system. To deal with this complexity we have removed the settler to encapsulate the change. We want to ensure that this CPF exchange will not generate an invalid state. Realize you have no ideology here. Only good practices.

Of all the examples you gave of attributes (name, CPF, address, email, phone) most likely, on any system a bit more complex, would be considered ValueObjects due to immutability.

Meanwhile ...

Changing your CPF does not mean anything too much in your project as it's just a simple value assignment, so you do not have complexity involved. If you do not have complexity involved, you do not need tools / processes / techniques to handle such complexity. Soon, DDD (or anything else to deal with complexity) would be Overengineering

    
29.07.2016 / 12:56
3

Great maturity in your interpretation. What you are noticing is that an oblique entity has its vision modified by who is looking at it. Taking the example of a Person :

  • The government sees you as RG, CPF, Civil Status, etc;
  • Your parents see you as Father's Eyes, Mother's Smile, Voice Ring, etc.
  • The doctor sees you as Sex, Weight, Height, Cholesterol, etc.
  • The postman sees you as Name, Zip Code, Number, etc;

This means that the same entity changes to context .

In software architecture, this pattern is called Bounded Context or Delimited Contexts .

This posture addresses this "nuisance" you are feeling. Your complete solution can, and should, have micro modules / services - totally isolated, inclusive. In the people registration module, you have the Person entity with name, date of birth, telephones, and finally, information pertinent to the context of registering people.

And in another module, banking, you have the entity Broker , where you have agency, account, image of the signature, etc. In this module, your entity has setters to manipulate bank data, but none to manipulate people's records. And vice versa.

In conclusion, look at Delimited Contexts that will meet that need you are already feeling, and make it all feel in software development in a responsible way.

    
28.07.2016 / 12:35