In software engineering we have a fairly plain answer to the question of whether something is fit for purpose: a system is fit for purpose if it reliably does the thing it was designed to do. We seem to apply a much softer standard to the systems people actually have to live inside. A public service can have a department, an application portal, a helpline, a set of criteria, a budget, and hundreds of people working within it, and none of that tells us whether it is achieving its purpose. A system existing is not the same thing as a system working. The longer technical walkthrough lives in the companion article on dev.to.
Activity is not an outcome
Picture a workflow where every component behaves. The application is submitted, the validation passes, the assessment happens, the decision is recorded. Operationally the system performed exactly as expected. But if the person reaches the end of that process without receiving the support they needed, the system produced activity rather than an outcome.
This is a problem we already know well. We can build dashboards showing requests processed, jobs completed, transactions handled, and uptime maintained, and none of those numbers necessarily tell us whether the system solved the problem it was built to solve. Applications received, appointments attended, cases opened, forms processed: all activity. The harder question is whether the person's situation actually changed. When a system measures activity far better than it measures outcomes, it becomes entirely possible for the system to look healthy while the people inside it experience failure.
A system needs somewhere to fail
One of the first things you learn as a developer is that the happy path is not the whole system. Real systems meet invalid input, missing information, unsupported configurations, unavailable dependencies, and users who do not behave the way the design assumed. Good software does not pretend those cases are absent. It detects them, explains them, and where it can, offers a recovery path.
So a service should be able to tell someone not only that they qualify, but also when it cannot give them what they need. That is not a failure. If an API knows it cannot fulfill a request, a clear early error is better than accepting the request, threading it through ten services, consuming resources, and eventually failing without explaining why. Compare a system that assesses a person, determines it cannot help, explains the reason, and routes them somewhere that can, against a system that runs them through months of appointments, documentation, and follow-ups before arriving at the same conclusion. The second one generates far more measurable activity and is the worse system. The first has a defined failure state. The second has an expensive failure path, and the cost of that path is paid in someone's time.
The loop that cannot close
There is a subtler failure mode, and it is the one I find most interesting when you read public services as architecture. Suppose a program is meant to bridge the gap between a candidate and an employer, but it can only intervene meaningfully once an employer has already engaged. The candidate applies, the employer does not engage, the application is ignored, there is no employer side intervention available, and the candidate applies again.
Nothing has crashed. There is no exception to catch. The system is simply unable to transition into the state that success requires. In software I would ask immediately which state transition is missing, and the answer here is a circular dependency: the system is waiting on the event it exists to help create. That deserves architectural scrutiny rather than another round of the loop.
Boundaries belong in the documentation
Every system has a boundary. An API has supported inputs, a database has constraints, a service has capacity, a platform has supported environments. Good systems publish those boundaries, because you do not want a developer discovering after six months that the operation they built around was never supported.
The same should hold for services involving people. If a program only holds employer relationships in particular sectors, that matters. If certain kinds of work sit outside its scope, that matters. If particular circumstances make a useful outcome unlikely, that matters, and the person needs to know early enough to make their own decisions about their own time. Otherwise the system hides its limitations and leaves the user to find them by repeated failure. Related to this is a set of questions I would call observability questions rather than hostile ones: which employers have relationships with the program, how many participants were connected through them, how many were simply advised to apply as normal, how many were identified as unsuitable, and what happened to those people afterward. If a system cannot answer that, it is difficult to establish whether it is doing the thing it was built to do.
The user becomes the error handling layer
When a system fails, something has to absorb the failure. In software that might be a retry, a dead letter queue, a fallback, or an operator stepping in. In poorly designed human facing systems, that responsibility quietly moves onto the person. A form fails, so they try again. An email goes unanswered, so they chase it. A verbal commitment is not recorded, so they write it down themselves. A case is transferred, so they reconstruct its history.
Eventually the person becomes the system's external state store. They keep the records, track the state, reproduce missing context, and supply the observability the system failed to provide. Their notes, dates, names, and saved emails turn into a second system running alongside the official one, maintained because the official one will not reliably preserve the context they need. If you had to hand maintain your own audit log because production did not provide one, you would call that an architectural problem. That work costs time, attention, organization, and emotional energy, and none of those costs show up in the institution's metrics.
Accessibility is architecture
This matters most when the system is meant to support disabled people. A process that demands sustained attention, precise documentation, repeated communication, and heavy administrative work can create a barrier for exactly the people it was built to serve. That does not mean every requirement should be stripped out. It means the design has to account for the users who will actually operate it, which in software we call accessibility: we do not assume everyone interacts the same way, so we offer alternatives and remove friction that earns nothing.
The principle I keep returning to is that you should not need the outcome in order to have the capacity to navigate the process that produces the outcome. If completing the process requires overcoming the same barrier the service exists to help with, the architecture deserves examination.
So, when is a system not fit for purpose?
Not simply when it is imperfect, because no serious system is perfect. And not when it says no, because sometimes the correct behavior is to say clearly that it cannot help. What matters is what happens next. A system becomes questionable when it cannot identify its own boundaries, cannot communicate them clearly, and can keep consuming a person's time and resources without producing a meaningful outcome.
In software we would investigate that. We would read the architecture, examine the state transitions, inspect the failure modes, check the metrics, and look at the monitoring, and then ask whether the system is optimizing for the thing that matters. Public systems deserve the same scrutiny, because the test is not whether the process ran. A system can be operational, compliant, fully staffed, and processing thousands of cases while still not being fit for purpose. Sometimes the most important failure is not that the system crashed. It is that the system kept running exactly as designed while the person it was supposed to help went nowhere.