Framework Independence
Not "how do I create an Express route" but "an HTTP request arrives, a router matches it, a handler runs, a response is written". Learn the mechanism at the level below the framework and the framework becomes syntax — learnable in an afternoon, swappable in a week.
The situation, the reflex, and why it stalls
Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.
What is the framework doing for you — and could you describe the mechanism without naming the framework?
I know how to make an Express route. I was asked to do the same thing in a different framework and I froze; then I was asked what happens between the browser sending a request and my handler running, and I realised I had only ever known the syntax. Every new tool is a new beginning for me, and the seniors seem to pick them up in a day.
Learn the framework properly. Read its documentation front to back, follow its tutorial, build its example app. Expertise in the tool is what the job asks for, and the next tool will get the same treatment when it arrives.
The expertise is in the tool's vocabulary — middleware, decorators, hooks — and none of it survives the tool. The next framework has different words for the same mechanism and the learning starts from zero, which is why every new tool feels like a new beginning.
- The expertise is in the tool's vocabulary — middleware, decorators, hooks — and none of it survives the tool. The next framework has different words for the same mechanism and the learning starts from zero, which is why every new tool feels like a new beginning.
- Because the mechanism is unknown, the framework's behaviour is magic: why the handler did not run, why the body is empty, why the response was sent twice are questions with no model to reason from, and each is solved by searching the exact error message.
- Design decisions are made in the framework's terms. "Where does validation go?" is answered "in a middleware" rather than "between parsing and the service", and the answer cannot be carried to a codebase that has no middleware.
- The tutorial that taught the framework built its app in its shape, and the shape is inherited as "how backends are structured". Documentation was used as a substitute for understanding instead of as an accelerator of it (Tutorial Dependency).
The move
Precisely enough to apply it to a problem you have never seen — not a slogan.
- For any framework feature, write the sentence that describes what happens without the framework's name in it. "A route" becomes: an HTTP request arrives on a socket; something parses the method and path; something matches them to a handler; the handler runs with the parsed request and produces a response; the response is serialised and written to the socket. That sentence is true of every web framework ever written, and it is the thing to know.
- Then map the framework's syntax onto the sentence.
app.get(path, handler)is "register a match on method and path"; middleware is "a step between parsing and the handler"; the response object is "the thing that serialises and writes". The framework is now a set of names for steps you already understand, and its documentation is a lookup, not a course. - Do this at the level *one below* the framework — the HTTP request lifecycle for a web framework, the render-and-reconcile loop for a UI framework, the query-build-and-execute path for an ORM. Not lower: the socket, the kernel and the SSD are further down the stack and not where the framework's promises live (Abstraction Levels).
- Use the framework fully. Independence is not avoidance; it is knowing the mechanism well enough that the framework's decisions are visible as decisions — which makes it faster to use, easier to debug and possible to leave.
The route, without the framework
The compare is the move in one pair. On the left, knowledge that lives only in the framework's vocabulary; on the right, the same knowledge stated as a mechanism, with the framework's syntax mapped onto it. The right-hand version is what makes the left-hand version cheap.
"To create a route you call app.get with a path and a handler; use middleware for things that run before; res.json sends JSON." True, and it evaporates on the next framework and explains nothing when the handler does not run.
"A request arrives; it is parsed into method, path, headers and body; the method and path are matched to a handler; steps registered before the handler run in order; the handler produces a response; the response is serialised and written." Then: app.get is the match, middleware is the ordered steps, res.json is the serialise-and-write.
The mechanism sentence is true of every HTTP framework, so it is learned once; the framework's constructs become names for its steps, so a new framework is a new set of names. And every misbehaviour is a question about one step, which is a question the docs can answer.
Mechanism on the left, syntax on the right
The table is the working tool, for a web backend. Learning a new framework is filling in a new right-hand column; debugging is reading down the left-hand column to find which step the symptom belongs to. The last column is the decision the framework has made for you, which is the part worth reading its documentation for.
| Mechanism step | Question it answers | A framework's name for it | What the framework decides for you |
|---|---|---|---|
| Accept a connection, read the request | how do bytes become a request? | the server / listen | timeouts, body size limits, HTTP versions |
| Parse method, path, headers, body | why is the body empty? | body parser, request object | when parsing happens, which content types, lazily or eagerly |
| Match to a handler | why did my handler not run? | route, router, decorator | match order, trailing slashes, method fallbacks |
| Run steps before the handler, in order | where does auth or validation go? | middleware, guards, filters | ordering rules, how a step short-circuits |
| Run the handler; call the service | where does the business logic live? | handler, controller, action | nothing — this one is yours |
| Turn an error into a response | why did the client get a stack trace? | error middleware, exception filter | default status codes, what leaks in production |
| Serialise and write the response | why was the response sent twice? | res.json, return value | content negotiation, when headers are committed |
Checkout, as a mechanism
Pseudocode for the checkout route with no framework in it. Every line is a mechanism step; every framework you will meet has a name for each. Write this first, then translate — and when the translation misbehaves, come back here to ask which line it was.
The first thing to build in an unfamiliar framework is the slice below: one request through every mechanism step. It fills in the right-hand column of the table with running code, and what it does not prove is exactly the list of things the framework decides for you.
- Parsethe JSON body arrives in the handler as a parsed object
- MatchPOST /checkout reaches the checkout handler and nothing else does
- Ordered stepsan authenticate step runs before the handler and can stop the request
- Handler → servicethe handler calls orderService.checkout and does no business logic itself
- Respondthe order id comes back as JSON with the intended status code
1on request:2 parse method, path, headers, body -- the framework's parser; note *when* it runs3 if method = POST and path = /checkout: -- the framework's matcher4 run ordered steps: authenticate, validate body shape5 if any step fails: respond with its error and stop6 result = orderService.checkout(body.cartId, user)7 if result is an order: respond 201 with the order id8 else: respond with the failure reason9 else: respond 40410on any unhandled error: respond 500, log, do not leak the traceNotice which lines are yours (the service call, the responses) and which the framework provides (parse, match, ordered steps, error catch). Independence is knowing which is which.
How to do it
Most important first.
- For each framework feature you use, write its mechanism sentence with no framework nouns. If you cannot, that is the entry question for the layer below; go to the request-lifecycle lesson, not to the framework's docs.
- Keep a two-column table: mechanism step on the left, this framework's syntax for it on the right. A new framework is a new right-hand column and nothing else.
- Debug from the mechanism. "The handler did not run" is a question about matching; "the body is empty" is a question about parsing order; ask the mechanism first, then look up how this framework exposes that step.
- Make design decisions in mechanism words — "validation between parsing and the service" — and only then translate to the framework's construct (Pseudocode Before Code).
- Read the framework's documentation for what it *decides* on your behalf — parsing, error handling, ordering — because those are the decisions you would otherwise not know you had delegated (Reading Documentation With a Goal).
Worked on a concrete problem
The move has to produce something. This is what it produced.
- Checkout, as a mechanism sentence: a POST arrives with a cart id; the body is parsed as JSON; the path matches the checkout handler; the handler validates the shape, calls the order service, and writes a response with the order id or an error. In Express that is a JSON body parser,
app.post('/checkout', handler), andres.status(...).json(...). In a different framework it is a decorator, a typed body and a return value. The sentence is the same; the second column changed. - The debugging pay-off: "the checkout handler runs but the body is empty". Mechanism question: which step parses the body, and does it run before the handler? In this framework, parsing is a step that must be registered before the route; it was registered after. Found from the mechanism in minutes; found from the error message never, because there was no error.
- The mechanism table for the frontend, same move: user event → state change → re-render of the parts that depend on it → DOM update. The UI framework's component, state hook and effect are names for steps of that loop; "why does this re-render twice?" is a question about the loop, and the framework's docs answer it once you know which step to look up.
How you know it worked
What now exists that did not before, and what question you can now ask.
- You can describe what your handler does between socket and response with no framework word in the sentence, and the sentence would be accepted by someone using a different framework.
- A new framework is learned by filling in a right-hand column, and the first day with it is productive.
- Debugging starts with a mechanism question — which step, in which order — and the framework's documentation is consulted for how that step is exposed.
The questions you can now ask
The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.
- ?What is this framework feature doing, in a sentence with no framework nouns?
- ?Which step of the mechanism does this syntax correspond to, and what does the framework decide about that step on my behalf?
- ?When this misbehaves, which step of the mechanism is the question about?
- ?What is the level one below this framework, and where does the atlas teach it?
What can go wrong
- Mechanism purism: refusing the framework's constructs and reimplementing routing "to really understand it". The mechanism is understood by describing it and mapping it, not by rebuilding it in production.
- Going too far down. Learning the socket layer and the kernel's accept queue to understand a route is two layers below the framework's promises; the request lifecycle is the right floor, and the ones beneath have their own lessons for when a symptom sends you there.
- Treating every framework as interchangeable because the mechanism is shared. Frameworks differ in what they decide for you — ordering, error handling, defaults — and independence means seeing those decisions, not ignoring them.
- Writing the mechanism sentence once and never checking it against the framework's actual behaviour. Some frameworks parse lazily, some stream bodies, some run handlers concurrently; the sentence is a model, and the documentation says where this framework departs from it.
- The mechanism sentence is an extra step on the first framework, and on the first framework it is slower than the tutorial. It is faster from the second framework on, which is the bet.
- Making design decisions in mechanism words and then translating means the code sometimes fights the framework's idiom; a team fluent in the framework will read it as unidiomatic, and occasionally they are right.
- Knowing what the framework decides for you is knowledge that has to be refreshed per version; the mechanism is stable and the framework's departures from it are not.
- "Frameworks are bad; write it yourself." The lesson is the opposite: use the framework, and know the mechanism so that using it is fast and leaving it is possible. Rewriting routing is delegating nothing and understanding nothing new.
- "Independence means an abstraction layer over the framework." Wrapping Express in your own router does not teach the mechanism and adds a layer to debug. The independence is in your head and in your design vocabulary, not in a wrapper (Library or Framework in the design domain covers when a wrapper is warranted).
- "Seniors learn frameworks fast because they are smarter." They learn them fast because they are filling in a column against a mechanism they already hold. The mechanism is learnable; it is one level down from where the tutorial stopped.
Where this applies
Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.
- GENERALEvery framework — web, UI, ORM, ML training loop, agent orchestration — sits on a mechanism one level down. The move is the same: describe the mechanism without the framework's nouns, then map the syntax onto it.
- TEAM-SPECIFICA solo learner should do the mechanism sentence for every feature, because nobody else will catch the magic. On a team with a house framework and a decade of idiom, the mechanism still matters for debugging and design, but the idiom is a real constraint and "unidiomatic but mechanism-correct" code is a cost to the team.
- CONTESTEDThe strongest opposing view: deep fluency in one framework — its idioms, its ecosystem, its failure modes — is what ships products, and the "learn the mechanism" advice produces engineers who are shallow everywhere and expert nowhere. That view is right about fluency being valuable and about the mechanism not substituting for it; the disagreement is only about order, and this lesson's claim is that fluency built on the mechanism is faster to acquire and survives the framework, while fluency built on the tutorial is lost on the next migration.
- ILLUSTRATIVEThe Express examples and the empty-body bug are invented for the shape of the argument; the mechanism sentence for HTTP is real and the framework-specific details (parsing order, response objects) differ by framework and version.
Where the depth lives
This domain asks the question and hands the answer off by name.
- — The manifesto's /manifesto/delegating cards list what a web framework handles for you and what stays yours; the right-hand column of this lesson's table is the same list for one framework.