Building software for government is unlike any other domain. The stakes are higher, the constraints are tighter, and the users are everyone — not a curated segment of early adopters.

After 18+ years working across HMCTS, the Ministry of Justice, the Department for Transport, and DWP, I’ve collected a set of principles that separate the projects that ship from the ones that stall.

## 1. Start with the user, not the service

GOV.UK’s first design principle — “Start with needs” — sounds obvious. It rarely is in practice. On almost every engagement, the initial brief describes a system rather than a user problem.

When we started on the **Possession Claims Service** for HMCTS, the instinct was to replicate the paper process digitally. Instead, we spent the first sprint mapping who was actually using the service: solicitors filing in bulk, litigants in person filing once, judges reviewing evidence. Three completely different mental models, one service.

```typescript
// Mapping user journeys before writing a line of code
interface UserJourney {
  persona:    'solicitor' | 'litigant-in-person' | 'judge';
  entryPoint: string;
  primaryTask: string;
  painPoints:  string[];
}

const journeys: UserJourney[] = [
  {
    persona:     'solicitor',
    entryPoint:  'bulk upload CSV',
    primaryTask: 'file 50+ claims per week efficiently',
    painPoints:  ['repetitive data entry', 'no batch status updates'],
  },
  {
    persona:     'litigant-in-person',
    entryPoint:  'GOV.UK search',
    primaryTask: 'understand what I need to do',
    painPoints:  ['legal jargon', 'no guidance on documents needed'],
  },
];
```

The resulting service had three distinct flows. Every content decision, every form field, every error message was written for a specific persona.

## 2. Treat accessibility as architecture, not audit

Most teams bolt accessibility on at the end. A quick axe scan, a few colour fixes, ship it. This doesn’t work — and in government it’s not optional. WCAG 2.2 AA compliance is a legal requirement under the Public Sector Bodies Accessibility Regulations.

The teams that do this well bake it into the Definition of Done:

- Every new component has been tested with a screen reader (NVDA + Chrome, VoiceOver + Safari)
- Keyboard navigation is verified before PR approval
- Colour contrast is checked at design stage, not dev stage

```scss
// Design tokens that guarantee contrast ratios
// — checked against WCAG 1.4.3 (contrast ratio ≥ 4.5:1 for normal text)
$gov-text-on-white:  #0b0c0c; // 21:1 — always safe
$gov-link:           #1d70b8; // 4.54:1 on white — just passes
$gov-link-visited:   #4c2c92; // 5.0:1 on white — passes
$gov-focus:          #ffdd00; // High-vis focus ring
```

## 3. CI/CD is not optional on government projects

Government services have some of the strictest change-management requirements around. Paradoxically, that’s a reason to invest heavily in automation — not to move fast, but to prove that every change is safe.

On our DfT engagement we built a pipeline that enforced:

```yaml
# Simplified CI pipeline for a GDS-style service
stages:
  - lint
  - unit-test
  - integration-test
  - accessibility-audit
  - security-scan
  - deploy-to-staging
  - smoke-test
  - deploy-to-prod

accessibility-audit:
  script:
    - npx axe-cli https://staging.service.gov.uk --tags wcag2a,wcag2aa
  allow_failure: false  # Hard gate — accessibility failures block the release
```

The accessibility audit was a hard gate. A failing axe scan blocked the release. No exceptions, no overrides without a documented risk acceptance from the product owner.

## 4. The strangler fig for legacy modernisation

Every government department has a 20-year-old mainframe system somewhere. The strangler fig pattern — gradually routing traffic to a new service while keeping the legacy system alive — is the safest way to modernise without a big-bang rewrite that risks public services.

The key is building a routing layer early:

```typescript
// Simplified strangler fig routing middleware
import type { Request, Response, NextFunction } from 'express';

const featureFlags = {
  useNewClaimsService: process.env.NEW_CLAIMS_ENABLED === 'true',
  useNewPaymentsFlow:  process.env.NEW_PAYMENTS_ENABLED === 'true',
};

export function routerMiddleware(req: Request, res: Response, next: NextFunction) {
  if (req.path.startsWith('/claims') && featureFlags.useNewClaimsService) {
    return next(); // New service handles it
  }
  // Fall through to legacy proxy
  res.redirect(307, `${process.env.LEGACY_BASE_URL}${req.path}`);
}
```

## Key takeaways

- **User research is not a phase** — it’s a continuous activity woven through delivery
- **Accessibility is architecture** — design for it, test for it, gate on it
- **Automate everything auditable** — if it can be checked by a machine, it should be
- **Strangle the legacy** — don’t rewrite, re-route

Government digital delivery is hard. But when it works, the impact is immense — millions of people interacting with services that actually serve them. That’s worth getting right.
