<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc" -->

---
title: Your Data Structure Is Too Flexible | daily.dev
description: A step-by-step refactoring walkthrough showing how to replace loose Python dictionaries and keyword arguments with a strict domain model. Starting from a...
canonical: https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Your Data Structure Is Too Flexible | daily.dev
og:description: A step-by-step refactoring walkthrough showing how to replace loose Python dictionaries and keyword arguments with a strict domain model. Starting from a...
og:url: https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc
og:image: https://api.daily.dev/og/posts/9lqth6GSc.png
og:image:alt: Your Data Structure Is Too Flexible
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Your Data Structure Is Too Flexible

**[ArjanCodes](https://daily.dev/sources/arjancodes)** · 20 min read · 3 upvotes · 0 comments

## Summary

A step-by-step refactoring walkthrough showing how to replace loose Python dictionaries and keyword arguments with a strict domain model. Starting from a flight booking function that uses untyped dicts, the tutorial progressively introduces frozen dataclasses, dedicated domain objects (Passenger, Flight, BookingRequest), enums for constrained values (FlightStatus, SeatType), and a Money value object with validation. It also demonstrates using Pydantic at the system boundary to validate raw API input before converting it into the strict domain model. The key takeaway: flexibility is appropriate at system edges (APIs, config), but business logic should operate on explicit, validated domain types.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.youtube.com/watch?v=lM7zWJRrRtg>

## Questions this post answers

### When should I use a dictionary versus a dataclass for domain data in Python?

Dictionaries and keyword arguments work well at the edges of a system, such as JSON payloads, config files, API inputs, or framework hooks, where structure is inherently flexible. Inside domain or business logic, data should be modeled with strict types like frozen dataclasses, enums, and value objects so invalid values are rejected rather than silently flowing through the system.

_Developers deciding where to draw the line between flexible and strict data modeling can find real-world refactors like this on daily.dev._

### How do I validate that a money amount is never negative in a Python dataclass?

Define a frozen dataclass called Money wrapping a Decimal amount, then add a __post_init__ method that checks the amount is greater than or equal to zero and raises a ValueError otherwise. This turns money into a value object with built-in validation, and behavior like applying a percentage discount can be added as a method that returns a new Money instance.

_Engineers building validation-heavy domain models can track patterns like this value object approach on daily.dev._

### Why use Pydantic instead of plain dataclasses for API input validation in a domain-driven Python app?

Pydantic validates raw API input, such as enforcing that price cannot be negative, and can convert that validated input directly into strict domain objects via a to_domain method. This keeps flexible, unvalidated data at the API boundary while ensuring only strict, validated domain objects like BookingRequest reach the core business logic.

_Teams choosing between Pydantic and plain dataclasses for domain boundaries can follow comparisons like this on daily.dev._

## Similar posts on daily.dev

- [Pydantic Performance: 4 Tips on How to Validate Large Amounts of Data Efficiently](https://daily.dev/posts/pydantic-performance-4-tips-on-how-to-validate-large-amounts-of-data-efficiently-v04aqj3wt) · Towards Data Science · 2 upvotes · 0 comments
- [The Complete Guide to Pydantic for Python Developers](https://daily.dev/posts/the-complete-guide-to-pydantic-for-python-developers-ingakiix5) · Machine Learning Mastery · 3 upvotes · 0 comments

---

Tags: [#python](https://daily.dev/tags/python), [#domain-driven-design](https://daily.dev/tags/domain-driven-design), [#pydantic](https://daily.dev/tags/pydantic)

[View this post on daily.dev](https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Your Data Structure Is Too Flexible","url":"https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc"},"datePublished":"2026-07-31T15:24:51.945Z","dateModified":"2026-09-14T06:52:14.800Z","description":"A step-by-step refactoring walkthrough showing how to replace loose Python dictionaries and keyword arguments with a strict domain model. Starting from a...","image":"https://i.ytimg.com/vi/lM7zWJRrRtg/sddefault.jpg","thumbnailUrl":"https://i.ytimg.com/vi/lM7zWJRrRtg/sddefault.jpg","isAccessibleForFree":true,"articleSection":"ArjanCodes","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"ArjanCodes","logo":"https://media.daily.dev/image/upload/s--QX1BCjx9--/f_auto,q_auto/v1777800752/logos/arjancodes?_a=BAMAMiWQ0","url":"https://daily.dev/sources/arjancodes"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":3},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"python,domain-driven-design,pydantic","timeRequired":"PT20M","video":{"@type":"VideoObject","name":"Your Data Structure Is Too Flexible","description":"A step-by-step refactoring walkthrough showing how to replace loose Python dictionaries and keyword arguments with a strict domain model. Starting from a...","thumbnailUrl":"https://i.ytimg.com/vi/lM7zWJRrRtg/sddefault.jpg","uploadDate":"2026-07-31T15:24:51.945Z","duration":"PT20M","url":"https://api.daily.dev/r/9lqth6GSc","embedUrl":"https://www.youtube.com/embed/lM7zWJRrRtg"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"ArjanCodes","item":"https://daily.dev/sources/arjancodes"},{"@type":"ListItem","position":3,"name":"Your Data Structure Is Too Flexible"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/your-data-structure-is-too-flexible-9lqth6gsc#faq","mainEntity":[{"@type":"Question","name":"When should I use a dictionary versus a dataclass for domain data in Python?","acceptedAnswer":{"@type":"Answer","text":"Dictionaries and keyword arguments work well at the edges of a system, such as JSON payloads, config files, API inputs, or framework hooks, where structure is inherently flexible. Inside domain or business logic, data should be modeled with strict types like frozen dataclasses, enums, and value objects so invalid values are rejected rather than silently flowing through the system. Developers deciding where to draw the line between flexible and strict data modeling can find real-world refactors like this on daily.dev."}},{"@type":"Question","name":"How do I validate that a money amount is never negative in a Python dataclass?","acceptedAnswer":{"@type":"Answer","text":"Define a frozen dataclass called Money wrapping a Decimal amount, then add a __post_init__ method that checks the amount is greater than or equal to zero and raises a ValueError otherwise. This turns money into a value object with built-in validation, and behavior like applying a percentage discount can be added as a method that returns a new Money instance. Engineers building validation-heavy domain models can track patterns like this value object approach on daily.dev."}},{"@type":"Question","name":"Why use Pydantic instead of plain dataclasses for API input validation in a domain-driven Python app?","acceptedAnswer":{"@type":"Answer","text":"Pydantic validates raw API input, such as enforcing that price cannot be negative, and can convert that validated input directly into strict domain objects via a to_domain method. This keeps flexible, unvalidated data at the API boundary while ensuring only strict, validated domain objects like BookingRequest reach the core business logic. Teams choosing between Pydantic and plain dataclasses for domain boundaries can follow comparisons like this on daily.dev."}}]}
```

