Object Calisthenics Concepts
Writing Better Object-Oriented Code Through Discipline
Object Calisthenics is a set of 9 coding rules meant to improve object-oriented design, code readability, and maintainability.
It’s not a framework or a library.
Think of it as discipline for writing clean OOP code, similar to how physical calisthenics train your body.
The concept comes from “The ThoughtWorks Anthology” by Jeff Bay.
These rules are intentionally strict. Their goal is not to be followed forever, but to train your design thinking and expose weak abstractions in your code.
1️⃣ Only one level of indentation per method
❌ BAD
def get_user(user):
if user_exists(user):
if user_logged_in(user):
return True
return False
✅GOOD
def get_user(user):
if user_exists(user) and user_logged_in(user):
return True
return False
Explanation
Deep nesting hides intent.
When you see multiple levels of indentation, your brain has to track too many conditions at once.
This rule forces you to:
Simplify conditions
Extract logic into methods
Make code easier to read at a glance
Less indentation usually means clearer logic.
2️⃣ Don’t use the else keyword
❌BAD
if user_exists():
process()
else:
error()
✅GOOD
if not user_exists():
error()
return
process()
Explanation
else tightly couples two branches of logic.
When requirements change, both branches usually need updates.
By returning early:
The unhappy path is handled first
The main logic stays flat and readable
The function becomes easier to extend
This pattern reduces mental load when reading code.
3️⃣ Wrap all primitives and strings
❌BAD
price = 100
✅GOOD
class Price:
def __init__(self, value: int):
self.value = value
Explanation
Primitives like int and str have no behavior.
They allow invalid values and spread rules across the codebase.
Wrapping primitives:
Gives meaning to the value
Allows validation in one place
Keeps business rules close to the data
This avoids repeating checks everywhere.
4️⃣ First-class collections
❌BAD
orders = []
orders.append(order)
✅GOOD
class Orders:
def add(self, order):
self._orders.append(order)
Explanation
If a collection has meaning, it should own its behavior.
Loose collections:
Scatter logic across files
Make it unclear who owns the rules
A first-class collection:
Encapsulates behavior
Protects invariants
Makes changes easier later
The collection becomes part of your domain model.
5️⃣ One dot per line
❌BAD
order.customer.address.city
✅GOOD
order.customer_city()
Explanation
Chained calls create tight coupling between objects.
This rule follows the Law of Demeter:
An object should talk only to its direct collaborators
Internal structure should stay hidden
It makes code less fragile when internals change.
6️⃣ Don’t abbreviate
❌BAD
cfg = Config()
✅GOOD
configuration = Configuration()
Explanation
Code is read more than it is written.
Abbreviations:
Save seconds when typing
Cost minutes when reading
Clear names improve understanding and reduce mistakes.
7️⃣ Keep entities small (≤ 50 lines)
If a class is large:
It has too many responsibilities
It’s lying about its name
Why
Small classes:
Are easier to test
Are easier to reason about
Encourage good separation of concerns
If a class grows too big, it usually wants to be split.
8️⃣ No classes with more than 2 instance variables
❌BAD
class User:
name
email
password
role
✅GOOD
class Credentials:
email
password
Explanation
Many fields often mean:
Procedural thinking inside a class
Multiple responsibilities mixed together
This rule forces you to:
Identify hidden concepts
Break large entities into focused objects
It leads to clearer domain models.
9️⃣ No getters/setters (Tell, don’t ask)
❌ (Logic Outside Class) BAD
if user.get_balance() > 100:
user.set_status("premium")
✅GOOD
user.promote_to_premium_if_eligible()
Explanation
Getters and setters move logic outside the object.
This creates:
Anemic domain models
Business logic spread across the system
Instead:
Tell objects what you want
Let them decide how to do it
Behavior belongs inside the object that owns the data.
For any questions, discussions, or collaborations, feel free to reach out at m.safi.ullah@outlook.com.
