The Software Delivery Lifecycle
The Software Delivery Lifecycle
In the previous two lessons you learned what DevOps is and how the CALMS framework describes the cultural shift it demands. Now you will zoom in on the mechanical heart of DevOps: the Software Delivery Lifecycle (SDLC) — every stage a change passes through from the moment a developer pushes a commit to the moment that change is serving real users in production.
Understanding this pipeline end-to-end is non-negotiable for a DevOps engineer. You will own large parts of it: the automation infrastructure, the quality gates, the deployment mechanism, and the feedback loops that make the whole system self-correcting.
The Seven Canonical Stages
Large-tech delivery pipelines vary in their exact names and internal sub-steps, but they all map to seven conceptual stages: Plan → Code → Build → Test → Release → Deploy → Operate. Each stage feeds directly into the next, and critically, each stage also produces feedback signals that flow back to earlier stages — the loops that make continuous improvement possible.
Stage-by-Stage Deep Dive
1. Plan
Work is broken into stories and tasks in tools like Jira, Linear, or GitHub Issues. At high-performing companies this stage includes Definition of Done (DoD) — an explicit checklist that every story must pass before it is considered complete. This is where you capture not just functional requirements but operability requirements: SLOs, rollback procedures, observability needs. Stories that skip operability requirements create fire-fighting work later.
2. Code
Developers write code in short-lived feature branches off of main. The pull-request (PR) review is the first quality gate: a human checks correctness, style, security, and test coverage. Pre-commit hooks run linters and secret-scanners locally so trivial issues never reach CI.
Pre-commit hook (via pre-commit framework, .pre-commit-config.yaml)
repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: detect-private-key - repo: https://github.com/gitleaks/gitleaks rev: v8.18.1 hooks: - id: gitleaks # blocks commits containing secrets3. Build
On every push the CI system compiles the code, resolves dependencies, runs static analysis, and produces a deterministic, immutable artifact — a Docker image, a JAR, or a compiled binary. The artifact is tagged with the Git SHA and pushed to a registry. Producing the artifact only once (not once per environment) is a hard rule: the same bytes that passed tests are the bytes that go to production. Rebuilding per-environment introduces drift.
Dockerfile — multi-stage build (Node.js example)
# ---- build stage ---- FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY . . RUN npm run build # ---- runtime stage ---- FROM node:20-alpine AS runtime WORKDIR /app ENV NODE_ENV=production COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules USER node EXPOSE 3000 CMD ["node", "dist/main.js"]docker build -t myapp:$(git rev-parse --short HEAD) . — never use :latest in CI pipelines. An immutable tag means you can pinpoint exactly what code is running anywhere.4. Test
Tests are arranged in a pyramid: many fast unit tests at the base, a smaller number of integration tests in the middle, and a thin layer of end-to-end (E2E) tests at the top. Big-tech pipelines enforce coverage thresholds (typically 80 %+ on critical paths) and treat a failing test as a pipeline blocker — not an optional warning.
Additional automated checks run here: SAST (static application security testing), dependency vulnerability scanning (trivy, snyk), and contract tests for API consumers. Any failure in this stage sends an immediate Slack/PagerDuty notification to the owning team — the faster the feedback, the cheaper the fix.
5. Release
The release stage promotes the verified artifact to the artifact registry (e.g., ECR, GCR, Artifactory) and creates a Git tag that anchors this exact version forever. In trunk-based development, every green build on main is a potential release candidate. In GitFlow, only merges to a release branch trigger this step. The release artifact also gets a Software Bill of Materials (SBOM) attached — an inventory of every library inside the image, required by many enterprise and government customers.
6. Deploy
The deploy stage puts the release artifact into a running environment. The deployment strategy determines risk:
- Rolling update — new pods replace old ones gradually; low risk, no extra infrastructure cost.
- Blue/Green — two identical environments; traffic switches atomically; instant rollback by pointing the load balancer back.
- Canary — route a small percentage (1–5 %) of live traffic to the new version first; promote or roll back based on real error rates.
At Google scale, canaries run for hours or days before a full rollout. Feature flags decouple deployment (code is live) from release (feature is visible to users), giving operators a runtime kill switch independent of the deployment pipeline.
7. Operate
The running system is observed through metrics, logs, and traces — the three pillars of observability. Alerts fire when SLO error budgets are consumed. Post-incident analysis feeds back into the Plan stage, closing the loop. This is not optional post-launch activity: at elite companies, on-call rotations include the same engineers who wrote the code, creating strong incentive to make software observable from day one.
The Feedback Loop Is the Product
The physical pipeline (CI server, artifact registry, deployment tool) is infrastructure. The real product is the feedback loop speed. DORA research (covered in Lesson 5) shows that elite teams deploy on demand and restore service in under one hour. That speed is only achievable when every stage fails fast, fails loudly, and feeds the failure information back to the responsible team immediately.
Pipeline as Code
The pipeline configuration itself is stored in version control alongside the application code — typically as .github/workflows/ (GitHub Actions), .gitlab-ci.yml, or a Jenkinsfile. This means the pipeline has code review, history, rollback, and the same quality standards as the application. Pipelines managed through a UI only are a production risk: when the CI server dies, no one remembers how to recreate the jobs.
Minimal GitHub Actions CI pipeline (.github/workflows/ci.yml)
name: CI on: push: branches: [main] pull_request: jobs: build-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: 20 cache: npm - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Unit tests run: npm test -- --coverage - name: Build Docker image run: | IMAGE_TAG=$(git rev-parse --short HEAD) docker build -t myapp:$IMAGE_TAG . - name: Scan image for vulnerabilities uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} exit-code: 1 severity: CRITICALSummary
The Software Delivery Lifecycle moves a change through seven stages — Plan, Code, Build, Test, Release, Deploy, Operate — with feedback loops connecting each stage back to earlier ones. CI covers Code through Test and ensures every commit is verified within minutes. CD covers Release through Deploy and ensures verified artifacts reach production safely. The Operate stage closes the loop by feeding real-world signals back into the next plan cycle. As a DevOps engineer you own the automation, quality gates, and observability that make these loops fast enough to matter.