SwadhyAI Notes

All Low-Level Design notes

Behavioral modeling

State machine vs status enum

Status is a label on an entity (CREATED, ACTIVE, PAID). The State pattern is for when each mode has real behavior of its own. Both model a machine; they are not the same tool size.

Example: a ticket has four chapters and almost no extra behavior — activate, pay, close. A vending machine has the same coin() and select() buttons, but idle, has-coin, and sold-out each do something different. Prefer an enum plus guards for the ticket; prefer State objects for the vending machine.

Ticket

Add a row

Small table, short commands, one class. CREATED → ACTIVE → PAID → CLOSED. Illegal CLOSED → ACTIVE is a missed row, not a missing class.

  • Orders, bookings, invoices — same shape.
  • Behavior is “may I?” not “do a policy.”
  • New chapter = new enum value + one legal move.

Vending / ATM

Add a class

Same methods, different work per chapter. coin() and select() mean something else in idle versus sold-out. Elevator movement and ATM sessions belong here.

  • Each state holds real code, not a one-line require().
  • The current state picks the next state.
  • New chapter = new type that implements the buttons.
Status enum + guards     Ticket, Order, Booking
  small table, short commands, one class

State objects            Vending, ATM, Elevator
  same methods, different work per chapter

Neither                  auth → balance → limit
  that is a pipeline of steps, not a life cycle

The test

If I add a state, do I add a class, or do I add a row to the table? Ticket: a row. Vending: a class. Pick the smaller tool that still makes illegal arrows impossible. A is enough when the states are labels and the commands are short. Reach for a when the in each chapter.

Do not use State objects to hide a workflow that is actually a of checks. Auth then balance then limit is a chain, not four statuses of the same account. Do not use a status enum when every branch is a page and the next product request will add two more chapters of behavior — you will drown in switch.

Ticket: status is enough

CreatedState, ActiveState, PaidState, ClosedState that only assign an enum are extra ceremony. A table and three commands are the design. CLOSED → ACTIVE still throws. You did not need eleven types to get there.

java
enum TicketStatus { CREATED, ACTIVE, PAID, CLOSED }

class Ticket {
  private TicketStatus status = TicketStatus.CREATED;

  void close() {
    if (status != TicketStatus.PAID) throw new IllegalStateException();
    status = TicketStatus.CLOSED;
  }
}

// Adding REFUNDED: one enum value, one command, one legal row.
// You did not need a RefundedState class.

Vending: behavior changes with the chapter

Idle.coin → HasCoin. SoldOut.coin → still SoldOut (reject). Each class holds the behavior. Ticket did not need this. When the switch on an enum grows a page per button, extract objects — and then open the State pattern note. This page only makes the choice.

java
interface VendingState {
  VendingState coin(VendingMachine m);
  VendingState select(VendingMachine m, String slot);
}

class Idle implements VendingState {
  public VendingState coin(VendingMachine m) { m.addCredit(); return new HasCoin(); }
  public VendingState select(VendingMachine m, String slot) { return this; /* ignore */ }
}

class SoldOut implements VendingState {
  public VendingState coin(VendingMachine m) { m.refund(); return this; }
  public VendingState select(VendingMachine m, String slot) { return this; }
}

// Same buttons. Different work. Ticket’s pay() is not this.

Do not confuse State with Strategy

Both swap an object the context holds. Strategy is “how do I do this job?” — you pick nearest versus random, and the strategy does not appoint its successor. State is “what am I right now?” — Idle becomes HasCoin because a coin arrived. Pricing is Strategy. Vending sessions are State. Ticket’s enum is a tiny machine, not a strategy. See Strategy when the interviewer changes the fee, not when they change the chapter.

Use enum

Ticket, order, booking. Short guards. One table.

Use objects

Vending, ATM, elevator. Fat methods per chapter.

Use neither

Auth → balance → limit. A pipeline, not a life.

Common mistakes

State objects for a four-step ticket

CreatedState, ActiveState, PaidState, ClosedState that only assign an enum are extra ceremony. A table and three commands are the design. CLOSED → ACTIVE is still just a missing row.

A status enum when each state is a page of code

A switch that grows with every button on the vending machine is the smell. That is when states become objects — and when you open the State pattern note.

Calling a pipeline a machine

Four checks in a row are not four lives of the same object. Keep Chain of Responsibility (or a list of validators) for that shape.

How to choose: say it clearly

“Ticket is a status with a table. Vending would be State objects because coin() changes meaning. I am not starting with the pattern name.” That statement is the design decision. The machine and the table come first either way.

A switch that is already too fat

If insertCoin has four cases and each case is fifteen lines, you are past enum-plus-guard even if you still have an enum. Extract the cases into types. Keep the context thin: VendingMachine holds money and inventory, and delegates buttons to state. Ticket never reached that size. Do not extract early to look clever; extract when the next button would touch every case.

Elevator is the usual follow-up. idle, moving, boarding — open(), close(), step() mean different work. That is objects. A lift “status” string plus a 60-line move() is the smell this page exists to catch.

Ticket checklist

  • Four labels, three short commands.
  • Adding REFUNDED is one row.
  • CLOSED → ACTIVE is a missed row, not a missing class.

Vending checklist

  • coin() and select() change meaning per chapter.
  • Adding SoldOut is a new type.
  • A 40-case switch is the smell.
  • Context stays thin; states appoint the next state.

When unsure, ship the enum. Promote to objects the moment a button’s meaning forks. Do not promote Ticket to look like vending.

Read next

Takeaway

Both Ticket and vending are machines. Ticket adds a row. Vending adds a class. Start with enum-plus-guard. Reach for State objects when the same button does different work. A pipeline of checks is neither. Illegal arrows stay impossible either way.