Video summary

Your Data Structure Is Too Flexible

Main summary

Key takeaways

Technology

Overview

The video critiques “too flexible” data passing in backend/domain logic—e.g., using Python dictionaries and **kwargs—using a flight booking example. It then refactors the design into a strict domain model with validation and constrained types.


Problem with the original code (unstructured input)

A create_booking function accepts a loose dictionary / keyword arguments. While it “works,” it hides important domain rules:

  • Keys like passenger_name, flight_number, price, status, loyalty are treated as generic values (strings/booleans/etc.).
  • No guarantees exist for:
    • valid status values (e.g., scheduled vs cancelled)
    • valid seat types
    • price constraints (e.g., non-negative)
  • Critical required data (e.g., seat) is pulled from **kwargs, making the function’s real contract implicit or “secret.”

Core guidance: flexibility at boundaries, strictness in the domain

  • Dictionaries / flexible structures are fine at system boundaries, such as:
    • JSON payloads
    • config files
    • API request bodies
    • framework hooks
  • Inside business logic / domain functions, the data should be modeled explicitly and validated.
  • Otherwise, you end up adding scattered checks throughout the codebase, increasing the chance of broken behavior—especially with AI coding assistants that rely on structure.

Refactor steps: making the model strict

1) Replace dict + **kwargs with a typed data class

  • Introduces a frozen BookingRequest data class with explicit fields:
    • passenger_name
    • flight_number (string)
    • price (converted to Decimal)
    • status
    • loyalty
    • seat moved from **kwargs into the request object (with a default like "standard")

Result: create_booking(request) has a clear contract and uses request.field instead of dictionary indexing or magic keyword arguments.


2) Introduce richer domain objects (decompose concepts)

Creates domain classes representing meaningful entities:

  • Passenger (name + loyalty)
  • Flight (number + price + status)

Result: BookingRequest and create_booking use Passenger and Flight objects rather than raw primitive fields, reflecting the actual domain concepts and making extension safer.


3) Constrain string fields with enums

Adds enums for fields that should only have certain values:

  • Flight status (e.g., scheduled/cancelled)
  • Seat type (e.g., standard, extra_leg_room)

Result: invalid seat types/status values no longer silently flow through the system; extending the domain (adding new seat types) becomes explicit.


4) Add a “value object” for money with invariants

  • Introduces a Money value object instead of plain Decimal:
    • stores amount as Decimal
    • validates invariants in __post_init__ (e.g., amount must be positive or zero; negative raises ValueError)

Result: money-related rules are enforced automatically and consistently close to the concept itself.


5) Move behavior closer to domain objects

  • Adds behavior such as Money.discounted(percentage) returning a new Money.
  • Moves flight validity logic into Flight, e.g., an ensure_bookable() method that raises if the flight is cancelled.

Result: create_booking becomes shorter and focuses on orchestration rather than status/money validation details.


Boundary integration: using validation libraries (example: Pydantic)

The refactor makes object creation more “annoying” because domain objects must be constructed explicitly. The suggested approach is a translation/validation step at boundaries using Pydantic:

  1. Define an input model (e.g., BookingInput)
  2. Validate raw API data (including constraints like non-negative price)
  3. Convert validated input into strict domain objects via something like to_domain()

Result: raw/dynamic input remains flexible at the boundary, but the domain only receives validated strict types.


Design nuance: not everything must be custom-modeled

The design keeps flight_number as a plain string because it’s mainly displayed/passed through and doesn’t yet have meaningful rules/validation.

Emphasis: domain modeling doesn’t require wrapping every primitive—add strict guarantees where they matter (e.g., enums for status/seat, value objects for money, validated domain rules for cancellability).


Benefits claimed

  • Explicit models reject invalid states (seat type/status/negative prices).
  • Clear contracts for functions like create_booking(request).
  • Better IDE/autocomplete and improved context for AI code generation.
  • Safer refactoring because fields are explicit attributes (not hidden dictionary-key structures).

Main speakers / sources

  • Primary speaker: the video’s author/instructor (speaking directly to camera and referencing their “brand new software design mastery program”).
  • No other named sources are provided besides Pydantic and the concept of AI coding assistants.

Original video