I love learning new things, often the way we code solutions has a cool name that we actually did not know about. Object Calisthenics
is such a case (for me anyway) - I was amazed to read / watch engineers build and talk about code and draw similarities to the way I approach code solutions in the real world.
Calisthenics are exercises that don’t rely on anything but a person’s own body weight.
Interesting that this name was chosen :)
As with all patterns and principles, they are not rules but mostly rather guidelines. The actual implementation is always tailored to the problem and each engineers solution will be built from their perspective.
So what are object calisthenics? Well they are a set of rules written by Jeff Bay (The Thoughtworks Anthology) and consist of the ‘rules’ defined below. I’m always sceptical of ‘rules’ for programming but feel its import to try understand other peoples perspective - we can ALL always learn something :)
- One level of indentation per method
- Dont use the ELSE keyword
- Wrap all primitives and strings
- First class collections
- One dot per line
- Dont abbreviate
- Keep all entities small
- No class with more tan 2 instance variables
- No getter/setter properties
Most of the content below is based on the amazing work by Nick Chapsas. What a legend!
Examples below were simplified for readability.
One level of indentation per method
This is the level of nesting in methods. The value of following this is debatable but I do feel it will highlight where logic could possibly be injected and follow Single Responsibility Principle (SRP)
You can extract whole code blocks out to be their own private methods and where these grow or can be grouped extract them out to their own classes.
Example:
1 | public void AskForDrink() |
Becomes:
1 | public void AskForDrink() |
Dont use the ELSE keyword
This this can significantly increase your codes readability, its not that we really remove the else
but rather making use of language features to return when the else
would be evaluated.
This is not going to work for MVC Views or Blazer but it can work very well for your class files (code behind)
Using else
conditions can also introduce smells like violation of Open/Closed Principle (OCP), so everytime we need a new condition the else if
is used which is a modification.
Example:
1 | private void HandleBeer() |
becomes
1 | private void HandleBeer() |
Simple checks like these can also be represented with a ternary operator but that depends on your team ways of working - its always best to keep the code copy the same thoughout the code base.
1 | _outputProvider(age >= 18) |
Nick also extracted the whole age check out into its own method HandleBeerAgeCheck(int age)
but I felt the above was fine.
Use a switch
If you are using a modern IDE like Visual Studio 2022 it will make these suggestions for you. This is not explicitly removing else
, its just a different type of check which most engineers would find acceptable.
Example:
1 | public void AskForDrink() |
becomes
1 | public void AskForDrink() |
Wrap all primitives and strings
A primitive type is a built in type, see example C# types. Note that in some languages, strings are not primitives. (They are in C#)
First class collections
https://youtu.be/gyrSiY4SHxI?t=402