senior-software-developer
Skill1 starsChanged 11 days agoMITView on GitHub
A working playbook for the judgment, lenses, and habits that make a senior software developer — not a competence checklist, but reference material for someone trying to be excellent at the role over years.
In this repository11 other files it gives its agents.
- codebase-designSkill
- code-reviewSkill
- explainerSkill
- PR-code-reviewSkill
- principle-redesign-from-first-principlesSkill
- Product ManagerSkill
- retroSkill
- sherlock-holmesSkill
- testerSkill
- unit-test-unslopSkill
- unslopSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 6 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 96
Teach, in writing: Write the design doc, the postmortem, the internal explainer, the talk.
- Distinctive: line 100
Run a retro on yourself: After every project, before the relief sets in: what would I do differently, and *why* — what model was I missing?
- Distinctive: line 116
Before committing to any decision, answer this:
- Distinctive: line 122
Is this reversible?: If yes, decide fast. If no, slow down and bring the other lenses.
- Distinctive: line 123
Who maintains this, and will they have what they need?: If the answer is "only me, from memory," you haven't finished.
- Distinctive: line 126
If you can answer those honestly and still like the decision, make it.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
1. What the role actually is
A senior software developer is someone who reliably turns ambiguous problems into systems that other people can safely build on and change.
The single most common misconception is that seniority is a measure of technical depth — that the senior is the person who writes the cleverest code, knows the most languages. That belief produces a specific failure: engineers who get more and more technically deep while staying junior in every way that matters, because the actual transition to senior is not "I write better code" but "I make better decisions under uncertainty, and I make the people around me better." Depth is table stakes. It is the floor, not the achievement.
What the role is not, stated against the adjacent roles people confuse it with:
- It is not the tech lead. Tech lead is a hat — coordination, delivery, unblocking. A senior may wear it, but the seniority is in the judgment, not the coordinating.
- It is not the architect. The architecture-astronaut who draws boxes and hands them down has usually lost the thread; senior engineering judgment lives close to the implementation, where the abstractions actually leak.
- It is not the staff/principal engineer. Those roles operate at org-wide leverage and are a different job, not just "senior plus."
- It is not the engineering manager. That is a people-and-org role. Conflating the two is how good engineers get promoted into a job they didn't want.
- It is emphatically not "the 10x hero." The lone genius who out-types everyone and is the only one who understands prod is not senior. He is a single point of failure with good PR.
The core pillars of the work are roughly: technical judgment (knowing what's true and what will bite you), change-safety / systems design (building things that stay malleable as they grow), translation (moving fluently between business intent and code), force multiplication (raising the floor of everyone around you), and execution (actually shipping). Weak practitioners over-index on the code they personally write — its cleverness, its novelty, its use of the newest tool. Strong practitioners over-index on the code other people will have to read, debug, and change at 3am two years from now, with none of your context. The whole career is the migration of your attention from the first to the second.
2. The lenses you hold at once
The senior's distinctive cognitive move is holding several incompatible viewpoints simultaneously and refusing to collapse into just one. Most of these lenses, held alone, are a known failure mode. Held together, they are judgment.
- The product/user lens — "What problem does this actually solve, and would the user notice if we never built it?" Guards against building technically beautiful things nobody needs.
- The maintenance lens — "Who debugs this in two years, and will they understand it without me?" The most chronically under-weighted lens and the one seniority is mostly about acquiring.
- The blast-radius lens — "What else breaks when this breaks, and how fast will we know?" Systems fail; the question is whether the failure is contained and observable.
- The cost lens — "What does this cost to build, to run, and to not build — and is it worth it now or only in principle?" The opportunity cost of the thing you're polishing is the thing you're not shipping.
- The team/social lens — "Who needs to understand this, and does the design fit how this team actually works?" Conway's Law is not a curiosity; it's a design constraint.
- The risk lens — "What's the worst plausible outcome, who's the adversary, and what are we on the hook for?" In regulated or safety-adjacent domains this lens stops being optional and becomes existential.
Here is the actual claim: the senior's primary value in any given discussion is noticing which lens is absent and supplying it. A design review that has spent forty minutes on elegance is missing the cost lens — say so. A planning meeting racing to ship is missing the maintenance lens. A heated debate about the database is often missing the user lens entirely (the user does not care about your database). You are not the person with the most opinions. You are the person who notices the room is reasoning with one eye closed, and opens it.
3. How the best think — mental models
Reversibility (one-way vs. two-way doors). Most decisions are reversible and should be made fast and cheap; a few are not and deserve real deliberation. Why it matters: the universal junior mistake is spending equal anguish on both, agonizing over a function name while casually picking a data model you'll be stuck with for five years. Spend your judgment budget where it can't be refunded.
Make the change easy, then make the easy change (Kent Beck). When a change is hard, don't force it through the existing mess — first refactor until the change becomes easy (this part is often hard), then make the now-easy change. Why it matters: it inverts the instinct to bolt features onto resistant code. The resistance is information: the code is telling you its shape is wrong for what you're asking.
Chesterton's Fence. Do not remove or "clean up" code you don't understand the reason for; the weird, ugly, seemingly pointless code is usually load-bearing and written in someone's blood after an outage. Why it matters: most "obvious" simplifications are obvious only because you haven't yet learned what they were protecting against.
Optimize for the reader, not the writer. Code is read an order of magnitude more often than it's written, so clarity for the next human beats brevity or cleverness for you now. Why it matters: the clever one-liner you're proud of is a tax levied on every future reader, compounding silently for the life of the system.
All abstractions leak (Spolsky). Every abstraction eventually fails to hide the thing beneath it, so you must understand at least one layer below the one you depend on. Why it matters: the engineer who treats the ORM, the network, or the LLM as a perfect black box is the one blindsided when it leaks — and it always leaks under load, at the boundary, at the worst time.
Conway's Law as a tool. Systems mirror the communication structure of the org that builds them — so use it deliberately: if you want decoupled services, you need decoupled teams, and if two teams must constantly coordinate, their code will entangle no matter how clean your interfaces. Why it matters: you can fight your org chart with architecture and lose, or design with it and win.
Failure-domain thinking. Assume every component fails and ask what's contained when it does; design the isolation before the feature. Why it matters: reliability is not built by making things not fail (they will) but by making failures small, local, and loud rather than large, spreading, and silent.
4. The core skills and how to build each
Reading code, not just writing it. Most engineers can write and can't read. Build it deliberately: pick an unfamiliar mature codebase and trace a single request from entry point to database and back, naming every layer it passes through. Use git log and git blame as archaeology — when you find baffling code, find the commit that introduced it and the issue it closed. The goal is to reconstruct why, not just what. Do this until reading a new codebase feels like reading, not deciphering.
Decomposition — finding the seams. Take a feature and break it into slices that each ship independently and deliver value alone. This is the central craft skill, and you build it by force: before writing code, write the list of slices, then critique it — could each ship on its own? where's the natural seam vs. the one you imposed? The tell of a strong decomposition is that the risky, uncertain part is in its own small slice you can throw away.
Writing for humans. Design docs, ADRs, and PR descriptions are where senior work is actually transmitted. Build it by writing the design before the code — if you can't explain the approach and its main tradeoff in three sentences, you don't understand it yet, and the writing is how you find that out. Practice the compression: take a decision and state it as "We chose X over Y because Z, accepting cost C."
Debugging as a discipline, not luck. Reproduce before you fix — a bug you can't reproduce is a bug you can't confirm you fixed. Form an explicit hypothesis, then binary-search the problem space (disable half, see which half holds the bug), and change exactly one thing at a time. The "works on my machine" reflex of guessing-and-rerunning is the absence of this discipline. Slow is fast here.
Estimation under uncertainty. Decompose until each piece is under a day; pieces larger than that are hiding unknowns, and the unknowns are the whole risk. Name them explicitly ("I don't know if their API supports batch — that's the spike"). Then track your estimates against actuals for a few months. You will be humbled, and then you will be calibrated. There's no shortcut around the humbling.
Code review as teaching. Review for the things that are expensive to change — design, naming, missing failure cases, the wrong abstraction — and let a linter handle the things that are cheap. Ask questions rather than issue commands ("what happens here if the list is empty?" teaches; "add a null check" doesn't). A review full of style nits and silent on the load-bearing design flaw is malpractice dressed as diligence.
Saying no by making cost visible. You rarely win a "no" by refusing; you win it by making the deferred cost legible. "We can ship this Friday without the migration, but then every future change to this table is twice as slow — is that the trade you want?" Hand the decision back with the price tag attached.
5. Frameworks — tools, not thinking
The real frameworks of the field, each a genuine tool: ADRs (Architecture Decision Records) for capturing why a decision was made and what was rejected; RFC / design-doc processes for thinking before building; the Twelve-Factor App for service hygiene; SOLID for object-oriented design; Domain-Driven Design and its bounded contexts for modeling complex domains; the C4 model for diagramming at consistent zoom levels; CAP / PACELC for reasoning about distributed-system tradeoffs; the testing pyramid for test strategy; DORA metrics for delivery health; and the blameless postmortem for learning from failure.
Now the warning, and it is the most important sentence in this section: a framework structures your thinking; it never substitutes for it. SOLID applied dogmatically produces a swamp of single-method interfaces and indirection that obscures more than it reveals — the principles are heuristics, not laws, and "single responsibility" is meaningless until you've decided what counts as a responsibility, which is the actual judgment the framework can't make for you. The testing pyramid taken literally produces brittle, low-value unit-test suites that test mocks testing mocks. DDD becomes ceremony when imposed on a domain that's actually simple. Every one of these was distilled from a specific context by someone solving a specific problem; cargo-culting the conclusion without the context is how frameworks become superstition. Use them to generate the right questions. Refuse to let them hand you the answer.
6. Worked examples — weak vs. strong
The flaky test. A test fails intermittently in CI. The weak move: add a retry, or mark it @flaky, and move on — the build is green again, ship it. The strong move: treat the flake as a signal, not noise. A test that fails one time in twenty is usually surfacing a real race condition, a shared-state leak between tests, or a timing assumption that's also false in production — just rarer there. The strong engineer reproduces it (run it 500 times in a loop locally), finds the actual ordering dependency, and fixes the root cause. The reasoning gap: the weak engineer optimized for a green build; the strong one understood that the flake was production telling them, cheaply and in advance, about a bug they'd otherwise meet expensively and at night.
The feature that fights the code. Product wants to add per-user notification preferences, but the notification module hard-codes a single global config. The weak move: thread a special-case if user.hasPreferences through six functions, ship it, leave the module worse than you found it. The strong move: recognize the resistance as information (Kent Beck's model) — the module's shape is wrong for what's now being asked. First refactor it so preferences are a first-class concept (the hard part), then the feature is a small, obvious addition (the easy change). The reasoning gap: the weak engineer treated the existing structure as fixed and the feature as the variable; the strong one knew that bolting onto a resistant structure compounds, and that the right move is sometimes to spend an afternoon making the next ten changes cheap.
The exciting new technology. Traffic is growing and someone proposes moving to microservices with Kafka and a service mesh. The weak move: agree, because it's what real engineers do and it'll look great — begin a six-month migration. The strong move: ask the questions the excitement skipped. What's the actual current and projected load? What specifically is breaking under it — is it a real bottleneck or an imagined one? Is this a one-way door (it largely is — you can't easily un-distribute a system)? Microservices trade in-process simplicity for distributed-systems complexity, which is a tax you pay forever; the strong engineer makes sure the problem being solved is worth that permanent tax, and usually discovers a well-indexed query and a read replica solve it for a fraction of the cost. The reasoning gap: resume-driven optimism vs. reversibility and cost held together.
7. How to become the best (not merely competent)
Competence is repeating what works. Excellence is the deliberate, slightly uncomfortable practice that compounds — and almost none of it is writing more code.
Keep a decision journal. When you make a non-trivial call, write down what you expect to happen and why. Months later, check. This is the only way to actually calibrate judgment rather than just accumulating confident memories of having been right. Most engineers never close this loop, which is why ten years of experience is often one year repeated ten times.
Maintain something for years. You cannot learn what a decision costs by making it; you learn it by living with it. The engineer who builds and walks away never feels the weight of their own abstractions. Owning a system across its evolution is the single richest teacher available, and it can't be rushed.
Read the layer below. Deliberately work just outside your comfort zone of the stack — read the source of a library you depend on, learn what the network actually does, understand how the LLM you're calling tokenizes and fails. The abstraction you treat as magic is the one that will blindside you.
Teach, in writing. Write the design doc, the postmortem, the internal explainer, the talk. Teaching is the most ruthless test of understanding there is — the gaps in your thinking become visible the moment you try to explain them to someone who'll ask "but why?"
Read great code and public postmortems like literature. Taste is built by exposure. Read the source of tools you admire; read the published incident writeups from companies operating at scale. You're not memorizing solutions — you're absorbing the texture of good judgment so your own pattern-matcher gets better inputs.
Run a retro on yourself. After every project, before the relief sets in: what would I do differently, and why — what model was I missing? Done consistently, this is the difference between accumulating scar tissue and accumulating wisdom.
9. A note for your context
You're a founder-engineer building a voice-agent platform for banks and fintechs, owning the full orchestration stack rather than renting it from Retell or Vapi. A few of these principles aren't just relevant for you — they're load-bearing.
The reversibility lens is sharpened by your runway. Owning the orchestration stack and committing to VPC/self-hosted deployment as a sales prerequisite are close to one-way doors — they shape your hiring, your cost structure, and your sales motion for years — so those deserve the slow, deliberate kind of decision. Almost everything else (a prompt revision, a tool's schema, an intent cache) is a two-way door you should be deciding fast and cheap. Make sure you're spending your limited founder-judgment on the irreversible calls and ruthlessly fast on the rest.
The risk lens is not optional in your domain; it's existential. In a regulated financial-voice context, a hallucinated answer or a PII leak isn't a bug you patch next sprint — it's potentially a company-ending event. Your tool-only, anti-hallucination architecture is exactly Chesterton's Fence built deliberately and in advance, which is the right instinct. Treat the compliance and blast-radius constraints (RBI localization, DPDP, PCI DSS) as design inputs from day one, not as a layer you add before a sales call.
Two founder-specific failure modes to watch. First, the Hero: at your stage you are the bus factor, which is survivable now and fatal at scale — start writing down the why of your prompt and architecture decisions as ADRs so the knowledge isn't only in your head. Second, resume-driven complexity: the Gemma fine-tuning / SLM-distillation work is genuinely interesting and may be the right long-term bet, but interrogate honestly whether it's solving a customer's problem now or whether it's the exciting thing pulling you off the boring thing that ships. Apply your own reversibility test to it.
One reframe worth internalizing: in your world, prompts are production code. They have failure modes, regressions, and security surfaces (the jailbreak hardening you've done is exactly this). Version them, test them against a suite of adversarial cases, and review them with the same seriousness you'd review a payments function — because functionally, that's what they are.
10. The one-line test
Before committing to any decision, answer this:
In two years, when someone who isn't me has to change this under pressure and without my context — will this decision have made their job easier or harder, and is what I'm saving now worth what I'm charging them later?
And if you want the compact field version, three questions, in order:
- Is this reversible? If yes, decide fast. If no, slow down and bring the other lenses.
- Who maintains this, and will they have what they need? If the answer is "only me, from memory," you haven't finished.
- What breaks if I'm wrong, and how fast will I find out? A wrong decision you detect in an hour is cheap. A wrong decision you detect in a quarter is not.
If you can answer those honestly and still like the decision, make it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

