Writing readable code
Code is read far more often than it is written. Clear names, small functions, and consistent style make programs easier to understand, fix, and extend.
Why readability matters
Most of a program's life is spent being maintained: fixed, extended, and read by other people, including your future self. Readable code reduces bugs, speeds up onboarding, and makes change safer. A widely quoted idea from Martin Fowler is that any fool can write code a computer understands, but good programmers write code humans understand.
Meaningful names
Names should reveal intent: days_since_last_login beats d, and calculate_tax beats do_stuff. Use nouns for variables and classes, verbs for functions, and consistent vocabulary, so you do not mix fetch, get, and retrieve for the same idea. Avoid misleading names, such as account_list for something that is not a list.
Small, focused functions
A function should do one thing, at one level of detail. Long functions that validate input, query a database, compute results, and format output are hard to test and reason about. Extracting well-named helper functions turns the main function into a readable summary of steps.
Comments
Good comments explain why: the reason for a surprising choice, a link to a bug report, or a warning. They should not restate what the code obviously does, such as # add one to i. Comments that drift out of date become actively misleading, so clear code that needs fewer comments is better still. Docstrings document public functions' purpose, parameters, and results.
Consistent style
Teams agree on style: indentation, naming conventions, line length, and layout. Python's PEP 8 and Google's style guides for various languages are common references. Automatic formatters, such as Black for Python and Prettier for JavaScript, apply style mechanically, ending arguments and keeping reviews focused on substance.
Linters and static analysis
Linters, such as Pylint, Ruff, ESLint, and Checkstyle, scan code for likely bugs and style issues without running it: unused variables, unreachable code, suspicious comparisons. Type checkers, such as mypy for Python and TypeScript's compiler, catch type mistakes. Running them automatically catches problems early and cheaply.
Avoiding magic numbers and duplication
Unexplained literal values, such as if score > 47, are magic numbers; naming them, as in PASS_MARK = 47, documents meaning and allows one-place changes. Duplicated logic means fixing bugs in several places, and missing one. Following DRY, shared logic belongs in one function, though small coincidental similarities need not be merged.
Worked example
Before: def f(l): t = 0; for x in l: if x[1] > 18: t += x[2]; return t. After: ADULT_AGE = 18; def total_adult_spending(customers): return sum(c.spending for c in customers if c.age > ADULT_AGE). The behaviour is the same, but the name says what it computes, the constant explains 18, and attribute names replace mysterious indexes.
Key takeaways
Code is read more than written, so optimise for readers. Use intention-revealing, consistent names. Keep functions small and focused on one task. Comments should explain why, not what; keep them accurate. Agree on a style and use formatters such as Black or Prettier. Linters and type checkers find problems without running code. Replace magic numbers with named constants and remove duplicated logic.
Flashcard
How easily people understand code
Check your understanding
Which comment adds the most value?
