Improve Your Code With Object Calisthenics

Calisthenics scaled 1

IT Tips & Insights: A Softensity Software Engineer details how to write cleaner code through the rules of Object Calisthenics.

By Caio Vidal, Software Engineer

Object Calisthenics was defined by Jeff Bay in his book, “The Thoughtworks Anthology.” It defines 9 different rules that you can use to write your code and keep it clean. Note that Object Calisthenics is not a design pattern. It defines simple rules that you can apply focusing on the maintainability, readability, and comprehensibility of your code. So, you’re free to apply only those you find relevant.

The rules

  1. Only one level of indentation per method
  2. Don’t use the else keyword
  3. Wrap all primitives and strings
  4. First-class collections
  5. One dot per line
  6. Don’t abbreviate
  7. Keep all entities small
  8. No classes with more than two instance variables
  9. No getters / setters / properties

Only one level of indentation per method

Indentation is helpful to organize your code and nest all statements in our logic. However, too much indentation makes the code much harder to read and understand.

Here is an example:

As we can see we have 2 levels of indentations (on the first and second “for”) which makes it hard to follow the code. Rather than having the two “for” inside the method, we can move them to separate methods.

It will not reduce the number of lines, but will improve readability.

Don’t use the else keyword

The if/else construct is very popular in nearly every programming language. You’ve probably seen a nasty nested conditional that is impossible to follow without spending some time on it. It is all too easy to simply add another branch to an existing condition instead of refactoring it to a better solution.

Here is an example:

A simple way we can avoid the ELSE keyword is by making use of the early return pattern. When a condition is met, return the appropriate value. That way we can fail fast and avoid confusing conditional logic which is hard to read and understand.

In the example above, we moved the else conditions to a separated if statement with an early return.

Wrap all primitives and strings

This rule is easy. It requires you to avoid primitive obsession code smell. The main goal is that in certain scenarios, rather than having raw primitive types you should have a meaningful one.

Let’s jump into an example of a vehicle registration plate:

In this case, we should ask if the NumberPlate type holds more information than just its value. In this scenario, the answer is yes, it does.

Let’s see a different way of this type that time having a class rather than a raw primitive type.

As we can see now the type is turned into a class that holds useful information regarding the “numberplate” parameter. Having a dedicated type can help you apply unit tests to it and easily create test flows.

First class collections

This rule is intended to enforce that any class that contains a collection shouldn’t have any other member variables.Each collection should be wrapped in its class and then any behaviors related to the collection will have a home.

Let’s see an example:

As you can see, we are mixing the collection rules in the main class. As an example, “AddCandy” method is maintaining a logic that doesn’t belong to the candy shot but rather to the stock itself.

So now let’s apply the rule:

We now have a different class to wrap the stock collection. It is only caring about what it is responsible for: maintaining the shop candies. Every single logic related to the stock will be added to this class and we can reuse this class in any other place. Here we are not only enforcing Single Responsibility Principle, but also improving the reusability of our logic.

One dot per line

This rule will help you to be aware of which object should take responsibility for an activity. Looking at lines of code with multiple dots is a signal that you have many misplaced responsibilities, and the activity is happening in the wrong place.

Let’s jump into an example:

The line in the “ShowCurrentPieceInLower” method looks like having too many things to care about. We are likely not only violating SRP principle but also letting the method manipulate a field from Piece to which the class has no direct access. A better way would be to add the right responsibilities to each class like in the example below.

Now we are not exposing the fields from Location and Piece and each class has its activities. The “ShowCurrentPieceInLower” method is not only worried about calling the method within the Location class.

Don’t abbreviate

This one is straightforward. How many of you have seen abbreviations that make no sense to you? Abbreviations may seem like the right thing to do when you have long method or property names, but that is incorrect. Most of the time it is quite useful to have long method names rather than abbreviated small ones.

Looking at the above example we don’t know exactly what “P” from the “CreatePFromName” method stands for without looking at the parameters.

Rather, you can have:

Here we have long methods which make it much easier to understand. However, we still have some problems. 

  • Looking at the name of the “EvaluateSumAndPrintResultInConsole” method we can see that it is probably violating SRP principle.
  • We also probably have code duplication in the last two methods.

In the first case, we should have two separated major components: one for operation and the other one for displaying the value. This logic shouldn’t be mixed into a single method.

For “CreatePersonFromName” and “CreatePersonFromLocation” the creation of the “Person” object should be moved to its base class. I just want to reinforce that abbreviations are usually a red flag and the same applies to business names.

Keep all entities small

Let’s say you just started on an existing project with complex business logic to understand. Ok, you have been told that the “CustumerService.cs” is a good entry point, to begin with. Everything looks good except the fact that you see the scrolling bar shrinking, and your editor is showing more than 1k lines of code. This is not only hard to read and understand, but also hard to either add new code or maintain existing ones.

This is also a signal that the maintainers are not careful enough and may be skipping the core OOP principles and deteriorating the code base. As a goal, we can think of a limit of lines per class like a minimum of 50 lines and a maximum of 150. Of course, it all depends on your scenario, but I believe this is a good reference to start.

No classes with more than two instance variables

This rule is more like a metric to keep you aware of keeping a high cohesion and a better encapsulation of your objects. Adding a new instance variable to a class immediately decreases the cohesion of that class. If you have more than two instance variables in your class, you must start thinking about decomposing your instances into a new class.

No getters / setters / properties

Having public getters and setters may violate the encapsulation of your logic, letting any external code change the state of your object.

Let’s see an example:

As we can see here, any external code could add or reduce the amount of money of your candy shop. Of course, we don’t want that. Instead, we want to have the Money property maintained by the class itself and let it be accessible externally for read-only.

It would look like this:

So now we have a candy shop that is responsible for the logic of buying and selling candies. External code will change its state by using the new methods.

Conclusion

Although the rules that we described here are intended to improve your code, you don’t need to blindly follow them. That said, you should at least ask yourself and your code why they are being violated.

About

 

Hi everyone! I’m Caio. I’ve been a software engineer for more than 9 years. I have worked for companies in Brazil and abroad. I enjoy designing and implementing new projects, focusing on aligning the IT deliveries with the business’ needs. My primary aim is to continue learning and developing my programming skills in order to develop better software. I enjoy programming enough to do it in my spare time.

Join Softensity’s Team