The Gap Between 'The Software Works' and 'The System Works'
I have become suspicious of clean demos.
The software works. The tests pass. The deploy succeeds. And then someone joins the team, can’t find the auth documentation, misconfigures an edge function, and ships a route that returns admin-scoped data to unauthenticated users.
The software still works. The system doesn’t.
Most engineering failures live in this gap.
Where the gap shows up
The gap is not abstract. It has specific shapes.
Auth that works in one app but not across apps. You add Clerk. Login works. Then you build a second app that shares the same users but has its own database. Now you need the same identity to produce different UUIDs in different Supabase projects, each with its own Row Level Security policies. The login button still works. The identity system doesn’t.
Security that lives in the wrong layer. Your API checks permissions before returning data. Someone adds an edge function that calls the database directly. Or an admin endpoint gets deployed without the middleware. The API-level auth was never the security layer — it was a convenience layer. The database didn’t enforce anything on its own.
Knowledge that lives in one person’s head. The original engineer knew why the JWT template was named supabase and why the JWKS cache expires after 24 hours. They left. The next person changes the cache TTL because it seems conservative. Key rotation breaks in production.
Documentation that describes what, not why. The README says “run npm start.” It doesn’t say why the app works without a backend, or what happens when a user signs up anonymously and later creates an account. The code runs. Nobody understands the merge-on-login behavior until it breaks.
The gap is not a bug
You can’t file a ticket for this. The gap between software and system isn’t a defect in any single component. It’s the absence of the connective tissue that makes components behave as a whole.
Software is what a single engineer builds and tests. A system is what survives contact with other engineers, production infrastructure, user behavior, and time.
The difference shows up in specific ways:
-
Software works when you understand it. A system works when someone who doesn’t understand it can’t accidentally break it. That’s what Row Level Security does — it enforces access control at the database, regardless of what the application layer does or doesn’t check.
-
Software works when you run it. A system works when you don’t have to think about it. That’s what documented architectural decisions do — they let the next person make correct choices without reverse-engineering intent from code.
-
Software works on your machine. A system works across frameworks, environments, and team changes. That’s what a shared auth library does — it encodes the same identity model across React SPAs, Astro SSR sites, and edge functions, so each new integration doesn’t reinvent the approach.
Closing the gap
The gap doesn’t close with more code. It closes with specific kinds of discipline.
Put enforcement at the data layer, not the application layer. If your security depends on every API route remembering to check permissions, it will eventually fail. If the database enforces access control through RLS, the application can be wrong without the data being exposed.
Document decisions, not just procedures. “How to deploy” is useful. “Why we chose Terraform over CDK” — with the constraints, options considered, and consequences — is what prevents someone from re-litigating the decision or making a contradictory one.
Build shared infrastructure, not shared assumptions. When three apps need the same identity model, the choice is between a shared library that encodes the pattern once, or three independent implementations that will drift. The library is more work upfront. The drift is more work forever.
Design for the person who isn’t in the room. The system holds when the person who built it is on vacation, or has left, or never existed. Every decision that depends on “everyone knows this” is a gap waiting to open.
Why this matters
The software industry is good at making things work. Frameworks are better than ever. Deployment is easier than ever. A single engineer can build and ship a functional product in a weekend.
But functional products fail all the time — not because the code stops running, but because the system around the code never cohered. The auth breaks across apps. The security model has a gap nobody tested. The new hire can’t find the rationale behind a critical design choice.
The gap between “the software works” and “the system works” is where most real failures originate. It’s where we work.