0Pricing
Clean Architecture & Design Patterns in Practice · Lesson

Enforcing Business Rules with Invariants

Learn to encode critical business rules as invariants inside entities so the domain can never enter an invalid state.

Enforcing Business Rules with Invariants is a free Clean Architecture & Design Patterns in Practice lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Clean Architecture & Design Patterns in Practice learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Rules That Must Always Hold

Beyond use-case logic, a domain has rules that must be true at all times. An account balance never goes below zero; an order always has at least one line item.

These are invariants, and the core should make them impossible to violate.

Entity Invariants vs Use-Case Rules

Two layers of rules exist:

  • Entity invariants: always true regardless of operation (Enterprise Business Rules).
  • Use-case rules: govern a specific workflow (Application Business Rules).

Invariants belong inside the entity itself.

The Danger of Anemic Entities

An anemic entity is just public fields with no protection.

class Account {
    public double balance; // anyone can set anything
}

Guarding Construction

Enforce invariants when the entity is created. An invalid entity should never exist.

class Account {
    private double balance;
    Account(double initial) {
        if (initial < 0) throw new IllegalArgumentException("balance < 0");
        this.balance = initial;
    }
}

Guarding Mutation

Every state change must preserve the invariant. Expose intent-revealing methods, not setters.

void withdraw(double amount) {
    if (amount <= 0) throw new IllegalArgumentException("amount");
    if (amount > balance) throw new IllegalStateException("insufficient funds");
    balance -= amount;
}

Make Illegal States Unrepresentable

A stronger goal than checking: design types so invalid states cannot be expressed.

Use value objects, enums, and required constructor arguments so the compiler enforces what it can before runtime checks ever run.

Value Objects Carry Their Own Rules

Wrap primitives in small immutable types that validate themselves.

final class Email {
    private final String value;
    Email(String v) {
        if (!v.contains("@")) throw new IllegalArgumentException("bad email");
        this.value = v;
    }
}

A Runnable Demonstration

The entity rejects an invalid operation, protecting the invariant.

public class Main {
  static class Account {
    private double balance;
    Account(double b){ if(b<0) throw new IllegalArgumentException(); balance=b; }
    void withdraw(double a){ if(a>balance) throw new IllegalStateException("insufficient"); balance-=a; }
    double getBalance(){ return balance; }
  }
  public static void main(String[] args){
    Account acc = new Account(100);
    acc.withdraw(30);
    System.out.println("Balance: " + acc.getBalance());
    try { acc.withdraw(1000); } catch(Exception e){ System.out.println("Blocked: " + e.getMessage()); }
  }
}

Keep Infrastructure Out

Invariant checks are pure domain logic. They must not reach for a database, network, or framework.

If validating a rule needs external data, that check belongs in a use case (interactor), not the entity.

Invariants and Testing

Because invariants live in pure entities, they are trivial to test: construct, call a method, assert the rule held or the operation was rejected.

No mocks, no database, no framework — fast and reliable tests.

Design Guidelines

  • Validate on construction and on every mutation.
  • Replace public setters with intent-revealing methods.
  • Use immutable value objects for self-validating data.
  • Keep all checks framework-free.

Quick Check

Test your understanding of invariants.

Recap

You learned to protect the domain with invariants.

  • Entity invariants always hold; use-case rules govern workflows.
  • Validate on creation and mutation; prefer unrepresentable illegal states.
  • Keep checks pure for easy testing.

Frequently asked questions

Is the “Enforcing Business Rules with Invariants” lesson free?

Yes — the full text of “Enforcing Business Rules with Invariants” is free to read here on the web, and the Clean Architecture & Design Patterns in Practice course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Clean Architecture & Design Patterns in Practice course, upgrade to CoddyKit PRO.

What will I learn in “Enforcing Business Rules with Invariants”?

Learn to encode critical business rules as invariants inside entities so the domain can never enter an invalid state. You practise Clean Architecture & Design Patterns in Practice with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Clean Architecture & Design Patterns in Practice?

No prior experience is required. Clean Architecture & Design Patterns in Practice on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Enforcing Business Rules with Invariants” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Clean Architecture & Design Patterns in Practice lesson?

Yes. Every Clean Architecture & Design Patterns in Practice lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Designing Business Entities
  2. Implementing Use Cases (Interactors)
  3. Input and Output Ports
  4. Enforcing Business Rules with Invariants
← Back to Clean Architecture & Design Patterns in Practice