Clean code story — How to give sense to your code

Using encapsulation and Tell don’t ask principle

Nash
5 min readJun 19, 2023

Have you ever come across a method in your code that is seemingly endless? You scroll and scroll, but the brackets don’t seem to end. That’s usually a clear indication that the method is trying to do too much, and it’s high time for some cleaning.

When we talk about clean code, we’re discussing code that is easy to read, understand, and change. Long methods are often the enemies of clean code. They can be hard to understand, tricky to debug, and resistant to modification. Today, we’ll explore how encapsulation and the ‘Tell, Don’t Ask’ principle can help us shorten our methods and write cleaner, more maintainable code.

Encapsulation for Cleaner Code

Encapsulation is one of the four fundamental principles of object-oriented programming (OOP). It suggests that the data of an object should be hidden from outside world and can be accessed only through methods of its own class. This increases modularity and maintainability of the code.

When you encapsule your data, that means your setter are private. Ideally, your getter also are. You can then only manipulate the instance using methods that match operation you would apply on it.

This simple code example show a code without encapsulation. If you want to increment your counter, you use the counter service to increment. Or maybe worse, you don’t know about this service, and duplicate the code elsewhere.

Now there is the same example, using encapsulation. If I want increment the counter, I have no choice except using increment(). This have many advantages.

  • First it tell what operation are possible on this class.
  • Second, avoid the code duplication, as the “count” property is not accessible, no one can duplicate this behaviour.
  • Third, it protects the class internals, the behaviour implementation. This means that the count property can be an int, a float, or a subclass, that doesn’t matter from an external point of view. Because the fact that we call “increment” and doesn’t manipulate the count property, we don’t care about how the count is done.

The ‘Tell, Don’t Ask’ Principle

The ‘Tell, Don’t Ask’ principle suggests that we should command objects to perform actions, rather than asking them about their state and making decisions on their behalf. By following this principle, we can further shorten our methods and make our code more readable and maintainable.

Going back to our example, we need to know if the counter is more or less than a number to decide if we make an action or not.

The service manipulate the counter to do an action every 10 times.
Now there is a version using encapsulation and tell don’t ask principle.

The count property is internal to the counter object. Code becomes more readable, cleaner, and it’s protected against duplication.

An even better approch could be to create a new object, a Timer for example, to encapsulate this behaviour instead of using a service.

This Timer use a counter as an internal dependency, but it’s hidden from an external point of view. As a timer user, we only create a timer, then call increment(). We don’t care about how increment work, and how the action will be executed. We trust the Timer, and can’t do anything against that, because all the timer behaviour is protected.

This approach not only helps us to ensures that our objects maintain their own state and behavior, adhering to the principles of OOP.

Ecapsulation discovery

One useful approach is to follow the principle of “high cohesion,” which suggests that methods within an object should be closely related and work together to accomplish a specific task. This means that a method should operate on the object’s internal state or collaborate with other methods of the same object.

Another consideration is to analyze the external interactions with the object. By applying the “Tell Don’t Ask” principle, we can identify opportunities for encapsulation. Instead of exposing the internal state and allowing external entities to manipulate it directly, encapsulation encourages defining methods that encapsulate the necessary operations and provide a controlled interface for interacting with the object.

Additionally, examining the parameters passed to methods can guide the creation of new methods. If a method only has one parameter, it may be an indication that the functionality it performs can be encapsulated by the type of that parameter. By encapsulating such methods within the relevant object, we enhance code organization and improve the clarity of the codebase.

Ultimately, discovering the methods to create or add to an object requires a thoughtful analysis of the object’s responsibilities, behaviors, and interactions. By considering the principles of high cohesion, encapsulation of operations, and parameter-based encapsulation, we can effectively identify and define the appropriate methods that enhance the encapsulation, modularity, and maintainability of our code.

The Payoff

By embracing encapsulation and the ‘Tell, Don’t Ask’ principle, we can significantly shorten our methods by dispatching code to the nearest to responsible of the data and avoiding duplication. These practices allow us to create cleaner and more modular code. In the process, we also create code that is easier to test and less prone to bugs.

Clean code might require more effort in the short run, but the benefits it provides in terms of readability, maintainability, and testability make it a worthwhile investment.

Remember, clean code is not just about shorter methods. It’s about creating a code base that your future self and other developers can read and understand with ease. It’s about code that can stand the test of time and adapt to changing requirements.

So, the next time you come across an excessively long method, consider using encapsulation and the ‘Tell, Don’t Ask’ principle. These powerful tools will go a long way in your journey towards writing clean code.

--

--