DEV Community

Cover image for Code Smell 28 - Setters
Maxi Contieri
Maxi Contieri

Posted on • Originally published at maximilianocontieri.com

3 1

Code Smell 28 - Setters

The first exercise junior programmers do. IDEs, tutorial and senior developers keep teaching them this anti-pattern.

Problems

  • Mutability

  • Information Hiding

  • Anemic Models

  • Fail Fast

  • Integrity

  • Duplicated Code

Solutions

  1. Avoid Setters

  2. Set essential attributes on private initialization.

Sample Code

Wrong

class PhoneCall:
_origin = ''
_destination = ''
_duration = 0
def set_origin(self, originNumber):
self._origin = originNumber
def set_destination(self, destinationNumber):
self._destination = destinationNumber
def set_duration(self, durationInSeconds):
self._duration = durationInSeconds
janePhoneCall = PhoneCall()
janePhoneCall.set_origin('555-5555')
janePhoneCall.set_destination('444-4444')
janePhoneCall.set_duration(60)
# Anemic and mutable Class
view raw setters.py hosted with ❤ by GitHub

Mutation brings lots of problems

# Since you have a setter you can create invalid combinations
janePhoneCall = PhoneCall()
janePhoneCall.set_origin('555-5555')
janePhoneCall.set_destination('555-5555')
janePhoneCall.set_duration(60)
# You can't change the destination during the call.
# This is not enforced due to setters
# Origin and Destination cannot be the same
def set_destination(self, destinationNumber):
if destinationNumber == self._origin:
raise ValueError("Destination cannot be the same as origin")
self._destination = destinationNumber
def set_origin(self, originNumber):
if originNumber == self._destination:
raise ValueError("Destination cannot be the same as origin")
# repeated code
self._origin = originNumber

Information Hiding Violated

class PhoneCall:
_origin = ''
_destination = ''
_duration = 0
def set_duration(self, durationInSeconds):
self._duration = durationInSeconds
def get_duration(self):
return self._duration
# duration is exposed in seconds as a ripple effect
# this violates information hiding principle
# and prevents you from changing it representation
view raw duration.py hosted with ❤ by GitHub

Right

class PhoneCall:
_origin = ''
_destination = ''
_durationInSeconds = 0
def __init__(self, origin, destination, durationInSeconds):
if destination == origin:
raise ValueError("Destination cannot be the same as origin")
# single control point.
# You only create valid phone calls
# and they remain valid since they cannot mutate
self._origin = origin
self._destination = destination
self._durationInSeconds = durationInSeconds
# No setters are necessary
def durationInSeconds(self):
return self._durationInSeconds
def durationInMilliSeconds(self):
return self._durationInSeconds * 1000
view raw immutable.py hosted with ❤ by GitHub

Detection

First step will be to forbid public attributes (if language allows them).

Secondly, we will search for methods setXXXX(), analyzing method structure (should be an assignment to attribute xxxx).

We should not forbid methods setting accidental state since this is valid. They should not be named setters since they ask the object to change, but they don't set anything.

Examples

  • DTOs

Exceptions

Setting attributes is safe for non-essential attributes.

But it has all drawbacks and considerations already mentioned.

Tags

  • Mutation

  • Information Hiding

Conclusion

Creating incomplete and anemic objects is a very bad practice violating
mutability, fail fast principle and real world bijections.

Relations

More Info

Fail Fast

Here is the full discussion on Setters

Credits

Photo by Victor Rodriguez on Unsplash


Object-oriented programming languages support encapsulation, thereby improving the ability of software to be reused, refined, tested, maintained, and extended. The full benefit of this support can only be realized if encapsulation is maximized during the design process.

Rebecca Wirfs-Brock

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Billboard image

Deploy and scale your apps on AWS and GCP with a world class developer experience

Coherence makes it easy to set up and maintain cloud infrastructure. Harness the extensibility, compliance and cost efficiency of the cloud.

Learn more

Retry later