10

Background

I m reading the "Clean Code book", and, in paralel, I m working on calisthenic objects Kata like the banker account, and I m stuck on that rule :

The 9th rule of calisthenic objects is that we don't use getter or setters.

It seems pretty fun, and I agree with this principle. Moreover, at page 98-99 of Clean Code, the author explains that getters / setters break abstraction, and that we don't have to ask our object, but we have to tell our object.

This makes perfect sense in my mind, and I fully agree with this principle. The problem comes in practice.

Context

For example, I m having an application in which I have to list some users, and to display the user details.

My user is composed of :

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

Problem

How can I do, or what can I do to avoid getters when I only need to display a simple information (and I have to confirm that I don't need extra operation on that particular field) to display the Firstname value in a simple (random) output support ?

What comes up in my mind

One solution is to make :

user.getName().getFirstName().getStringValue()

Which is totatally terrible, breaking many rules of calisthenic objects, and breaking the Demeter Law.

Another one would be something like :

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

But I don't feel comfortable with this solution, that only seem to be a "higher order accessor" like bypassing standard getter/setter with a method that only aims to match Demeter law...

Any idea ?

16

The common misconception about the idea of avoiding getters and setters is to avoid them everywhere, which is impossible when you come to the surface of your architecture interacting with the user.

You should avoid using getters and setters in the business-logic part of your application, where objects should be protected using aggregates providing context, and methods should act as commands.

To avoid getters and setters you could design a solution similar to reactive programming, implementing reporting system through observable entities, but this extremely complicates architecture and makes no sense in CRUD level of your application, even though the design is really good for user interfaces.

Whether you should consider using getters/setters depends entirely on the part of application you are currently working at. If your concern is user interface using getters is completely fine, for business-logic, where you would run a part of a code based on a value retrieved through a getter, not so much (this screams that the logic should have been actually encapsulated within the class you are calling the getter on).

Also, law of demeter is not about counting dots, but merely about tearing apart a context-providing class by using getters on the class to obtain its components to which you shouldn't have access on its own.

If you feel like your user interface is going too deep within your business models, you can think about introducing view models to your system being responsible for transforming specific parts of models to visual representations.

  • Okay, I think of that suggestion just like a mapper between my domain entity, to a custom DTO for my presentation layer that would have some accessors right ? – mfrachet Jan 24 '17 at 11:07
  • @Margin Pretty much, yes. – Andy Jan 24 '17 at 12:49
  • All this cascading stuff sounds really good and smooth, thanks for the answer ;) – mfrachet Jan 24 '17 at 12:50
2

One direction to think would be to provide a generic string formatting member function, rather than providing access to the raw data. Something like this:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

You see, with this approach, you are not restricted to just providing the full data as it is, you can provide means to transform the data in convenient, meaningful ways. For instance, you might need to play tricks with character case:

String accountName = user.formatDescription("$(firstname).$(lastname)");

You could also define some commonly used, possibly complex formats once, so you could say, for instance

String fullAddress = user.formatDescription(User.kAddressFormat);

The beauty of this approach is, that it keeps the individual strings internal to the User class, while actually providing significantly more functionality to the calling code. However, the downside is, that you need to implement the templating mechanism within formatDescription() which will be a few lines of code.

As such, this might be complete overkill: Never forget that programming principles are only guidelines. And whenever following another principle is in violation of the KISS principle, it's likely best to just do it the simple way. So, unless you have at least some need for such a formatting member, I wouldn't bother implementing it for the sake of simplicity, using the accessor based approach.

  • 5
    This, however, looks like an SRP violation to me. Is it really the responsibility of a User object to parse and compile/interpret a templating language? – Jörg W Mittag Jan 24 '17 at 9:40
  • @JörgWMittag Not necessarily. As I said, the KISS-principle takes precedence. And I said nowhere that the User class has to implement this functionality itself. If I had only two classes that were in need of such functionality, you could bet on me factoring the template replacement mechanism out into its own class. This is meant to be an example of how you can lift the abstraction that User provides to a level where it is actually more than just a data container. And I believe, that's what avoiding accessors is all about: doing OOP instead of handling a bunch of structs. – cmaster Jan 24 '17 at 18:38
  • You know that KISS is totally subjective and SRP objective? KISS does not tell you anything about WHAT to do. And what is "Simple" to you may not "simple" to me. I see a real difference in the quality if arguing with KISS or SRP. – oopexpert Feb 2 '17 at 11:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.