Skip to main content

Links from my inbox 2026-08-14

Β· 65 min read
1. Teach Yourself Programming in Ten Years 001 2. No Silver Bullet: Essence and Accidents of Software Engineering 002 3. Programming as Theory Building 003 4. The Law of Leaky Abstractions 004 5. Things You Should Never Do, Part I 0056. Out of the Tar Pit 006 7. You and Your Research 007 8. The Rise of 'Worse is Better' 008 9. Reflections on Trusting Trust 009 10. How Complex Systems Fail 01011. Choose Boring Technology 011 12. The Grug Brained Developer 012 13. The Wrong Abstraction 013 14. Parse, Don't Validate 014 15. End-to-End Arguments in System Design 01516. A Note on Distributed Computing 016 17. On the Criteria To Be Used in Decomposing Systems into Modules 017 18. The Humble Programmer 018 19. Go To Statement Considered Harmful 019 20. Why Functional Programming Matters 02021. Big Ball of Mud 021 22. CAP Twelve Years Later: How the 'Rules' Have Changed 022 23. Life Beyond Distributed Transactions: An Apostate's Opinion 023 24. Building on Quicksand 024 25. Immutability Changes Everything 02526. The Log: What every software engineer should know about real-time data's unifying abstraction 026 27. Scalability! But at what COST? 027 28. The Tail at Scale 028 29. Ironies of Automation 029 30. An Investigation of the Therac-25 Accidents 03031. They Write the Right Stuff 031 32. MonolithFirst 032 33. Is High Quality Software Worth the Cost? 033 34. Mocks Aren't Stubs 034 35. Microservices 03536. Test Pyramid 036 37. Is TDD dead? 037 38. The Joel Test: 12 Steps to Better Code 038 39. Fire and Motion 039 40. Back to Basics 04041. The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) 041 42. What Color is Your Function? 042 43. C Is Not a Low-level Language 043 44. What Every Programmer Should Know About Memory 044 45. The Lost Art of C Structure Packing 04546. What Every Computer Scientist Should Know About Floating-Point Arithmetic 046 47. Execution in the Kingdom of Nouns 047 48. Falling Into The Pit of Success 048 49. Semantic Compression 049 50. Learnable Programming 05051. Magic Ink: Information Software and the Graphical Interface 051 52. Responsive Web Design 052 53. A Dao of Web Design 053 54. Cool URIs don't change 054 55. The Web's Grain 05556. The Website Obesity Crisis 056 57. Web Design: The First 100 Years 057 58. The Internet With a Human Face 058 59. The Software Disenchantment 059 60. Falsehoods Programmers Believe About Names 06061. Falsehoods programmers believe about time 061 62. Programming Sucks 062 63. Local-first software: You own your data, in spite of the cloud 063 64. Hyrum's Law 064 65. Cargo Cult Software Engineering 06566. Software Quality at Top Speed 066 67. On Being a Senior Engineer 067 68. Being Glue 068 69. Staff Engineer: Archetypes 069 70. The Engineer/Manager Pendulum 07071. Maker's Schedule, Manager's Schedule 071 72. Don't Call Yourself A Programmer, And Other Career Advice 072 73. Salary Negotiation: Make More Money, Be More Valued 073 74. Beating the Averages 074 75. Hackers and Painters 07576. Taste for Makers 076 77. How to Get Startup Ideas 077 78. Do Things that Don't Scale 078 79. Startup = Growth 079 80. Schlep Blindness 08081. Keep Your Identity Small 081 82. The Top Idea in Your Mind 082 83. How to Do Great Work 083 84. Good and Bad Procrastination 084 85. Great Hackers 08586. How to Work Hard 086 87. How to Be Polite 087 88. Ten Lessons I Wish I Had Been Taught 088 89. Solitude and Leadership 089 90. The Bitter Lesson 09091. Why Software Is Eating the World 091 92. A little bit of plain JavaScript can do a lot 092 93. Choices 093 94. Application compatibility layers are there for the customer, not for the program 094 95. John Carmack on Inlined Code 09596. Rob Pike's Rules of Programming 096 97. Design Principles Behind Smalltalk 097 98. The Error Model 098 99. Structured Programming with go to Statements 099 100. The Early History of Smalltalk 100

Article notes​

001 β€” Teach Yourself Programming in Ten Years β€” Peter Norvig​

You will not become a programmer by absorbing syntax from a crash course; the craft develops through years of deliberate practice. Build substantial programs, study other people's code, work with programmers both stronger and weaker than you, and learn languages from several paradigms so that each changes how you think. Keep stretching just beyond your current ability, seek feedback, and understand the machine beneath your abstractions.

002 β€” No Silver Bullet: Essence and Accidents of Software Engineering β€” Frederick P. Brooks Jr.​

Separate the accidental difficulties of tools and notation from the essential difficulty of constructing precise conceptual systems. Better languages, environments, and hardware can remove friction, but no single invention can erase the complexity, conformity, changeability, and invisibility inherent in software. Improve by buying rather than rebuilding, prototyping requirements, growing systems incrementally, and cultivating unusually strong designers.

003 β€” Programming as Theory Building β€” Peter Naur​

Regard a program as the visible residue of a theory held by the people who built it: an understanding of how the problem, its constraints, and the chosen solution fit together. Source code and documentation alone cannot fully preserve that theory, which is why maintenance becomes brittle when no one who understands the original reasoning remains. Preserve software by transferring understanding through close collaboration, explanation, and continued participationβ€”not merely by preserving artifacts.

004 β€” The Law of Leaky Abstractions β€” Joel Spolsky​

Abstractions make routine work easier, but their underlying machinery still surfaces through failures, performance limits, and unusual cases. A network API may resemble a local call until latency or disconnection matters; a database may hide indexes until a query becomes slow. Learn at least one layer below the interface you use, because abstractions save labor without eliminating the knowledge needed to diagnose reality.

005 β€” Things You Should Never Do, Part I β€” Joel Spolsky​

Resist replacing a mature codebase merely because the existing structure feels ugly. Every awkward line may encode a bug fix, performance lesson, or edge case accumulated through real use, and a rewrite silently discards that knowledge while freezing visible progress. Improve the system incrementally, preserving behavior as you reshape it, unless you can justify the exceptional cost and risk of starting over.

006 β€” Out of the Tar Pit β€” Ben Moseley and Peter Marks​

Attack complexity by reducing mutable state and the control logic that determines when state changes. Separate essential domain data and rules from accidental mechanisms, express derived values declaratively, and keep the remaining state visible and constrained. A functional core paired with a relational model makes behavior easier to understand because fewer facts depend on execution history.

007 β€” You and Your Research β€” Richard Hamming​

Your choice of problem determines much of what your work can become, so look for questions that are both consequential and open to attack. Develop courage, tolerate ambiguity, protect sustained thinking time, and communicate results clearly enough that others can use them. Luck matters, but preparation, working conditions, persistence, and the choice of problem determine how often luck can help you.

008 β€” The Rise of Worse is Better β€” Richard P. Gabriel​

Favor designs that are simple to implement, ship, and port when that simplicity lets a system spread and improve through use. A theoretically cleaner design can lose to one that places fewer demands on implementers, even when the latter compromises interface consistency or completeness. Judge elegance alongside adoption dynamics: a small, viable system can acquire quality, while an immaculate system that never propagates cannot.

009 β€” Reflections on Trusting Trust β€” Ken Thompson​

Follow the chain of trust below source code and notice that every compiler, assembler, loader, and piece of microcode can influence the program you finally run. A compiler can learn to insert a backdoor into both a login program and future versions of itself, leaving no trace in the inspected source. Treat software assurance as a supply-chain and provenance problem, not something source review alone can settle.

010 β€” How Complex Systems Fail β€” Richard I. Cook​

A complex-system failure is rarely the work of one careless operator or one isolated root cause. Reconstruct the path through latent weaknesses, defenses, adaptations, and production pressures from what practitioners could see before the outcome was known. Strengthen the system's capacity to adapt and recover, remembering that people continuously create safety while operating an already imperfect system.

011 β€” Choose Boring Technology β€” Dan McKinley​

Spend novelty deliberately: every unfamiliar database, language, or framework adds operational unknowns and consumes a team's finite ability to learn. Prefer mature components whose limitations and failure modes are already understood, then introduce new technology only when it solves a problem the existing stack genuinely cannot. Count the interactions among choices as part of their cost, because complexity grows faster than the component list.

012 β€” The Grug Brained Developer β€” Carson Gross​

Protect your limited working memory from complexity, the predator that grows quietly as abstractions, distributed state, and clever machinery accumulate. Start with straightforward code, introduce abstractions only when repeated evidence earns them, and keep boundaries narrow enough to understand locally. Use tests, types, tools, and factoring as aids to comprehension rather than ceremonies that create more concepts than they remove.

013 β€” The Wrong Abstraction β€” Sandi Metz​

A shared abstraction stops helping when it must serve several cases that change for different reasons. Restore the duplicated implementations, make each correct in isolation, and let the true common structure reveal itself over time. Duplication is cheaper than a false abstraction because it keeps future changes local and leaves you free to discover a better boundary.

014 β€” Parse, Don’t Validate β€” Alexis King​

Convert untrusted input into a type that carries the facts you have established instead of checking a weak value and then forgetting the result. Parsing moves failure to the system boundary and lets downstream functions accept only valid states, replacing defensive rechecks with stronger interfaces. Choose data structures that preserve evidenceβ€”such as a non-empty list rather than a list separately asserted to be non-emptyβ€”so correctness follows from construction.

015 β€” End-to-End Arguments in System Design β€” Jerome H. Saltzer, David P. Reed, and David D. Clark​

Place a correctness function at the endpoints when only the application can know whether that function has truly succeeded. Lower layers may improve reliability or performance, but checks such as complete file transfer still require end-to-end verification because intermediate guarantees cannot cover every failure. Keep the shared substrate simple, and add lower-level mechanisms only when their broad performance benefit justifies the cost.

016 β€” A Note on Distributed Computing β€” Jim Waldo, Geoff Wyant, Ann Wollrath, and Sam Kendall​

A remote interaction is not an ordinary local object call, however similar the interfaces appear. Latency, partial failure, concurrency, memory access, and object lifetime make distribution a semantic boundary that applications must confront explicitly. Design interfaces around coarse-grained communication and failure-aware behavior, because pretending location is transparent produces systems that are fragile in precisely the cases that matter.

017 β€” On the Criteria To Be Used in Decomposing Systems into Modules β€” David L. Parnas​

Divide a system around design decisions likely to change, hiding each decision behind a stable interface. A pipeline-shaped decomposition that mirrors processing steps may look orderly yet force many modules to know the same representation details. Encapsulate secrets such as storage layout and algorithm choice so teams can work independently, changes remain localized, and readers can understand one module without reconstructing the whole system.

018 β€” The Humble Programmer β€” Edsger W. Dijkstra​

Accept that software can exceed the unaided mind's capacity long before it exceeds the computer's. Control that gap through languages, proofs, and structures that let you reason about behavior in compact, composable units instead of relying on testing and cleverness alone. Approach programming with humility: simplify the intellectual task until correctness becomes tractable.

019 β€” Go To Statement Considered Harmful β€” Edsger W. Dijkstra​

A computation is easiest to reason about when its progress remains aligned with the structure of its text. Unrestricted jumps create arbitrary execution coordinates, forcing a reader to reconstruct history before understanding the current state. Prefer control constructs with constrained entry and exit points so program behavior remains accessible to reasoning and proof.

020 β€” Why Functional Programming Matters β€” John Hughes​

Treat higher-order functions and lazy evaluation as mechanisms for modularity, not ornamental language features. Higher-order functions separate reusable patterns of computation, while laziness lets producers and consumers be composed without committing to an execution schedule or intermediate structure. Build programs from independently useful pieces whose combination creates new behavior without reopening their implementations.

021 β€” Big Ball of Mud β€” Brian Foote and Joseph Yoder​

Recognize the economic and organizational forces that turn systems into sprawling structures of expedient patches, blurred boundaries, and shared state. Such systems persist because local fixes meet immediate needs, architectural knowledge is scarce, and wholesale reconstruction is risky. Preserve habitable regions through continuous refactoring, clear boundaries, and reconstruction in small areas, while treating decay as a pressure to manage rather than a moral failure.

022 β€” CAP Twelve Years Later: How the β€œRules” Have Changed β€” Eric Brewer​

CAP becomes more useful when you replace 'pick two' with decisions tied to particular operations, data, and moments in a partition. Consistency and availability are spectra, and a system may detect a partition, limit the affected work, trade one property temporarily, and recover explicitly afterward. Design the normal and partitioned modes together, including how state converges once communication returns.

023 β€” Life Beyond Distributed Transactions: An Apostate’s Opinion β€” Pat Helland​

Build large distributed applications around independently transactional entities that exchange messages rather than around one global transaction. Once data crosses an entity boundary, accept uncertainty, duplicate delivery, delayed knowledge, and the need for idempotent or compensating behavior. Record durable histories and make business rules tolerate tentative outcomes, because coordination at scale resembles agreements among organizations more than updates inside one database.

024 β€” Building on Quicksand β€” Pat Helland and David Campbell​

Stop treating globally shared, synchronously updated state as the natural foundation of scalable systems. Data observed across distance is inevitably delayed and may be contradictory, so build on stable identifiers, immutable versions, local transactions, and explicit rules for interpreting incomplete knowledge. Make uncertainty part of the data model rather than hiding it behind an interface that promises a single instantaneous truth.

025 β€” Immutability Changes Everything β€” Pat Helland​

Cheap storage and computation make immutable facts a practical foundation for systems whose current views are derived from history. Append-only logs, snapshots, versioned datasets, copy-on-write structures, and idempotent computation reduce coordination and make retries, replication, and parallel processing safer. Separate semantic immutability from physical representation so you can reorganize data for efficient reads without changing what it means.

026 β€” The Log: What Every Software Engineer Should Know About Real-Time Data’s Unifying Abstraction β€” Jay Kreps​

Model a stream of changes as an ordered, append-only log, then let consumers maintain their own materialized views by replaying it. The same abstraction explains database commit logs, replication, change capture, messaging, and stream processing, turning data integration into controlled propagation of state transitions. Preserve ordering and position so systems can recover, bootstrap new consumers, and reason about the relationship between historical facts and current state.

027 β€” Scalability! But at What COST? β€” Frank McSherry, Michael Isard, and Derek G. Murray​

Demand a competent single-threaded baseline before celebrating a system's scale-out graph. Compute the configuration that first beats that baselineβ€”the COST, or configuration that outperforms a single threadβ€”because parallel frameworks can spend enormous resources recovering overhead they introduced themselves. Optimize useful work and elapsed time, not merely the ability to occupy more machines.

028 β€” The Tail at Scale β€” Jeffrey Dean and Luiz AndrΓ© Barroso​

When a request fans out across many components, even a rare slow response becomes likely to delay the whole result. Reduce variability within services, then use cross-request techniques such as hedged requests, backup work, and latency-aware partitioning to keep outliers from dominating user experience. Apply redundancy selectively so tail improvement does not create uncontrolled extra load.

029 β€” Ironies of Automation β€” Lisanne Bainbridge​

Expect automation to remove routine practice while leaving the human responsible for rare situations requiring the deepest skill. If operators only monitor a reliable system, their attention fades and their ability to diagnose unfamiliar failures decays precisely when intervention becomes necessary. Design automation to keep people informed, practiced, and able to form an accurate model of the processβ€”not merely available as a last-resort component.

030 β€” An Investigation of the Therac-25 Accidents β€” Nancy G. Leveson and Clark S. Turner​

Read the Therac-25 accidents as a systems failure spanning unsafe software, reused assumptions, weak interfaces, inadequate testing, poor incident communication, and misplaced confidence in software reliability. Do not infer safety from the absence of hardware interlocks or from the rarity of reproduced failures; specify hazards and enforce independent defenses. Treat operators' reports as evidence and share incident knowledge promptly, because safety depends on the organization surrounding the code as much as on the code itself.

031 β€” They Write the Right Stuff β€” Charles Fishman​

Build reliability by making every change explicit, reviewed, and traceable. The Shuttle team controlled requirements, kept detailed records, used independent verification, and preferred proven code to unnecessary novelty. Measure the process and study every defect so dependable behavior follows from repeatable engineering rather than individual heroics.

032 β€” Monolith First β€” Martin Fowler​

A well-structured monolith gives a new domain room to reveal its boundaries before distribution makes those boundaries expensive to change. Microservices amplify the cost of a mistaken split through remote communication, deployment coordination, and data ownership, while in-process modules are easier to move as understanding develops. Extract services only after experience reveals stable boundaries and the operational benefits outweigh distribution's premium.

033 β€” Is High Quality Software Worth the Cost? β€” Martin Fowler​

Distinguish external quality, which users can observe, from internal quality, which determines how safely and quickly you can change the product. Cutting internal quality may appear faster briefly, but accumulated friction soon raises the cost of every feature and defect repair, reversing the apparent tradeoff. Keep the codebase healthy as an economic investment in future delivery speed, not as an aesthetic indulgence.

034 β€” Mocks Aren’t Stubs β€” Martin Fowler​

Distinguish state-based tests that inspect results from behavior-based tests that set expectations on collaborators; mocks are not merely convenient stubs. A classical style uses real collaborators when practical and substitutes only awkward dependencies, while a mockist style isolates each object and specifies its outgoing interactions. Choose deliberately, because the testing style pushes design toward different collaboration patterns, coupling, and refactoring behavior.

035 β€” Microservices β€” James Lewis and Martin Fowler​

Microservices are an organizational and operational architecture, not merely a collection of small processes. Build independently deployable services around business capabilities, give product teams responsibility for running them, and keep intelligence at the endpoints rather than in elaborate transport infrastructure. Accept the price explicitly: remote calls, distributed data, eventual consistency, and failure-aware automation demand capabilities that a monolith may not require.

036 β€” Test Pyramid β€” Martin Fowler​

Shape your automated test suite as a pyramid: keep a broad base of fast, focused unit tests, add a thinner service-level layer, and reserve relatively few end-to-end UI tests for behavior that genuinely crosses the whole system. A top-heavy suite runs slowly, fails ambiguously, and becomes expensive to maintain. Use the proportions as a heuristic rather than a quota, optimizing for rapid feedback and clear diagnosis.

037 β€” Is TDD Dead? β€” Martin Fowler, Kent Beck, and David Heinemeier Hansson​

Examine test-driven development as a collection of design and feedback practices rather than a ceremony that must be defended whole. Ask whether isolated tests, mocks, and a test-first rhythm improve your particular design, and notice when they instead couple tests to implementation or distort architecture. Keep the discipline of short feedback loops while remaining willing to change the technique when its costs exceed its signal.

038 β€” The Joel Test: 12 Steps to Better Code β€” Joel Spolsky​

Twelve concrete questions can expose whether a software team has the basic engineering infrastructure needed to work well. Check source control, one-step builds, daily builds, defect tracking, schedules, specifications, working conditions, tools, testing, usability, and hiring. The score is deliberately crude, but fixing the gaps it reveals removes recurring friction before you reach for elaborate process reforms.

039 β€” Fire and Motion β€” Joel Spolsky​

Preserve forward motion when the work feels uncertain, political, or dull: writing code, fixing defects, and shipping small improvements keeps a team’s initiative alive. Competitors and distractions can pin you down by consuming attention even when they do not produce anything better. Turn intimidating projects into the next concrete action and let consistent progress compound.

040 β€” Back to Basics β€” Joel Spolsky​

Learn what string operations and memory access cost beneath the conveniences of a high-level language. A seemingly innocent abstraction can conceal repeated scans or copies, turning straightforward code into an accidental quadratic algorithm. Reason from data representation and operation count first, then choose abstractions with a clear view of the work they perform.

041 β€” The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) β€” Joel Spolsky​

Text is not a bag of bytes whose meaning can be guessed later. Distinguish characters from code points and encoded byte sequences, understand what Unicode and UTF-8 each specify, and carry encoding metadata across every boundary. Decode input deliberately, work with a defined character model internally, and encode explicitly on output so text is not silently corrupted.

042 β€” What Color is Your Function? β€” Bob Nystrom​

Notice how a language’s async model can split otherwise similar functions into incompatible β€œcolors,” forcing the distinction through every caller in the stack. Colored functions are harder to compose because one kind cannot freely call the other, and the burden spreads across APIs rather than staying at the operation that waits. Prefer runtimes and abstractions that hide scheduling mechanics without hiding latency or failure.

043 β€” C Is Not a Low-level Language β€” David Chisnall​

Abandon the idea that C is portable assembly for contemporary processors. Its abstract machine omits capabilities modern hardware needs to expressβ€”parallelism, rich memory behavior, and provenance among themβ€”while aggressive compilers exploit undefined behavior in ways that break machine-level intuition. Choose a language and intermediate representation that can communicate your intended semantics to both the optimizer and the hardware.

044 β€” What Every Programmer Should Know About Memory β€” Ulrich Drepper​

Modern processors often spend more time waiting for data than computing on it, which makes the memory hierarchy part of your design. Understand caches, cache lines, associativity, prefetching, write behavior, NUMA placement, and contention well enough to predict when access patterns will stall. Measure with hardware-aware tools, organize data for locality, and reduce needless movement before tuning arithmetic.

045 β€” The Lost Art of C Structure Packing β€” Eric S. Raymond​

Read a C structure as a layout contract shaped by member sizes, alignment rules, and padding, not merely as a list of fields. Reordering members can sharply reduce memory consumption when millions of instances amplify a few wasted bytes. Verify the ABI and compiler rules you actually target, and use explicit packing only when its portability and access penalties are understood.

046 β€” What Every Computer Scientist Should Know About Floating-Point Arithmetic β€” David Goldberg​

Treat floating-point numbers as finite approximations governed by precise rounding rules, not as slightly unreliable real numbers. Learn to reason in relative error and ulps, recognize cancellation and exceptional values, and understand the guarantees supplied by IEEE arithmetic. Reformulate unstable calculations and specify rounding behavior when numerical reproducibility or correctness matters.

047 β€” Execution in the Kingdom of Nouns β€” Steve Yegge​

A simple action becomes difficult to follow when a design forces it through a ceremonial hierarchy of classes. Turning verbs into noun-heavy command objects, factories, and visitors scatters the operation across excessive structure. Give behavior first-class representation and introduce objects where identity, state, and substitution genuinely earn them.

048 β€” Falling Into The Pit of Success β€” Jeff Atwood​

Make the easiest path through an API the one that produces correct, secure, and maintainable behavior. Documentation and discipline cannot compensate for interfaces whose defaults invite misuse or whose dangerous operations look ordinary. Move invariants into the design so callers succeed by following the obvious route and must work deliberately to escape it.

049 β€” Semantic Compression β€” Casey Muratori​

Begin with direct code that expresses the cases you actually understand, even when that creates duplication. Watch repeated semantics emerge, then compress them into an abstraction that has a stable meaning rather than merely a similar textual shape. Delay generalization until the examples teach you the right boundary, because premature compression stores incorrect assumptions in a form that is harder to undo.

050 β€” Learnable Programming β€” Bret Victor​

A programming environment can teach by making the program's behavior visible while the learner constructs it. Show values, control flow, time, and relationships; connect code to its output immediately; and let the learner manipulate concrete examples before requiring symbolic prediction. Simplified syntax and motivational games are not substitutes for a medium that supports a correct mental model of computation.

051 β€” Magic Ink: Information Software and the Graphical Interface β€” Bret Victor​

Design information software first as a medium that helps a person understand and decide, not as a collection of controls. Infer context where possible, present relevant relationships clearly, and spend interaction only where the user must genuinely supply information or express intent. Treat graphic design as the organization of meaning, then add manipulation with the same care you would add complexity to a program.

052 β€” Responsive Web Design β€” Ethan Marcotte​

Let a web layout respond to its viewing context instead of assuming a fixed canvas. Combine fluid grids, flexible media, and media queries so proportions and hierarchy survive across widths without maintaining a separate design for every device. Start from relationships among elements, test where those relationships break, and introduce breakpoints around the content rather than around fashionable screen sizes.

053 β€” A Dao of Web Design β€” John Allsopp​

The web does not behave like a fixed printed page: readers bring different windows, fonts, devices, preferences, and constraints. Rigid pixel control turns that ordinary variability into failure. Specify enough structure to preserve meaning, then allow the browser and reader to negotiate the final presentation.

054 β€” Cool URIs don't change β€” Tim Berners-Lee​

Design a URI to outlive the server, framework, file format, and organizational chart that first produced it. Put durable conceptsβ€”not implementation detailsβ€”into public identifiers, and maintain redirects when infrastructure must change. Every broken address transfers your internal migration cost to readers, citations, indexes, and archives that cannot coordinate with you.

055 β€” The Web’s Grain β€” Frank Chimero​

Work with the web’s native grain: a fluid vertical flow of text, links, and containers that can adapt across contexts. Begin from the smallest coherent expression, let layout grow from the content, and use frameworks or visual polish only after the relationships are sound. The browser is not an inferior page-composition tool; its flexibility is the material you are designing with.

056 β€” The Website Obesity Crisis β€” Maciej Ceglowski​

Page weight and complexity are product decisions with human costs, not harmless implementation details that future bandwidth will erase. A simple document should not require megabytes of scripts, surveillance machinery, and fragile dependencies merely to place text on a screen. Set explicit performance budgets, remove work that does not serve the reader, and make the useful content arrive first.

057 β€” Web Design: The First 100 Years β€” Maciej Ceglowski​

Design for a mature, constrained web rather than an endlessly accelerating technological future. Hardware, bandwidth, attention, and social tolerance encounter limits, while supposedly obsolete protocols and interfaces persist because they are useful and widely embedded. Build accessible, durable, participatory systems, and ask what human purpose a novelty serves before making the world adapt to it.

058 β€” The Internet With a Human Face β€” Maciej Ceglowski​

Build online systems around human limits: people forget, change, make mistakes, and need private spaces that do not become permanent dossiers. Advertising-funded surveillance and centralized data collection turn ordinary behavior into durable institutional power while offering users little meaningful consent or recourse. Minimize retained data, preserve room for anonymity and forgetting, and make business incentives answer to the people living inside the system.

059 β€” Software Disenchantment β€” Nikita Prokopov​

Faster hardware has not prevented software from becoming slower, larger, and less reliable. Layers of dependencies, background work, and indifferent craftsmanship consume memory, battery, bandwidth, and human attention without proportionate value. Measure responsiveness from the user's machine, reduce the stack you ask them to carry, and treat efficiency as part of correctness.

060 β€” Falsehoods Programmers Believe About Names β€” Patrick McKenzie​

Model names as user-provided, culturally contingent data rather than as a universal first-name/last-name tuple. People may have one name, many names, changing names, punctuation, unfamiliar scripts, or forms that exceed your chosen length and ordering rules. Store what the domain truly requires, preserve the user’s representation, and avoid validation that encodes your local custom as a law of identity.

061 β€” Falsehoods Programmers Believe About Time β€” Noah Sussman​

Clocks jump, drift, disagree, repeat values, and obey political rules rather than tidy arithmetic. Durations, civil timestamps, time zones, and monotonic ordering are different concepts and should not share an accidental representation. Use monotonic clocks for elapsed time, carry zone context for human schedules, and test the discontinuities your ordinary day conceals.

062 β€” Programming Sucks β€” Peter Welch​

Accept that production software is assembled atop incomplete knowledge, mutable requirements, leaky abstractions, and systems no one fully understands. Small changes can awaken interactions far beyond their apparent scope, while success often means maintaining a fragile truce among historical constraints. Keep designs comprehensible, investigate failures without pretending the system is simple, and leave the next programmer enough context to continue.

063 β€” Local-First Software: You Own Your Data, in Spite of the Cloud β€” Martin Kleppmann, Adam Wiggins, Peter van Hardenberg, and Mark McGranaghan​

Put a user’s primary copy of data on their own device and make the network an aid to collaboration rather than a gate to basic work. Preserve offline availability, fast local interaction, multi-device synchronization, long-term access, privacy, and user control while using conflict-free replicated data types where concurrent edits must merge. Judge cloud architecture by whether people retain agency when the service is slow, discontinued, or unwilling to cooperate.

064 β€” Hyrum’s Law β€” Hyrum Wright​

At sufficient scale, every observable API behavior becomes somebody's dependency, whether or not you documented or intended it. Performance, error text, ordering, timing, and quirks can harden into de facto contracts. Limit what consumers can observe, measure real usage before changing behavior, and plan migrations as compatibility work rather than assuming the specification defines the whole interface.

065 β€” Cargo Cult Software Engineering β€” Steve McConnell​

Select engineering practices for the mechanisms and evidence that make them effective, not for their resemblance to what successful organizations do. Process becomes cargo cult when a team copies visible rituals while ignoring context, feedback, and the causal work underneath them. Form hypotheses about quality and productivity, measure the outcome, and revise the practice when reality disagrees.

066 β€” Software Quality at Top Speed β€” Steve McConnell​

Stop framing quality and delivery speed as automatic opposites. Defects create rework, destabilize schedules, and grow more expensive as they travel downstream, so disciplined prevention and early removal usually shorten the path to release. Invest in practices that expose mistakes close to their source, then use defect and rework data to find the quality level that supports sustained throughput.

067 β€” On Being a Senior Engineer β€” John Allspaw​

Seniority shows up in judgment under uncertainty, not in tenure or the volume of code produced. Build shared context, explain tradeoffs, ask questions that expose hidden assumptions, and help the team recover when systems and plans fail. Exercise influence without needing authority, keep technical depth connected to business consequences, and make the people around you more capable.

068 β€” Being Glue β€” Tanya Reilly​

Notice the coordination, onboarding, review, and gap-filling work that makes a technical team effective even though it produces little visible code. Choose that work deliberately: make its impact legible, share genuinely non-promotable tasks fairly, and keep enough of your evaluated craft in your workload to grow toward the career you actually want. If you manage others, do not let glowing feedback conceal a widening gap between what someone contributes and what your promotion system rewards.

069 β€” Staff Engineer: Archetypes β€” Will Larson​

Staff engineering is not one uniform job. You may guide a team as a Tech Lead, steward a durable technical domain as an Architect, resolve high-stakes ambiguity as a Solver, or extend an executive's reach as a Right Hand. Identify which form of leadership the organization actually needs, then choose work that fits both that need and the way you create leverage.

070 β€” The Engineer/Manager Pendulum β€” Charity Majors​

Treat management as a change of profession, not a promotion or a permanent departure from engineering. Move between the two tracks when the work calls you: management teaches conflict, motivation, and business context, while hands-on engineering renews the technical judgment and credibility that decay away from the code. Do each role fully rather than attempting both at once, since people and difficult technical problems each require sustained attention.

071 β€” Maker's Schedule, Manager's Schedule β€” Paul Graham​

Protect creative work in half-day blocks, because an hour is often only enough time to load a difficult problem into your head. A meeting that looks like one cheap calendar slot to a manager can split a maker's day into unusable fragments and suppress ambitious work before it begins. Cluster appointments into office hours or the edges of the day so coordination remains possible without repeatedly throwing exceptions through someone's concentration.

072 β€” Don't Call Yourself A Programmer, And Other Career Advice β€” Patrick McKenzie​

Employers buy reduced costs, increased revenue, and managed riskβ€”not programming as an identity. Frame your work around those business outcomes, and learn how companies hire, budget, negotiate, and value line-of-business software even when the technical work looks ordinary from inside the profession. Build communication and commercial judgment alongside coding skill so other people can recognize the leverage you already produce.

073 β€” Salary Negotiation: Make More Money, Be More Valued β€” Patrick McKenzie​

Negotiate compensation as a consequential business conversation, not as a referendum on your worth or gratitude. Preserve information and optionality: avoid naming the first number, keep multiple opportunities alive, and evaluate the complete offer only after the employer has decided it wants you. Ask calmly for an improvement backed by the value and alternatives you bring; a short uncomfortable exchange can outweigh years of routine raises.

074 β€” Beating the Averages β€” Paul Graham​

Choose technology for the advantage it gives the product, even when conventional employers would reject it as unusual. A more expressive language can compress implementation, expose better abstractions, and let a small team test ideas faster, while competitors may not recognize the advantage because their own tools constrain what they can imagine. Keep the strategic language choice close to the people who understand both the code and the business rather than reducing it to a standardized hiring decision.

075 β€” Hackers and Painters β€” Paul Graham​

Programming often behaves more like a maker's craft than a process of executing a complete specification. Begin with a working sketch, learn from the artifact, and revise toward a form you could not fully predict in advance. Let language, tools, and taste expand the designs you can think, while preserving enough autonomy and contact with users for iterative discovery to happen.

076 β€” Taste for Makers β€” Paul Graham​

Train your taste by studying why your earlier choices were worse, not by declaring every preference equally good. Seek designs that are simple, durable, fitted to the real problem, open to recombination, and easy to revise; apparent effortlessness usually arrives only after exacting iteration. Pay attention when expertise makes a tolerated convention look ugly, because that discomfort can identify work worth improving.

077 β€” How to Get Startup Ideas β€” Paul Graham​

Look for problems you know firsthand instead of brainstorming products that merely sound like startups. Start with a small group that urgently needs a solution you can build, choosing a narrow, deep well of demand over a broad audience that feels mild hypothetical interest. Put yourself near a changing frontier, notice what is newly missing, and let a real need pull the company into existence.

078 β€” Do Things that Don't Scale β€” Paul Graham​

Early-stage work often has to be done by hand before you know what deserves to scale. Recruit users manually, give them an unexpectedly attentive experience, and perform whatever the immature product cannot yet automate. That effort teaches you what users need, creates the first momentum for growth, and reveals which processes deserve machinery later.

079 β€” Startup = Growth β€” Paul Graham​

Define a startup by its pursuit of rapid growth, not by age, size, funding, or the use of fashionable technology. Choose a large reachable market, measure a meaningful growth rate every week, and let that constraint force decisions about product, hiring, and financing. Once growth becomes the compass, many debates become concrete: choose the action most likely to move the rate without destroying the foundations that sustain it.

080 β€” Schlep Blindness β€” Paul Graham​

Examine ideas you reflexively avoid because they involve sales, operations, regulation, payments, or other tedious work. That reluctance is shared by other capable builders, so the unpleasant execution may be the barrier protecting a valuable opportunity rather than evidence that the idea is bad. Separate a truly intractable business from a merely unappealing schlep, then decide whether the avoided work is precisely where you can create leverage.

081 β€” Keep Your Identity Small β€” Paul Graham​

The more tightly a belief is attached to your identity, the harder it becomes to examine honestly. Disagreement then feels like an attack, and inquiry becomes socially dangerous for everyone involved. Keep your identity small and your ideas available for revision so you can follow an argument past tribal boundaries without having to defend yourself along with the claim.

082 β€” The Top Idea in Your Mind β€” Paul Graham​

Guard the problem that occupies your mind when your attention is free, because background thought continues working on it long after you leave the desk. Money disputes, status anxiety, and other unresolved concerns can silently displace the question you most want your best thinking to advance. Audit what appears in quiet moments and change your circumstances when the wrong concern has become cognitively expensive.

083 β€” How to Do Great Work β€” Paul Graham​

Great work usually starts with curiosity strong enough to carry you to a field's frontier. Look for a problem that is important, tractable, and genuinely interesting to you; ambition supplies direction, but sustained interest provides the energy for years of learning and revision. Produce often, seek excellent peers, preserve morale through setbacks, and let discoveries redirect the plan instead of demanding a straight path from the beginning.

084 β€” Good and Bad Procrastination β€” Paul Graham​

Distinguish avoiding all work from postponing a smaller obligation because a harder, more important problem has taken hold of you. Significant work often requires long, apparently unproductive stretches and a willingness to disappoint the endless errands that present themselves as urgent. Ask what you are protecting by procrastinating, then arrange your life so the answer can be a consequential project rather than mere escape.

085 β€” Great Hackers β€” Paul Graham​

Create conditions in which exceptional programmers can spend their ability on the product instead of fighting weak tools, office politics, and arbitrary process. Give them hard problems, strong colleagues, autonomy over implementation, and a language expressive enough to keep ideas close to code. Do not confuse credentials, age, or conformity with ability; judge hackers by what they can make and by the clarity of the thinking embedded in it.

086 β€” How to Work Hard β€” Paul Graham​

Hard work lasts when genuine interest, a worthy aim, and an honest sense of your best effort reinforce one another. Push toward the edge of your capacity while protecting health and the curiosity that makes sustained effort possible, then calibrate yourself against people doing excellent work. Discipline matters most when it keeps you returning to the problem through uncertainty, not when it merely lengthens the visible workday.

087 β€” How to Be Polite β€” Paul Ford​

Practice politeness as an operational discipline: answer people, arrive when you said you would, remember names, apologize cleanly, and make ordinary interactions easier than they might have been. Assume that other people carry contexts you cannot see, and leave them room to recover from awkwardness or error without turning every lapse into a verdict. Courtesy will not resolve every conflict, but it reduces needless friction and keeps repeated relationships workable.

088 β€” Ten Lessons I Wish I Had Been Taught β€” Gian-Carlo Rota​

Give people something concrete to take home: organize a lecture around one memorable point, write for readers rather than prestige, and use clear exposition to discover whether you understand your own subject. Protect time for sustained work, learn the useful tricks of your profession without mistaking them for depth, and treat reputation as the accumulation of what others can reliably associate with you. Choose which obligations to neglect consciously, because a serious intellectual life cannot optimize everything at once.

089 β€” Solitude and Leadership β€” William Deresiewicz​

Leadership requires enough distance from messages, institutional incentives, and other people's finished opinions to form a thought of your own. It means more than executing assigned goals well; you must decide which goals matter, defend a new direction, and resist the conformity that bureaucracies reward. Develop that independence through concentration, reflective conversation, and solitary work that lets your first conventional answer mature into judgment.

090 β€” The Bitter Lesson β€” Rich Sutton​

Design AI methods to benefit from increasing computation rather than encoding ever more of your own domain knowledge. Across games, speech, and vision, handcrafted insight produced attractive short-term gains but eventually plateaued behind general search and learning methods that scaled. Build mechanisms that can discover useful structure for themselves, because the world's complexity is too open-ended to be captured as a fixed inventory of human-designed features.

091 β€” Why Software Is Eating the World β€” Marc Andreessen​

Treat software as the operating core of industries that once regarded it as a support function. Falling computing costs, broad connectivity, and a large population of capable developers let software-native companies reach customers and reorganize markets from books and music to logistics, finance, and energy. Evaluate incumbents by whether they can become software organizations quickly enough, not merely by whether they have purchased modern systems.

092 β€” A little bit of plain JavaScript can do a lot β€” Julia Evans​

The browser's built-in APIs can carry a small application farther than framework-first habits suggest. Event listeners, DOM methods, URL state, forms, and a little CSS support useful interactive tools with code that remains easy to inspect and change. Add dependencies when they solve a demonstrated problem, not before you have tested how far the platform itself can carry the design.

093 β€” Choices β€” Joel Spolsky​

Remove decisions that do not help the user accomplish the task. Every option forces someone to understand a distinction, predict a consequence, and accept responsibility for choosing, so configurability carries a cognitive cost even when implementation is cheap. Select strong defaults, infer what the program can know, and reserve explicit choices for differences that users genuinely understand and care about.

094 β€” Application compatibility layers are there for the customer, not for the program β€” Raymond Chen​

Regard a compatibility workaround as protection for the person who owns broken software, not as a new API contract for that software to exploit. The platform may detect an old program and emulate earlier behavior so a customer can keep working, but depending on the shim converts a temporary rescue into deliberate fragility. Program to documented behavior and let compatibility layers remain an implementation detail that can disappear when the original need does.

095 β€” John Carmack on Inlined Code β€” John Carmack​

Code can be easier to reason about when its execution and state changes read locally from top to bottom. Splitting that story into one-use helpers may scatter mutable dependencies across a file, although function boundaries remain valuable when they create strong contracts. Move separable logic toward pure functions and single-assignment values; purity improves reasoning even when the surrounding system cannot be purely functional.

096 β€” Rob Pike's 5 Rules of Programming β€” Rob Pike​

Measure before optimizing, because the expensive path is rarely where intuition first places it. Keep algorithms and data structures simple until evidence shows that scale demands something clever, then measure again rather than trusting the elegance of the optimization. Invest most heavily in representing and organizing the data well: once the structure is right, the necessary algorithms often become obvious.

097 β€” Design Principles Behind Smalltalk β€” Daniel H. H. Ingalls​

Build a computing environment from a small set of concepts applied consistently: everything is an object, computation happens through messages, and each component owns the interpretation of its state. Preserve a live, inspectable system in which users can understand and change the tools they use rather than being separated from them by fixed applications. Favor a simple, uniform kernel that can describe itself and grow through composition over a large language full of special cases.

098 β€” The Error Model β€” Joe Duffy​

Recoverable environmental failures and bugs that violate program invariants need different treatment. Make expected errors visible in types and signatures so callers must confront them, while failing fast on corrupted state instead of pretending execution can safely continue. Design the language, runtime, contracts, and diagnostics together: error handling shapes control flow and reliability too deeply to be repaired by adding exceptions after the rest of the system is settled.

099 β€” Structured Programming with go to Statements β€” Donald E. Knuth​

Treat structured programming as a method for making control flow provable and comprehensible, not as a lexical ban on goto. Choose constructs according to the reasoning they permit and the performance the problem actually needs; some well-disciplined jumps express exits, state machines, or optimized inner loops more clearly than contorted alternatives. Replace slogans with measured analysis, preserving structure while allowing carefully justified exceptions.

100 β€” The Early History of Smalltalk β€” Alan C. Kay​

Follow Smalltalk's development as an iterative search for a personal dynamic medium, not merely the invention of an object-oriented language. Objects, messages, late binding, graphical interfaces, networks, and children's learning experiments evolved together because the system was repeatedly rebuilt around a compact generative idea. Design ambitious systems by protecting the principles that let them grow, while remaining willing to replace implementations that no longer serve the larger vision.