Connascence in Python: the 9 types of coupling explained

Connascence in Python: the 9 types of coupling explained

Coupling is often treated as a vague notion: “it’s too coupled” says nothing about what to actually change. Connascence provides a precise vocabulary to name the different forms of coupling, compare them, and decide which ones to reduce first. The concept is documented in detail at connascence.io. Three axes to evaluate connascence Every instance of connascence can be analyzed along three axes: Strength: the stronger a connascence, the harder it is to detect and refactor. Degree: an entity coupled to hundreds of others is more problematic than one coupled to two. Locality: two components that are close together (same class, same module) can tolerate stronger forms. At a distance, those same forms become dangerous. The 9 types of connascence Connascence of Name (CoN) Multiple components agree on the name of an entity. This is the weakest and most unavoidable form. ...

May 11, 2026 · 4 min · Anthony
Optimizing Django ORM Queries with defer(), only() and Prefetch()

Optimizing Django ORM Queries with defer(), only() and Prefetch()

By default, Django loads every field of a model on every query. On a list view showing 50 posts, that means fetching the full content, excerpt, metadata, and translation fields 50 times, even when only the title and date are displayed. Four QuerySet methods let you control exactly what gets loaded: defer(), only(), values_list(), and Prefetch(). The result: 2 SQL queries instead of N+2, with only the necessary columns. Django defer(): Exclude Heavy Fields from the QuerySet Django defer() tells the ORM to exclude specific fields from the initial query. Excluded fields remain accessible on the instance, but each access triggers an additional query. ...

May 8, 2026 · 6 min · Anthony
Django squashmigrations: cleaning up your migration history

Django squashmigrations: cleaning up your migration history

After a few months of development, it’s not unusual to end up with 30, 50, or even 100 migration files on a Django application. Every test run that starts from a clean database replays them all. Every deployment to a new environment does too. squashmigrations lets you merge several migrations into one, without losing compatibility with environments that have already applied earlier migrations. The command and what it generates The syntax takes a range of migrations: ...

May 7, 2026 · 5 min · Anthony
Django select_for_update(): row-level locking for concurrent transactions

Django select_for_update(): row-level locking for concurrent transactions

Two concurrent requests read a product’s stock, both see one unit remaining, and both confirm the order. Stock drops to -1. This kind of race condition is nearly impossible to reproduce in development and devastating in production. select_for_update() is Django’s answer: acquire a SQL lock at read time so no other transaction can modify the row before the current operation finishes. What select_for_update() does in SQL select_for_update() generates a SELECT ... FOR UPDATE. The lock is acquired as soon as the queryset is evaluated and held until the end of the transaction.atomic() block. Any other transaction that tries to acquire a lock on the same rows is blocked until the lock is released. ...

May 6, 2026 · 4 min · Anthony
Python __slots__: cut instance memory by 40–60% without changing your logic

Python __slots__: cut instance memory by 40–60% without changing your logic

By default, Python allocates a __dict__ for every instance of a class. Flexible, yes. Cheap, no. When you hold thousands or millions of objects in memory at once, that dictionary overhead adds up fast. __slots__ removes it and replaces per-instance storage with compact internal descriptors. Typical result: 40 to 60 percent less memory per instance. What Python does without slots Without any declaration, each instance carries its own __dict__: class Point: def __init__(self, x: float, y: float) -> None: self.x = x self.y = y p = Point(1.0, 2.0) print(p.__dict__) # {'x': 1.0, 'y': 2.0} This dictionary allows adding attributes at runtime: ...

May 6, 2026 · 4 min · Anthony
Renaming Django ORM fields with F() in values()

Renaming Django ORM fields with F() in values()

When exposing data from a Django model to an API or serializer, the model’s field names don’t always match what you want to return. The usual approach: fetch instances, then rename in Python. There’s a better option: let the database do the work using F() inside values(). The problem: model field names dictate output class Task(models.Model): name = models.CharField(...) created_at = models.DateTimeField(...) If you want to return task_name instead of name, the typical approach is to fetch the data and rename in Python, either with a dict comprehension or inside the serializer. Either way, the transformation happens after the fact, in memory. ...

May 5, 2026 · 2 min · Anthony
HATEOAS: Your REST API Might Just Be CRUD

HATEOAS: Your REST API Might Just Be CRUD

Teams often claim “we have a REST API in place.” But when you look at the actual JSON responses, there are no links anywhere. Just raw data. That’s not REST, it’s CRUD exposed over HTTP. The difference comes down to one principle most developers overlook: HATEOAS. What Is HATEOAS in a REST API? HATEOAS stands for Hypermedia As The Engine Of Application State. It is one of the fundamental constraints of REST, defined by Roy Fielding in his 2000 dissertation, the same paper that coined the term REST itself. ...

May 4, 2026 · 4 min · Anthony
Django Window Functions vs GROUP BY: Chainable QuerySets

Django Window Functions vs GROUP BY: Chainable QuerySets

Django ORM gives you two ways to add a computed value across a set of rows: annotate() with a classic aggregation (Max, Count, Sum…) or annotate() with a Window function. On the surface they look similar. In practice, they behave in fundamentally different ways — and picking the wrong one can break your entire filtering chain. GROUP BY with annotate(): rows that collapse When you combine values() and annotate() with an aggregation, Django generates a GROUP BY in SQL. The result: rows get merged, and you end up with one row per group. ...

May 4, 2026 · 4 min · Anthony
Django in_bulk(): why it beats filter() for bulk lookups

Django in_bulk(): why it beats filter() for bulk lookups

When you have a list of identifiers and want to retrieve the corresponding instances, the usual reflex in Django is filter(pk__in=[...]). It works — one SQL query. But in_bulk() is an often-overlooked ORM optimization: it returns a dictionary {id: instance} instead of a QuerySet, which fundamentally changes how you access results. Where filter() forces an O(n) traversal to find an object by ID, in_bulk() gives direct O(1) access. in_bulk() signature and behavior QuerySet.in_bulk(id_list=(), *, field_name='pk') id_list: list of identifiers to retrieve. If omitted (called without arguments), returns all objects in the table. field_name: field used as the dictionary key. Must have unique=True, otherwise Django raises a ValueError. The generated SQL is a simple WHERE pk IN (...) clause — one query regardless of list size. ...

May 4, 2026 · 4 min · Anthony
AI doesn't replace learning to code

AI doesn't replace learning to code

We keep hearing the same promise lately: “No need to know how to code anymore — AI handles it.” And honestly, it’s tempting. You open an agent, describe what you want, and within seconds, code appears. Magic. Except not really. Agentic development — but for whom? AI-assisted development is a genuine revolution. I’m not going to pretend otherwise. For a senior or intermediate developer who has already wrestled with complex problems, debugged twisted algorithms, and shipped systems to production, productivity reaches unprecedented heights. You delegate repetitive tasks, prototype in hours what used to take days, and stay in your high-value zone: architecture, critical decisions, validation. ...

May 4, 2026 · 4 min · Anthony

Newsletter

Get new articles delivered straight to your inbox.

No spam. Unsubscribe in one click.