AZ-400: Designing and Implementing Microsoft DevOps Solutions

Design and Implement Pipelines

Maintainability

Maintainability is often overlooked but it’s a critical factor in the long-term success of your CI/CD lifecycle. By emphasizing maintainability, you future-proof your DevOps processes, reduce technical debt, and enable teams to iterate faster. Azure Pipelines offers built-in features and best practices to help you design, manage, and evolve pipelines that stand the test of time.

The image shows a person interacting with gears containing the Azure Pipelines logo, alongside text introducing Azure Pipelines as a tool for CI/CD with a focus on maintainability.

Why Maintainability Matters

  • Speeds up onboarding for new team members
  • Simplifies troubleshooting and updates
  • Enables consistent compliance with internal standards
  • Supports scalable, repeatable deployments

Note

Investing in maintainability reduces downtime and accelerates feature delivery.


Core Pillars of Maintainable Pipelines

The image outlines the key components of maintainable Azure Pipelines: Code Reusability, Modular Design, and Documentation.

PillarDescription
Code ReusabilityLeverage templates and variable groups to avoid duplication.
Modular DesignBreak pipelines into stages, jobs, and templates for clear separation of concerns.
Comprehensive DocumentationUse inline comments, README files, and parameter descriptions to clarify pipeline intent.

Defining your pipeline in YAML unlocks version control, peer reviews, and automated validation—key enablers for these pillars.


Best Practices for Pipeline Maintainability

The image outlines three best practices for enhancing maintainability: using naming conventions, implementing version control, and regularly refactoring the pipeline.

  1. Consistent Naming Conventions
    Use clear, descriptive names for pipelines, stages, jobs, tasks, and variables.
  2. Version Control Everything
    Store YAML definitions and templates in Git to track changes and enable rollbacks.
  3. Regular Refactoring
    Periodically review pipelines to remove redundancy and simplify complex logic.

Key Azure Pipelines Features

FeatureBenefitReference
Pipeline-as-codeFull integration with your Git repoYAML schema
TemplatesReusable components for uniform practicesTemplate syntax
Variable GroupsCentralized management of secrets and settingsVariable groups
trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

variables:
- group: MyVariableGroup

steps:
- script: dotnet build MySolution.sln
  displayName: 'Build solution'

Refactoring for a Scalable Pipeline

A monolithic YAML file can quickly become unwieldy. Let’s transform a single-file pipeline into a modular, stage-driven configuration.

The image is a diagram outlining a practical example of refactoring a pipeline for better maintainability, with three steps: before and after refactoring, step-by-step refactoring process, and key takeaways.

Original Monolithic Pipeline

trigger:
- main

pool:
  vmImage: 'windows-latest'

steps:
- script: dotnet build MySolution.sln
  displayName: 'Build solution'

- task: DotNetCoreCLI@2
  inputs:
    command: 'publish'
    publishWebProjects: true
    arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: true

- task: PublishBuildArtifacts@1
  inputs:
    PathToPublish: '$(Build.ArtifactStagingDirectory)'
    ArtifactName: 'drop'
    publishLocation: 'Container'

- script: |
    echo Deploying to staging environment
    # Mock deployment script
  displayName: 'Deploy to Staging'

Warning

Monolithic pipelines are hard to debug and scale. Breaking them into stages and templates greatly improves clarity.

Refactored Pipeline

trigger:
- main

stages:
- stage: Build
  jobs:
  - template: templates/build.yml
    parameters:
      solution: 'MySolution.sln'

- stage: Deploy
  jobs:
  - template: templates/deploy.yml
    parameters:
      environment: 'staging'

Build Template (templates/build.yml)

parameters:
  solution: ''

jobs:
- job: BuildJob
  pool:
    vmImage: 'windows-latest'
  steps:
  - script: dotnet build ${{ parameters.solution }}
    displayName: 'Build solution'

  - task: DotNetCoreCLI@2
    inputs:
      command: 'publish'
      publishWebProjects: true
      arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)'
      zipAfterPublish: true

  - task: PublishBuildArtifacts@1
    inputs:
      PathToPublish: '$(Build.ArtifactStagingDirectory)'
      ArtifactName: 'drop'
      publishLocation: 'Container'

Deploy Template (templates/deploy.yml)

parameters:
  environment: ''

jobs:
- job: DeployJob
  pool:
    vmImage: 'windows-latest'
  steps:
  - script: |
      echo Deploying to ${{ parameters.environment }} environment
      # Mock deployment script
    displayName: 'Deploy to ${{ parameters.environment }}'

The image lists the benefits of refactoring, highlighting modularity, clarity, flexibility, and maintenance with corresponding icons.

Refactoring Benefits

  • Modularity: Independent templates for build and deploy phases.
  • Clarity: Stages and parameters make pipeline flow explicit.
  • Flexibility: Reuse templates across different projects and environments.
  • Maintainability: Smaller, focused files are easier to update and debug.

References

Watch Video

Watch video content

Previous
Connectivity