Why Reading Your Own Code Is Hard: The Missing Reason
Rewritten: . Rewritten with AI assistance. Examples and tool references follow the original publication period.

Read this function without any surrounding context:
def ready(i, d):
return (
i["state"] == "open"
and i["paid_at"] is None
and (d - i["due_date"]).days >= 3
)
You can work out its mechanics. It checks two fields and a date difference. But what is ready? Why three days? Does “open” already imply unpaid? Is the extra check redundant or essential?
Knowing the language gets you through the expression. It does not recover the decision behind it.
First, improve the names without changing the behavior
def should_send_payment_reminder(invoice, today):
is_open = invoice["state"] == "open"
has_no_recorded_payment = invoice["paid_at"] is None
days_past_due = (today - invoice["due_date"]).days
return is_open and has_no_recorded_payment and days_past_due >= 3
Assume a valid invoice contains these keys and both date values are Python date objects. Within that input contract, the second function expresses the same condition as the first. This is a readability refactor, not a change to the reminder policy.
The names now tell us what decision the function makes. They still do not establish why it makes that decision.
Supply the missing policy
For this invented billing example, suppose the policy is: wait three calendar days after the due date before sending a reminder, because an external payment feed can arrive late. An open invoice can temporarily have a recorded payment while another process updates its state.
Now the apparently redundant payment check has a purpose. So does the number three. A concise comment can preserve that context:
# Wait three calendar days for the external payment feed to catch up.
# A payment can be recorded before the invoice state is updated.
This is hypothetical business context, not a claim about a real payment system. In an actual repository, verify the policy with its owner or recorded decision. Inventing a plausible reason for unfamiliar code makes it harder to discover the real one.
The boundary deserves a test:
from datetime import date
invoice = {
"state": "open",
"paid_at": None,
"due_date": date(2025, 6, 28),
}
assert not should_send_payment_reminder(invoice, date(2025, 6, 30))
assert should_send_payment_reminder(invoice, date(2025, 7, 1))
paid_invoice = {**invoice, "paid_at": date(2025, 6, 30)}
assert not should_send_payment_reminder(paid_invoice, date(2025, 7, 1))
The test records what the boundary means. The comment records why it exists. Neither replaces the other.
More pieces can mean more reconstruction
It is tempting to turn every expression into a helper. Sometimes that reveals a useful domain concept. Sometimes it forces the reader to visit five files to understand a condition that fits comfortably on one screen.
Choose boundaries that let the reader hold a meaningful unit of behavior together. A tiny function with a vague name can be harder to understand than a longer function with a clear local sequence.
Similarly, claims that working memory has one fixed capacity should not become universal line-count rules. Research such as Cowan’s discussion of short-term memory concerns experimental conditions, attention, and meaningful chunks; it does not prescribe the maximum number of variables in a function.
Your own old code becomes unfamiliar because the surrounding context fades. Preserve the parts that cannot be recovered reliably from syntax: the rule, the exception, the boundary case, and the reason. Future you can reread the implementation. Reconstructing an unrecorded decision is much harder.