This chapter moves Python from loose dictionaries into explicit domain models. The focus is not object-oriented ceremony. The focus is when a class or dataclass makes the rules easier to trust, evolve, and explain.

Why This Chapter Exists In The OrderOps Python Project

MID

This chapter moves Python from loose dictionaries into explicit domain models. The focus is not object-oriented ceremony. The focus is when a class or dataclass makes the rules easier to trust, evolve, and explain.

Inside OrderOps, this chapter shows up while the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. The goal is not to memorize one-off syntax. The goal is to make Python code readable enough to explain, safe enough to change, and grounded enough to discuss in an interview without sounding vague.

  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Milestone: model core order concepts with dataclasses or classes that preserve invariants and keep behavior near the relevant data
  • Interview lens: the next chapter makes data processing more expressive with comprehensions, iterators, and generators while keeping readability in view
  • The chapter teaches Python fundamentals through one connected backend and automation story.

A Class Becomes Worth It When The Data And Behavior Want The Same Name

EASY

Introduce a class when related state and behavior start traveling together often enough to deserve one concept.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes When To Use A Class a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: Keeping a growing domain concept as an unstructured dictionary makes invariants and behavior harder to place. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Interviewers like candidates who can say why a class exists beyond 'because OOP is good'.

  • Introduce a class when related state and behavior start traveling together often enough to deserve one concept.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: Keeping a growing domain concept as an unstructured dictionary makes invariants and behavior harder to place.
  • Interview lens: Interviewers like candidates who can say why a class exists beyond 'because OOP is good'.

order = {"id": "ORD-1", "subtotal": 49.99}
print(order["id"])

Dataclasses Are A Strong Default For Simple Domain Records

EASY

Use dataclasses when the main value is named fields and readable construction without hand-writing repetitive boilerplate.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Dataclass Basics a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: Avoiding dataclasses out of habit can leave beginner Python modeling more verbose than necessary. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Good answers mention that dataclasses improve clarity but do not replace design judgment.

  • Use dataclasses when the main value is named fields and readable construction without hand-writing repetitive boilerplate.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: Avoiding dataclasses out of habit can leave beginner Python modeling more verbose than necessary.
  • Interview lens: Good answers mention that dataclasses improve clarity but do not replace design judgment.

from dataclasses import dataclass

@dataclass
class OrderLine:
    sku: str
    quantity: int

Initialization Is Where Many Domain Rules First Need To Become Explicit

MID

Enforce the basic invariant when the object is created so the rest of the code can trust the instance.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Invariants In __post_init__ a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: Letting invalid objects exist and hoping later code cleans them up makes bugs harder to localize. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Interviewers often respect candidates who push validation to the moment state becomes real.

  • Enforce the basic invariant when the object is created so the rest of the code can trust the instance.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: Letting invalid objects exist and hoping later code cleans them up makes bugs harder to localize.
  • Interview lens: Interviewers often respect candidates who push validation to the moment state becomes real.

from dataclasses import dataclass

@dataclass
class OrderLine:
    sku: str
    quantity: int

    def __post_init__(self) -> None:
        if self.quantity <= 0:
            raise ValueError("quantity must be positive")

Behavior Belongs Near The Fields It Depends On

MID

Keep behavior on the object when it mainly exists to answer a question about that object's own state.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Instance Methods a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: If every operation stays outside the object forever, the model can become a passive bag of fields. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Candidates sound stronger when they explain why a method belongs on the object instead of in a utility module.

  • Keep behavior on the object when it mainly exists to answer a question about that object's own state.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: If every operation stays outside the object forever, the model can become a passive bag of fields.
  • Interview lens: Candidates sound stronger when they explain why a method belongs on the object instead of in a utility module.

from dataclasses import dataclass

@dataclass
class OrderLine:
    unit_price: float
    quantity: int

    def line_total(self) -> float:
        return self.unit_price * self.quantity

Composition Usually Models Order And Cart Relationships More Honestly Than Deep Hierarchies

MID

Connect smaller objects through references when the domain is about collaboration rather than type substitution.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Composition a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: Inventing inheritance too early often hides the real relationships in the problem. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Interviewers look for honest modeling rather than fashionable abstractions.

  • Connect smaller objects through references when the domain is about collaboration rather than type substitution.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: Inventing inheritance too early often hides the real relationships in the problem.
  • Interview lens: Interviewers look for honest modeling rather than fashionable abstractions.

from dataclasses import dataclass

@dataclass
class Cart:
    lines: list["OrderLine"]

Properties Are Useful When You Need A Controlled Public Surface Instead Of Naked Field Mutation

ADVANCED

Expose state in a way that protects invariants and makes derived behavior explicit when necessary.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Properties And Encapsulation a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: Blindly exposing mutable internal fields invites invalid state transitions later. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Candidates who talk about invariants instead of just 'privacy' sound more grounded.

  • Expose state in a way that protects invariants and makes derived behavior explicit when necessary.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: Blindly exposing mutable internal fields invites invalid state transitions later.
  • Interview lens: Candidates who talk about invariants instead of just 'privacy' sound more grounded.

class InventoryItem:
    def __init__(self, stock: int) -> None:
        self._stock = stock

    @property
    def stock(self) -> int:
        return self._stock

Factory Methods Help When Construction Needs A Clear Domain Name

ADVANCED

Use class methods when a named construction path explains the domain better than one raw initializer signature.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Factories a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: Forcing all construction through one overloaded initializer can make object creation harder to read. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Interviewers like hearing how factory names communicate meaning and hide conversion detail.

  • Use class methods when a named construction path explains the domain better than one raw initializer signature.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: Forcing all construction through one overloaded initializer can make object creation harder to read.
  • Interview lens: Interviewers like hearing how factory names communicate meaning and hide conversion detail.

from dataclasses import dataclass

@dataclass
class Money:
    cents: int

    @classmethod
    def from_dollars(cls, dollars: float) -> "Money":
        return cls(int(round(dollars * 100)))

A Mini Domain Model Should Read Like The Problem, Not Like Generic Containers

ADVANCED

The model is healthy when the reader can see orders, lines, totals, and validation responsibilities directly in the types.

In OrderOps, the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide. That makes Mini Domain Model a real engineering concern instead of a trivia topic. It affects whether the script or service stays easy to trust when another engineer reads it six weeks later.

The common failure mode is straightforward: If the model still feels like loosely connected containers, the chapter has not gone far enough. The stronger move is to make the rule explicit, keep the data shape visible, and leave a code path that is easy to narrate under interview pressure. Good interview prep includes being able to point at a model and explain why each type exists.

  • The model is healthy when the reader can see orders, lines, totals, and validation responsibilities directly in the types.
  • Project lens: the toolkit now carries orders, lines, customers, and inventory concepts that deserve clearer state and behavior than raw dictionaries provide
  • Common pitfall: If the model still feels like loosely connected containers, the chapter has not gone far enough.
  • Interview lens: Good interview prep includes being able to point at a model and explain why each type exists.

cart = Cart(lines=[OrderLine(unit_price=9.99, quantity=2)])
print(cart.lines[0].line_total())

Chapter Milestone And Interview Checkpoint

ADVANCED

The milestone for this chapter is clear: model core order concepts with dataclasses or classes that preserve invariants and keep behavior near the relevant data

That milestone matters because interview prep is not only about remembering Python features. It is about explaining why the code is shaped that way, what bug or maintenance cost the shape avoids, and what you would test before calling the work safe.

This chapter should end with two kinds of confidence. First, you should be able to write and read the code in context. Second, you should be able to explain the tradeoff behind it in plain engineering language.

  • Milestone: model core order concepts with dataclasses or classes that preserve invariants and keep behavior near the relevant data
  • Healthy interview answers explain both code behavior and design intent.
  • Good preparation means being able to trace a small example without guessing.
  • Bridge to next chapter: the next chapter makes data processing more expressive with comprehensions, iterators, and generators while keeping readability in view

Chapter takeaway

Use classes and dataclasses when the domain gains clarity from named state, invariants, and behavior that belongs near the data.