DEV Community

Discussion on: Avoid getters and setters whenever possible

Collapse
 
dstefanow profile image
Dobromir Stefanov

What we have to use if we want validation for the current field only in the class?
... Yes we use setters!

These examples are not correct and don't give a logical answer to the question why we shouldn't use getters and setters.

Collapse
 
scottshipp profile image
scottshipp

Hi Dobromir! I mentioned the case of validation in a setter as a valid usage, in the section "When getters make sense"

In a setter, before updating the state in this object according to some input, we validate the input.

Nevertheless, a key point that shouldn't be overlooked is to prefer to make validation part of a behavior rather than part of a setter. For example, let's say a web site has a place where potential customers can enter their name and email address to request more information. When someone enters their information in the form and submits it, we want to perform a number of actions including but not limited to:

  • Validate the email address
  • Save the email address along with other data like the current date and time
  • Kick off an automated email which has more information for the customer
  • Schedule a follow up email for a couple days from now to remind the customer about the product

A common approach is that once the web server receives the request, an object called Customer or User is created with name and email fields. The object is passed around the application and the name, email, and other fields are constantly gotten and set. For example the first thing that may happen is a database lookup which indicates we already have other information for this person, and those fields are all set on the existing object.

Well, whether or not the validation of the email happens in this object, and whether or not it happens in the constructor or setter, I think this data-centered approach is fundamentally flawed. Consider the case where we change what data we collect. Instead of name and email, now we're going to do it with name and cell phone and we're going to use SMS messaging to interact with the customer, because SMS has eight times the response rate of email (retaildive.com/ex/mobilecommerceda...).

In this scenario, we switched from email to phone, and now we go refactor every place in the application that calls getEmail() or setEmail().

Instead, what if we took behavior as the first-class citizen of this scenario. What behavior do we want to happen when the customer submits their data? We want to give them more information. OK. We make an interface PotentialCustomer with a giveMoreInformation() method. (Sidebar: the naming here could use some work probably). We implement this interface for our name and email scenario.

When the web server receives this data, it creates the instance of our implementation of PotentialCustomer. The name and email data is passed to PotentialCustomer via the implementation's constructor, and this data is private and immutable so the rest of our application doesn't even know (or care) that we're using name and email.

The PotentialCustomer is composed of other members, who are themselves behavioral objects, and each have a task. One persists the data. Another sends the initial email. Another schedules the follow-up. All of this is called when giveMoreInformation() is invoked.

Now we have a much better situation for the update to use SMS instead of email. The worst case here is that we create a new implementation of the PotentialCustomer interface for this scenario. We don't need to refactor code across many paths.

Does that makes better sense?