Efficient CI/CD Pipelines: Patterns and Antipatterns

NDC Conferences

Summary:

This video discusses common CI/CD pipeline antipatterns and suggests best practices to build efficient and less frustrating pipelines. The speaker outlines 9 antipatterns and corresponding patterns, focusing on reducing frustration, boredom, and environmental impact.

  • Antipattern 1: The Ritual – Running all steps all the time, regardless of relevance.
    • Pattern 1: The Right Pipeline for the Job – Tailor pipeline steps to specific situations (e.g., PR, merge, nightly).
    • Pattern 2: Conditional Pipeline Steps – Use logic to run only necessary steps based on changed modules.
  • Antipattern 2: Hoarding – Keeping all artifacts forever, leading to storage issues and poor discoverability.
  • Antipattern 3: The Aesthete – Ordering steps "naturally" instead of prioritizing faster feedback on failures.
    • Pattern 3: Fail Fast – Arrange steps to run the most failure-prone tasks earliest.
  • Antipattern 4: The One Pipeline – Using a single, long pipeline for everything, leading to long feedback loops.
    • Pattern 4: Parallel Pipelines – Split into multiple parallel pipelines and use temporary artifacts for dependencies.
  • Antipattern 5: Gift Wrapping – Using wrapper tasks instead of calling command-line tools directly, limiting flexibility.
    • Pattern 5: Composable Pipeline Library – Build reusable, composable actions, or define pipeline logic in scripts.
  • Antipattern 6: It's Complicated / Entangled – Making the pipeline its own complex software project, making it hard to change or migrate.
    • Pattern 6: Scripted Pipeline – Offload complex logic to platform-agnostic scripts (e.g., Makefiles, PowerShell).
  • Antipattern 7: Groundhog Day – Starting from scratch every time, neglecting caching opportunities.
    • Pattern 7: Caching – Implement dependency and build output caching to significantly speed up pipelines.
    • Pattern 8: Tooling Images – Bundle frequently used tools into cached Docker images for faster setup.
  • Antipattern 8: Interference – Colliding with other pipelines due to shared, non-unique resources (e.g., latest tags, hardcoded database names).
  • Antipattern 9: Overloading – Running pipelines on underpowered machines.
    • Pattern 9: Proper Build Agent Sizing – Ensure build agents are at least as powerful as the least powerful developer machine, or ideally the most powerful.
    • Run Your Own Agents (Pros/Cons) – Discusses pros (control, right-sizing) and cons (maintenance, scaling, cost) of self-hosted agents.
      Comparison of a single, monolithic pipeline (top) versus parallelized pipelines (bottom) for backend, frontend, and integration tests, showing a reduction in perceived runtime.
      Comparison of a single, monolithic pipeline (top) versus parallelized pipelines (bottom) for backend, frontend, and integration tests, showing a reduction in perceived runtime. [ 00:17:53 ]

Introduction to CI/CD Pipeline Efficiency [0:00:19]

The speaker, Daniel Raniz Raneland, shares his experience migrating and working with various company pipelines, highlighting common issues that lead to frustration, boredom, and environmental impact. The goal of the talk is to address these problems by presenting patterns and antipatterns.

Antipattern 1: The Ritual - Doing Everything All the Time [0:02:46]

This antipattern involves pipelines running the exact same steps regardless of the trigger or context (e.g., pull request, merge to main, nightly run).

Antipattern: The Ritual, showing the same steps (backend setup, lint, tests, frontend setup, lint, tests, integration tests, publish artifact) being run for PR, Merge, and Nightly pipelines, highlighting inefficiency.
Antipattern: The Ritual, showing the same steps (backend setup, lint, tests, frontend setup, lint, tests, integration tests, publish artifact) being run for PR, Merge, and Nightly pipelines, highlighting inefficiency. [ 00:05:16 ]

Problem Description [0:02:51]

Pattern 1: The Right Pipeline for the Job [0:05:36]

Pattern 2: Conditional Pipeline Steps [0:06:11]

Antipattern 2: Hoarding - Keeping All Artifacts Forever [0:10:15]

This antipattern involves indefinitely storing all produced artifacts (e.g., binaries, Docker images), which leads to storage issues and poor discoverability.

Problem Description [0:10:20]

Solution: Delete Regularly [0:12:33]

Antipattern 3: The Aesthete - Natural Instead of Practical Ordering [0:12:47]

This antipattern refers to structuring pipeline steps in a "natural" sequence (e.g., setup, lint, compile, unit test, integration test, end-to-end test) rather than an optimal one that provides faster feedback on failures.

Problem Description [0:12:56]

Pattern 3: Failing Fast [0:14:26]

Antipattern 4: The One Pipeline - One Pipeline to Rule Them All [0:15:04]

This antipattern is characterized by a single, monolithic pipeline that performs all tasks sequentially for all components (e.g., backend and frontend).

Problem Description [0:15:06]

Pattern 4: Parallel Pipelines [0:17:02]

Antipattern 5: Gift Wrapping - Using Wrapper Tasks to Execute Command-Line Tools [0:20:25]

This antipattern involves using generic wrapper actions or tasks (e.g., a GitHub Action that wraps cargo build) instead of directly invoking the underlying command-line tools.

Problem Description [0:21:08]

Pattern 5: Composable Pipeline Library (with Direct Tool Calls) [0:21:56]

Antipattern 6: It's Complicated - The Pipeline is its Own Software Project [0:23:56]

This antipattern occurs when pipeline logic becomes excessively complex, often written in a platform-specific language or library, making it difficult to understand, maintain, or migrate.

Problem Description [0:24:02]

Pattern 6: Scripted Pipeline [0:28:39]

Antipattern 7: Groundhog Day - Starting from Scratch All the Time [0:31:32]

This antipattern refers to pipelines that always perform a full, clean build, reinstalling all dependencies and recompiling everything, even if nothing relevant has changed.

Problem Description [0:31:43]

Pattern 7: Caching [0:33:14]

Pattern 8: Tooling Images [0:39:16]

Antipattern 8: Interference - Colliding with Other Pipelines [0:40:51]

This antipattern occurs when multiple pipelines or concurrent runs interact negatively due to shared, non-unique resources or identifiers.

Problem Description [0:40:54]

Solution: Unique Identifiers [0:41:50]

Antipattern 9: Overloading - Running on Underpowered Machines [0:42:36]

This antipattern involves provisioning CI/CD build agents with insufficient hardware resources, leading to slow pipeline execution and developer frustration.

Problem Description [0:42:39]

Raniz's Rules of Thumb for Build Agent Sizing [0:42:51]

  1. Minimum Power: The build agent should be at least as powerful as the least powerful developer machine.
  2. Ideal Power: Ideally, the build agent should be as powerful as the most powerful developer machine. This makes CI faster than local builds, encouraging developers to rely on it.
  3. Beef Up Resources: If a build fails due to resource limitations (e.g., memory), the quickest and often cheapest fix is to simply give the build agent more resources (RAM, CPU).
  4. Custom Configurations: If available build agent configurations are insufficient, consider rolling your own agents.

Should You Run Your Own Agents? (Pros and Cons) [0:44:17]

Pros and Cons of running your own build agents, detailing advantages like full control and right-sizing, versus disadvantages like maintenance, scaling, and potential cost.
Pros and Cons of running your own build agents, detailing advantages like full control and right-sizing, versus disadvantages like maintenance, scaling, and potential cost. [ 00:46:51 ]

What's Next in CI/CD Pipelines? [0:47:27]

The speaker mentions two emerging tools: Dagger and Earthly.