Object Calisthenics : Rule 2

Leo BchecheLeo Bcheche
4 min read

Hi Dev, have you heard about Object Calisthenics before?

Object Calisthenics is a set of nine coding rules introduced by Jeff Bay in The ThoughtWorks Anthology. The term combines "Object", referring to object-oriented programming (OOP), and "Calisthenics", which means structured exercises — in this case, applied to code. These rules are meant to help developers internalize good OOP principles by practicing them at the micro level, directly in their day-to-day coding.

You’re not expected to follow every rule 100% of the time. Instead, the idea is to use them as a guide — a structured constraint — to help shift your coding habits and improve the design of your software. As you apply these rules consistently, you’ll begin to see the benefits: better encapsulation, cleaner abstractions, and more testable, readable, and maintainable code.

Seven of the nine rules focus directly on strengthening encapsulation — one of the core principles of OOP. Another encourages replacing conditionals with polymorphism. The final rule helps improve naming clarity by avoiding cryptic abbreviations. Together, they push developers to write code that is free from duplication and easier to reason about.

At first, following these rules may feel uncomfortable or even counterproductive. But that friction is exactly the point — it forces you to break old habits and rethink how your objects interact. Over time, these small design constraints train you to write code that is simpler, more focused, and easier to evolve.

Today we’re diving into Rule #2: Don’t Use the else Keyword. Yes, you read that right. No else. At first, it sounds extreme, maybe even counterintuitive. But stick with me. This rule is about clarity, control flow, and reducing mental branching.

Removing else forces you to write more linear, readable, and intention-revealing code. When used carelessly, else can bury important logic and introduce complexity that’s easy to miss. Let’s see why this rule exists and how to apply it in real code.


Why else Can Be Harmful

The keyword else often hides what happens when a condition is not met. It couples two code paths: the “do this” and “otherwise, do that.” That coupling can reduce clarity, especially when each branch is long or includes more branching.

By removing else, we make each logical path more explicit and easier to follow.


The Strategy: Use Early Returns, Guards, or Extracted Methods

Let’s break this down with examples.

Example 1 – Simplifying Logic with Guards

# ❌ Using else
def grant_access(user):
    if user.is_admin():
        allow()
    else:
        deny()

Looks simple but what if this expands later?

# ❌ Soon it becomes:
def grant_access(user):
    if user.is_admin():
        log("Admin access granted")
        allow()
    else:
        notify_admin_request(user)
        log("Access denied")
        deny()

Now, the logic feels less direct. We have to mentally simulate what happens in both branches.

# ✅ With early return
def grant_access(user):
    if user.is_admin():
        log("Admin access granted")
        allow()
        return
    notify_admin_request(user)
    log("Access denied")
    deny()

Cleaner, right? Now we exit early from the "happy path", and what's left is the fallback, linear and clear.

Example 2 – Avoiding Nested Branches

# ❌ Using else in multiple levels
def decide_discount(user):
    if user.is_active():
        if user.has_coupon():
            return 0.2
        else:
            return 0.1
    else:
        return 0.0
r# ✅ Remove else by refactoring logic
def decide_discount(user):
    if not user.is_active():
        return 0.0
    if user.has_coupon():
        return 0.2
    return 0.1

This version is easier to read because each branch is self-contained and independent.

Example 3 – Delegating Fallback Behavior

# ❌ else hides a second responsibility
def get_avatar(user):
    if user.has_custom_avatar():
        return user.avatar_url
    else:
        return get_default_avatar()
# ✅ Delegate responsibility instead
def get_avatar(user):
    if user.has_custom_avatar():
        return user.avatar_url
    return get_default_avatar()

Or, better yet:

# ✅ Make the object responsible
def get_avatar(user):
    return user.get_avatar()

Let the object encapsulate the logic — this is a clean OOP move.


Why This Rule Matters

  • Separation of Concerns: Without else, you often end up splitting responsibilities into separate methods or classes.

  • Readability: Linear flow is easier for the human eye to scan.

  • Error Handling: Early returns help manage edge cases upfront.

  • Refactoring Clarity: Each branch becomes clearer to isolate and test.


Trade-offs

  • Mindset Shift: You’ll have to unlearn some habits from imperative programming.

  • Verbose Methods: Sometimes removing else increases the number of return points. That’s okay, clarity is worth it.

  • Feels Redundant at First: Especially in small functions. But as complexity grows, this rule shines.


Practical Tip

Whenever you write an else, ask yourself:

“Can I return early instead?”
“Can I invert the condition?”
“Can I move fallback logic into a helper method?”

This mindset builds clean, expressive code.


Works Great with Rule #1

Rule 2 pairs beautifully with Rule 1 (Only One Level of Indentation).
Both aim to flatten logic and promote small, focused methods.


Final Thoughts

Rule #2, “Don’t Use else,” isn’t about banning a keyword, it’s about cleaner flow and decoupling logic paths. You’ll gain better separation, clearer responsibilities, and code that’s easier to follow.

It might feel awkward at first. But with practice, you'll start to see when else is hiding complexity and you'll be equipped to write something better.

In the next article, we’ll continue exploring the Object Calisthenics rules, one by one.
Until then, go refactor some else away, your future self will thank you.

0
Subscribe to my newsletter

Read articles from Leo Bcheche directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Leo Bcheche
Leo Bcheche