Technical
Python Patterns That Earned Their Place After 11 Months of Daily Use
I wrote Python every day for eleven months. Through that time the patterns that stuck were not the clever ones. They were the ones that stayed readable under modification.
Pattern 1: Functions, Not Classes, Until Proven Otherwise
I default to functions. A class shows up when I have state that genuinely persists across calls or polymorphism that genuinely matters. 90 percent of my code is functions. Testing is easier, reading is easier, refactoring is easier.
# default
def send_newsletter(issue_id, recipients): ...
# only when needed
class NewsletterSender:
def __init__(self, ses_client, db): ...Pattern 2: Pydantic at the Boundary, Dataclasses Inside
Pydantic for anything that crosses a trust boundary: HTTP input, config files, webhook payloads. Dataclasses for internal structures where validation is my problem. Mixing the two was a bad early habit.
Pattern 3: Pure Functions Where Possible
A pure function takes inputs, returns outputs, touches nothing else. 80 percent of my code base is now pure. The other 20 percent is clearly marked as side-effecting. This split makes every debugging session shorter.
Pattern 4: Explicit Over Implicit Error Handling
I returned result tuples more and raised exceptions less this year. Exceptions are for genuinely exceptional conditions. Expected failures travel in the return type where the caller is forced to handle them.
def fetch_user(id) -> tuple[User | None, Error | None]: ...Pattern 5: urllib for Scripts, httpx for Services
Scripts that run once or twice get urllib, because no dependencies means no environment setup. Services get httpx for ergonomics and async support. The split prevents dependency sprawl in small utilities.
Pattern 6: Type Hints Even on Scripts
I used to skip type hints on quick scripts. I stopped. Type hints on scripts caught more bugs than type hints on services, because scripts have less test coverage.
Pattern 7: One File Until Three Files
I start every Python project in one file. I split when the file exceeds 500 lines or when three distinct concerns emerge. Premature file splitting produces import spaghetti.
What I Stopped Doing
Metaclasses, decorators I wrote myself, abstract base classes, excessive typing generics. Clever Python rarely survives a second read. Boring Python survives every read.
Reading
Python design patterns by Brandon Rhodes aligns with most of what I landed on. Read it before reinventing.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read