What Happens When You Type a URL and Press Enter
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →Clean code isn't about rules from a book. It's about the next person reading your code, who is often you. Practical habits for naming, functions, comments and structure that pay off every week.
Code is read far more often than it's written. Every bug fix, new feature and code review starts with someone trying to understand what's already there. "Clean code" just means code that makes that understanding fast and safe.
These habits aren't dogma. They're the ones that consistently make codebases easier to live with.
A good name removes the need for a comment.
// Unclear
const d = users.filter(u => u.s === 1 && u.l > t)
// Clear
const activeRecentUsers = users.filter(
user => user.status === STATUS_ACTIVE && user.lastLoginAt > cutoffDate
)
Guidelines:
invoiceTotal beats total, which beats t.isPaid, hasAccess, canEdit.calculateTax, sendWelcomeEmail, parseDate.data, info, manager, handler, helper, utils2.If you need "and" to describe what a function does, it probably does too much. validateAndSaveAndNotifyUser wants to be three functions.
Small functions are easier to name, test and reuse. But don't go to extremes: fifty three-line functions that each call the next can be harder to follow than one clear 30-line function. Aim for "one level of abstraction," not a line count.
// Deeply nested
function getDiscount(user) {
if (user) {
if (user.isMember) {
if (user.orders > 10) {
return 0.15
} else {
return 0.05
}
}
}
return 0
}
// Guard clauses
function getDiscount(user) {
if (!user?.isMember) return 0
if (user.orders > 10) return 0.15
return 0.05
}
Handle the edge cases first and get them out of the way. The main logic then reads top to bottom.
if (password.length < 12) ... // why 12?
if (password.length < MIN_PASSWORD_LENGTH) ...
The same goes for status codes, time durations (30 * 24 * 60 * 60 * 1000 deserves a named constant) and repeated strings.
// Bad: repeats the code
// increment retries
retries++
// Good: explains a non-obvious decision
// The payment provider rate-limits refunds to 1 per second per account,
// so we space retries out instead of sending them in parallel.
If you need a comment to explain what code does, try renaming or restructuring first. Save comments for intent, trade-offs, workarounds and links to the ticket or documentation that explains them.
Code that changes together should live together. Grouping by feature rather than by technical layer keeps related logic close. (Project structure that scales.)
catch blocks.try/catch everywhere.(Async error-handling mistakes.)
// Clever
const r = a.reduce((p, c) => ({ ...p, [c.k]: [...(p[c.k] || []), c] }), {})
// Clear
const groupedByKey = {}
for (const item of items) {
groupedByKey[item.key] ??= []
groupedByKey[item.key].push(item)
}
If a teammate needs five minutes to decode a one-liner, it's not saving anyone time. Readability wins over brevity.
Commented-out blocks, unused functions and stale feature flags create noise and doubt. ("Is this still used? Is it safe to change?") Git remembers everything, so delete freely.
Arguing about semicolons and indentation in code review is a waste of everyone's time. Use a formatter (Prettier, Black, gofmt and similar) and a linter, run them automatically on save or commit, and never discuss formatting again.
The "boy scout rule": when you touch a file, improve one small thing. Rename a confusing variable, extract a messy block, add a missing test. Over months, this quietly transforms a codebase without ever needing a big rewrite. (Working with legacy code.)
What counts as "clean" varies a bit between teams and languages. Agree on conventions, write them down briefly, automate what you can and reinforce the rest through kind, consistent code reviews.
Code that's easy to read, understand and change safely: clear names, small focused functions, straightforward control flow, deliberate error handling and consistent formatting.
Yes, for the "why": intent, trade-offs and non-obvious decisions. If you need a comment to explain what code does, try clearer names or structure first.
Focus on descriptive names, early returns instead of deep nesting, small functions and an automatic formatter. Then read your code a day later and fix whatever confused you.
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →There are dozens of HTTP status codes, but about fifteen cover nearly everything. What each one means, when to return it, and the mix-ups (401 vs 403, 301 vs 302) that confuse everyone.
Read →A, AAAA, CNAME, MX, TXT and NS records in plain English, why DNS changes seem slow, and the troubleshooting commands that tell you what is really going on.
Read →