Build a boring, reliable delivery system

September 3, 2025

A compact checklist for CI/CD, GitOps, IaC, and observability that scales with your team.


CI/CD: optimize for fast, trusted feedback

Good pipelines are boring:

  • Run lint, typecheck, and tests on every change
  • Cache dependencies and build artifacts
  • Fail fast, then show the smallest useful error output

If developers don’t trust CI, they stop looking at it. Keep it deterministic.

Example (a minimal CI job that runs on every push/PR):

name: ci
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm test

GitOps: make the desired state the source of truth

GitOps works best when:

  • Environments are described declaratively
  • Changes are reviewed like application code
  • The cluster reconciles state continuously

Keep a clear boundary between “app repo” and “environment repo,” or at least make ownership explicit.

IaC: reduce snowflakes and surprise drift

Infrastructure-as-code is not only provisioning; it’s lifecycle management:

  • Pin providers and modules
  • Separate state per environment
  • Run drift detection and policy checks in CI

Prefer composable modules over mega-modules, and make inputs explicit.

Observability: answer “what changed?” quickly

Focus on a few high-signal signals:

  • Logs with request IDs and meaningful error context
  • Metrics for saturation, errors, latency, and throughput
  • Traces across service boundaries

Tie these to SLOs so alerts represent user impact, not noise.

Automation: remove toil, don’t create surprise

Automate repeatable workflows:

  • Provisioning and access requests
  • Dependency updates
  • Release notes and versioning

Make automation auditable and reversible.

References

Hi, I'm Martin Duchev. You can find more about my projects on my GitHub page.