Four modules on, Contoso Airlines' platform is complete: compute, data, networking, identity and governance. And yet every deployment is still an act of faith. Marta Ríos opens a Cloud Shell session on a Friday night, pastes in a batch of commands she keeps in a text file on her laptop, and hopes. Diego Salas has emailed her a ZIP with the latest version of Contoso Bookings and a note: "this is the good one, yesterday's had a bug". Nobody knows for certain which version is in production right now, and if something breaks at eleven at night the only way back is to hunt for the previous ZIP in an inbox.

This module gets rid of that scene. Azure DevOps is the set of services that turns software delivery into a repeatable, auditable and boring process — which is exactly what it should be. But before touching any tool you have to understand that DevOps is not a product you buy: it is a way of working that the tool enables, and confusing the two is the reason so many adoptions fail with the best tools installed.

Contents

  1. DevOps is culture before it is tooling: Contoso's silos
  2. Measuring improvement honestly: the DORA metrics
  3. What Azure DevOps Services is and its five services
  4. Organization, project and structure
  5. Azure Boards: making work visible
  6. Users, security groups and access levels
  7. Service connections: the bridge to Azure
  8. Azure DevOps versus GitHub
  9. The complete flow Contoso is going to build
  10. Common Mistakes and Tips
  11. Exercises
  12. Conclusion

  1. DevOps is culture before it is tooling: Contoso's silos

Look at how Contoso Airlines works today and you will see a textbook example of everything DevOps sets out to fix:

  • Diego develops on his laptop. His goal, as measured by his manager, is to ship features fast. When he is done, he "hands it over to ops".
  • Marta deploys on Friday nights. Her goal, as measured by her manager, is that the platform stays up. Every deployment is a risk, so she batches three weeks of changes into a single window to minimize the number of windows.
  • Nobody owns the outcome. If the website fails on Saturday, Marta restarts the application and calls Diego, who has no access to the production logs.

The result is a perfectly logical vicious circle: because deploying hurts, they deploy rarely; because they deploy rarely, each release accumulates many changes; because each release accumulates many changes, it is more likely to fail and harder to work out what broke it; because it fails, deploying hurts more. Both teams' incentives are opposed by design.

DevOps breaks that circle by inverting the intuition: deploying more often is safer, not riskier, because each deployment carries fewer changes and rolling it back is trivial. Culturally it demands three things no tool can buy for you:

Cultural principle What it means at Contoso What enables it in Azure DevOps
Shared responsibility Diego is accountable for his code in production, not up to the ZIP Environments, shared telemetry (module 7)
Automate the repetitive Nobody pastes commands by hand on a Friday Pipelines, infrastructure as code
Short feedback loops Knowing within 10 minutes whether a change breaks something Continuous integration, automated tests
Visible work Anyone can see what is being done and why Boards and its link to commits
Blameless failures You fix the process instead of hunting for the culprit Full traceability of what changed and when

  1. Measuring improvement honestly: the DORA metrics

If it is not measured, "we have adopted DevOps" is an opinion. The DORA research program (DevOps Research and Assessment) identified four metrics that predict the performance of a delivery team. Their virtue is that they are hard to game and that they balance each other out: two measure speed and two measure stability.

Metric What it measures Contoso today Target for this module
Deployment frequency How often code reaches production Every 3 weeks Several times a week
Lead time for changes From commit to production 18-24 days Under 2 days
Time to restore service How long it takes to recover from a failure 4-8 hours Under 30 minutes
Change failure rate What percentage of deployments cause incidents ~30% Under 15%

Two important warnings. First: you do not optimize just one. Deploying fifty times a day and breaking half of them is not improvement; the speed-stability pair is read together. Second: they are team metrics, not individual ones. The moment they are used to appraise Diego, Diego will learn to inflate them and they will stop meaning anything.

  1. What Azure DevOps Services is and its five services

Azure DevOps Services is Microsoft's SaaS offering for the full software lifecycle. There is also Azure DevOps Server, the version you install in your own data center — relevant only if some regulatory restriction rules out SaaS. In this course we always use Services.

It is not a monolithic product: it is five services that are enabled separately and can be used independently (it is perfectly valid to keep your code in GitHub and use only Azure Pipelines).

Service What it solves The Contoso problem it attacks Covered in
Azure Boards Planning and tracking work "Why was this change made?" 05-01 (this lesson)
Azure Repos Hosting private Git repositories The emailed ZIP and "the good one is yesterday's" 05-02
Azure Pipelines Building, testing and deploying The manual Friday-night deployment 05-03, 05-04
Azure Test Plans Managed manual and exploratory testing Business validation before the season opens Separate license
Azure Artifacts Hosting your own and third-party packages The shared library copied into three places 05-05

Azure Test Plans deserves a note: it requires an additional and fairly expensive per-user license, and it only pays off when there is a QA team running formal manual test plans. Contoso will not enable it; its tests will be automated and will live in the pipeline.

  1. Organization, project and structure

The hierarchy has three levels and it is worth deciding it well, because moving things later is awkward:

graph TD
    A["Organization: contoso-airlines<br/>dev.azure.com/contoso-airlines"] --> B["Project: contoso-reservas"]
    A --> C["Project: contoso-millas"]
    B --> D[Boards: work items]
    B --> E["Repos: contoso-reservas,<br/>contoso-api-disponibilidad,<br/>contoso-modelos, contoso-infra"]
    B --> F["Pipelines: CI and CD"]
    B --> G["Artifacts: contoso-paquetes feed"]
  • Organization: the billing and user container, with its own URL dev.azure.com/contoso-airlines. It is linked to a Microsoft Entra ID tenant — the same one from module 4 — so that access is governed by corporate identities and not by scattered personal accounts.
  • Project: the security and visibility boundary. Everything inside it is shared; what lives in another project is invisible unless permission is granted explicitly.
  • Repositories, pipelines, feeds: the artifacts inside the project.

The usual dilemma is one big project or many small ones. The practical recommendation — and the one Contoso follows — is few, large projects: one product, one project, with many repositories inside. Lots of small projects fragment the boards, force you to duplicate configuration and make sharing packages harder. Contoso creates contoso-reservas for the ticket sales platform and will keep contoso-millas (the exercise project, centro-coste=CC-2077) as a separate second product, because it has a different team, a different budget and a different cycle.

You create them from the portal (dev.azure.com), but also with the azure-devops extension of the CLI you already know well:

# Install the Azure DevOps extension for the CLI (once only)
az extension add --name azure-devops

# Set the default organization and project so you do not repeat them in every command
az devops configure --defaults organization=https://dev.azure.com/contoso-airlines

# Create the project: private, with Git as version control and the Agile process
az devops project create \
  --name contoso-reservas \
  --description "Contoso Airlines ticket sales platform" \
  --visibility private \
  --source-control git \
  --process Agile

# Set the default project as well
az devops configure --defaults project=contoso-reservas

--visibility private is non-negotiable: public opens the project to the internet with no authentication, which is designed for open source projects. --process Agile picks the work template we are about to look at and cannot be changed freely afterwards, so it is worth thinking about.

  1. Azure Boards: making work visible

Boards is where the why of every change lives. Without it, in six months nobody will remember why the Availability API caches fares for exactly 90 seconds.

Work items and hierarchy

A work item is any trackable unit: a feature, a bug, a task. They are organized in a hierarchy, and under the Agile process Contoso's looks like this:

graph LR
    E["Epic<br/>Online ticket sales"] --> F["Feature<br/>Seat selection"]
    F --> H["User story<br/>As a passenger I want to see<br/>the cabin map"]
    H --> T1["Task: map API<br/>Diego · 8 h"]
    H --> T2["Task: web component<br/>Diego · 6 h"]
    H --> T3["Task: Redis cache<br/>Diego · 4 h"]
    H --> B["Bug<br/>Occupied seats<br/>shown as free"]
  • Epic: a business objective, measured in months. "Online ticket sales on Azure".
  • Feature: a deliverable capability, measured in weeks.
  • User story: value for a user, measured in days. It is written in the form "As a role I want action so that benefit" and carries acceptance criteria: the concrete list of conditions that must be met for it to count as done. Without acceptance criteria, "finished" is an opinion.
  • Task: technical work measured in hours, which is what gets estimated and tracked day to day.
  • Bug: a defect. It can be treated as a story (appearing in the backlog alongside them) or as a task, depending on configuration.

Available processes

Process Main items Who it is for
Basic Epic → Issue → Task Small teams starting out; the simplest
Agile Epic → Feature → User story → Task The most common; teams using Kanban or lightweight Scrum
Scrum Epic → Feature → Product backlog item → Task Teams doing strict Scrum; it talks about impediments
CMMI Adds change requests, risks and formal reviews Heavily regulated environments with change auditing

Contoso picks Agile: it has recognizable vocabulary, supports both sprints and continuous flow, and does not impose the CMMI ceremony, which would be disproportionate for a team of seven.

Boards, sprints and queries

The board is the Kanban view: New → Active → Resolved → Closed columns that you drag cards across. Two settings make it genuinely useful:

  • Work in progress (WIP) limits: a maximum number of cards per column. If "Active" is full, nobody starts anything new until something moves. It is the most effective tool there is against the team that has fifteen things started and nothing finished.
  • Definition of ready and definition of done: written on the column itself, so that "resolved" means the same thing to Diego and to Marta.

Sprints (iterations) group work into fixed windows — Contoso uses two weeks — with per-person capacity and a burndown chart. Queries let you ask things like "open priority 1 bugs assigned to my team" and they feed the dashboards.

The link that gives you traceability

Here is the real value of Boards, and the reason it appears in this lesson rather than as a footnote. When Diego writes in his Git commit:

git commit -m "Fix available seat count on flights with an aircraft change

The cabin map used the flight's original configuration instead of
the aircraft assigned after the change.

Fixes AB#1842"

The AB#1842 reference makes Azure DevOps link the commit automatically to work item 1842 and, if the keyword is Fixes, close it on merge. From that point on the chain is complete:

work item → commit → pull request → build → deployed version → environment

That means the question "why is this line here?" and the question "what changes went into Tuesday's deployment?" both have automatic answers. When in 05-02 we configure the branch policy that requires a linked work item before you can merge, that chain stops depending on anybody's discipline.

  1. Users, security groups and access levels

Two concepts that get confused constantly and are worth separating from the outset:

  • Access level: which services a person can use. This is what gets billed.
  • Security group / permissions: what they can do inside them. This is free.
Access level What it includes Indicative cost
Stakeholder Full Boards (without advanced portfolio features), approving deployments; no access to code Free, unlimited
Basic Everything except Test Plans: Repos, Pipelines, Artifacts, Boards First 5 users free, then ~$6/user/month
Basic + Test Plans Adds Azure Test Plans ~$52/user/month
Visual Studio Subscriber Included with the Visual Studio subscription No additional cost

Cost warning: the five free Basic users are per organization, not per project. The classic mistake is giving Basic to everybody: Nuria Peña, from finance, only needs to see progress and approve spending, so Stakeholder is enough for her and costs nothing. Review access levels quarterly and free up those of people who no longer take part; billing will not do it for you.

The built-in security groups in every project are Readers, Contributors, Build Administrators and Project Administrators. Just as with RBAC in module 4, the rule is assign to groups, never to people, and — better still — have those Azure DevOps groups fed from the Microsoft Entra ID groups that already exist: Contoso-Desarrollo as Contributors, Contoso-Infraestructura as Project Administrators, Contoso-Operaciones as production approvers. A single employee onboarding in Entra ID gives them what they need on both planes.

  1. Service connections: the bridge to Azure

This section is the most important in the lesson for the rest of the module. A pipeline that deploys to Azure needs to authenticate against Azure. A service connection is that credential, stored in the project and referenced by name from the YAML.

There are two ways to set one up, and the difference is about security, not convenience:

Service principal with a secret Workload identity federation
What Azure DevOps stores A client secret Nothing: only a trust configuration
Expiry 1-2 years; the pipeline breaks the day it expires Never expires
Rotation Manual, and always forgotten Not applicable
If somebody exfiltrates the configuration They hold valid Azure credentials There is nothing to steal
Microsoft's recommendation Legacy The default

Federation works on the same principle as the managed identities from 04-02: instead of storing a password, a trust relationship is established between the Azure DevOps token issuer and a Microsoft Entra ID application. When the pipeline runs, Azure DevOps issues a short-lived token asserting "I am the run of pipeline X in project Y", Entra ID validates it against the configured trust and returns an access token for Azure. At no point does a secret exist that could leak or expire. It is the same "no keys, no passwords" idea that led Contoso to turn off allow-shared-key-access on its storage accounts, now applied to deployment.

Contoso creates two connections, and here the least privilege of module 4 is applied literally:

Service connection Scope of the role assignment Role Used by
sc-contoso-dev Resource group rg-contoso-reservas-dev Contributor Development pipelines
sc-contoso-pro Resource group rg-contoso-reservas-pro Website Contributor Deployment to production

Note two decisions. First, the scope is the resource group, not the subscription: the bookings pipeline has no reason whatsoever to be able to touch rg-contoso-red-pro or rg-contoso-seguridad-pro. Second, in production the role is Website Contributor rather than Contributor: the pipeline needs to deploy applications, not create databases or delete networks. When the Bicep pipeline in 05-06 needs to create infrastructure, it will get its own connection with more permissions and stricter approvals, instead of widening this one.

On top of that, service connections can be restricted to specific pipelines (by turning off the grant-access-to-all-pipelines permission), so that a new pipeline created by anybody does not automatically inherit the ability to deploy to production. We will see that in 05-04.

  1. Azure DevOps versus GitHub

Microsoft owns both, which generates legitimate confusion. Neither is going away, but product investment is clearly in GitHub.

Azure DevOps GitHub
Work management Boards: powerful, deep hierarchy, queries, sprints Issues and Projects: simpler and more flexible
Code Azure Repos (Git; TFVC legacy) The de facto standard of the ecosystem
CI/CD Azure Pipelines (YAML, very mature for enterprise deployments) GitHub Actions, with an enormous action marketplace
Packages Azure Artifacts, with very good upstream sources GitHub Packages
Code security Extensions and Defender for Cloud Advanced Security built in (native, paid)
Community and open source Scarce Its natural home
Microsoft investment Maintenance and occasional improvements Main focus

When to choose each, without kidding yourself:

  • Azure DevOps if you need enterprise work tracking with hierarchies and formal traceability, if you already have years of history inside it, or if your regulated environment demands self-hosted Azure DevOps Server.
  • GitHub if you are starting from scratch today, if your team already lives there, if the project is open source or if you want Advanced Security.
  • Both combined, which is very common: code and Issues in GitHub, deployment with Azure Pipelines for its maturity around environments, approvals and agents inside the virtual network.

Contoso chooses full Azure DevOps for one specific reason: it needs auditable traceability between requirement, change and deployment for its PCI DSS certification (04-05), and Boards gives it that with no extra work. What matters is that the concepts in this module transfer almost one to one to GitHub Actions: the syntax changes, not the idea.

  1. The complete flow Contoso is going to build

This is where the module is headed. Everything that follows is implementing this diagram.

graph TD
    WI["Boards<br/>Work item AB#1842"] --> DEV["Diego creates branch<br/>feature/1842-cabin-map"]
    DEV --> PR["Pull request<br/>into main"]
    PR --> POL{"Branch policies<br/>05-02"}
    POL -->|"2 reviewers + linked<br/>work item"| CI["CI pipeline<br/>05-03"]
    CI -->|"build, test,<br/>analyze"| ART["Pipeline<br/>artifact"]
    ART --> DES["Environment: desarrollo<br/>automatic deployment"]
    DES --> PRE["Environment: preproduccion<br/>App Service slot"]
    PRE --> APR{"Approval by<br/>Marta Ríos"}
    APR -->|approved| PRO["Environment: produccion<br/>slot swap<br/>05-04"]
    PRO --> MON["Monitoring<br/>module 7"]
    FEED["contoso-paquetes feed<br/>05-05"] -.-> CI
    BICEP["Bicep: infrastructure<br/>05-06"] -.-> PRO

Translated back to the scene at the start: Diego no longer emails any ZIP; Marta no longer pastes commands on a Friday; and the question "which version is in production" has an exact answer on the produccion environment screen.

Common Mistakes and Tips

  • Believing that installing the tool is adopting DevOps. If Diego still "hands things over to ops" and Marta is still the only person who can deploy, you will have the same silos with a prettier interface. Automation without a shift in responsibilities only speeds up the old process.
  • Creating one project per microservice. It multiplies configuration, fragments the boards and complicates sharing packages. One product, one project, many repositories.
  • Giving everybody the Basic level. It is the most frequent silent cost leak in Azure DevOps. Anyone who only reads or approves is fine on Stakeholder, and it is free.
  • Assigning permissions to people. Same as with RBAC: to groups, and ideally groups synchronized from Microsoft Entra ID.
  • Using service principals with secrets out of habit. They expire, and they always do so at the worst possible moment. Use workload identity federation from day one.
  • Giving the service connection subscription-level Contributor "so nothing fails". That is the equivalent of permanent sudo for anyone who can edit a YAML file. Minimum scope and minimum role.
  • Using the DORA metrics to appraise people. They become the target, stop measuring reality and poison the very culture they were meant to improve.
  • Tip: enable only the services you are going to use. A project with Boards, Repos, Pipelines and Artifacts enabled and Test Plans disabled is cleaner and avoids expensive licenses by accident.
  • Tip: write the definition of done on the board column itself before the first week is out. It is five minutes of work that saves months of arguments about what "resolved" means.

Exercises

Exercise 1: DORA diagnosis and a plan of attack

The Contoso Miles team (the exercise project, centro-coste=CC-2077) measures its four DORA metrics and gets: deployment frequency once a month, lead time 32 days, time to restore 6 hours, change failure rate 40%.

  1. Taken together, what do these four numbers tell you about the way they work?
  2. Which one would you attack first, and why?
  3. Which Azure DevOps service attacks each of the four?

Exercise 2: structure, licenses and connections

Contoso Miles joins the contoso-airlines organization. Its team is four developers, one infrastructure lead and Nuria Peña, who only wants to see progress and approve spending. They will deploy into the rg-contoso-millas-dev resource group.

  1. A new project or repositories inside contoso-reservas? Justify your answer.
  2. Assign an access level to each person and work out the approximate additional monthly cost, knowing that the organization already uses up its five free Basic licenses.
  3. Define the service connection: name, authentication type, scope and role.

Exercise 3: broken traceability

A PCI DSS audit. The auditor points at a change to the fare calculation deployed to production on 14 March and asks what business requirement drove it, who reviewed it and which version was deployed. All the team can show is a commit titled "fix fares" with no further context.

  1. Which specific links are missing from the traceability chain?
  2. List the three Azure DevOps mechanisms that would have answered this automatically.
  3. What specific configuration prevents this from happening again, and in which lesson of the module is it implemented?

Solutions

Solution 1:

  1. That they form a coherent circle: they deploy rarely because deploying is expensive and risky, so each release accumulates a month of changes, and that is why four out of ten fail and recovery takes six hours — there are too many suspect changes to sift through. The four metrics are symptoms of the same problem, not four problems.
  2. Time to restore, even though it seems counterintuitive. As long as recovery costs six hours, the team will be afraid to deploy and everything else is blocked. Bringing it down to minutes (automatic rollback, slot swap, 05-04) removes the fear, and with the fear gone frequency rises by itself and the rest of the numbers improve in cascade.
  3. Frequency and lead time: Pipelines (continuous integration and deployment) and Repos (short branches). Time to restore: Pipelines with environments and rollback, plus the monitoring from module 7. Change failure rate: Pipelines with automated tests and Repos with mandatory review enforced by a branch policy.

Solution 2:

  1. A new project contoso-millas: a different team, a different budget (CC-2077), a different delivery cycle and the need to keep its backlog from getting mixed up with the bookings one. The "few, large projects" rule applies within a product; here we have two distinct products. If they shared a team and planning, the answer would be repositories inside contoso-reservas.
  2. The four developers and the infrastructure lead need Basic (code and pipelines): that is five. Nuria Peña gets Stakeholder: she sees the work and can approve deployments, with no access to code, and it is free. Since the five free Basic licenses are already used up, the additional cost is 5 × ~$6/month ≈ $30/month. If Nuria were given Basic "just in case", it would be $36 with no extra capability she is ever going to use.
  3. Name sc-contoso-millas-dev; authentication via workload identity federation (no secret to expire or leak); scope the rg-contoso-millas-dev resource group, never the subscription; role Contributor in development, and a separate, more restricted connection for production when it arrives. On top of that, restrict the connection to the specific pipelines that need to use it.

Solution 3:

  1. Three are missing: the work item that explains the why of the change (requirement, acceptance criteria, who asked for it); the review by a second pair of eyes with its conversation record; and the relationship between the deployed version and the commit, which would let you state exactly which code was in production that day.
  2. (a) The commit-to-work-item link through AB#<id> in the commit message. (b) The pull request, which records reviewers, comments and decisions. (c) The Azure Pipelines environment, which stores which run and which artifact were deployed to produccion and when, with a link back to the commits included.
  3. A branch policy on main that simultaneously requires a linked work item, a minimum number of reviewers and a successful build validation; it is implemented in 05-02, and the per-environment deployment record in 05-04. The key point is that traceability stops depending on somebody remembering: without the three requirements, the merge simply is not allowed.

Conclusion

You have seen that DevOps is first and foremost a way of working: Contoso's silos — Diego handing over a ZIP, Marta deploying on Friday nights and nobody knowing what is in production — are not fixed by buying a tool, but by shifting responsibilities, automating the repetitive and shortening the feedback loops. And you have learned to measure that improvement honestly with the four DORA metrics, reading speed and stability together, and never using them to appraise people.

On that basis you have met Azure DevOps Services and its five services — Boards, Repos, Pipelines, Test Plans and Artifacts — you have created the contoso-airlines organization and the contoso-reservas project with the Agile process, and you have gone deep into Azure Boards: the epic → feature → user story → task hierarchy with its acceptance criteria, boards with work in progress limits, sprints and, above all, the AB#1842 link between commit and work item that makes traceability automatic. You have separated access levels (what gets billed) from permissions (what is free), knowing that Stakeholder covers anyone who only reads and approves, and that groups should come from Microsoft Entra ID. And you have built the bridge that will hold up the whole module: the service connections sc-contoso-dev and sc-contoso-pro, using workload identity federation instead of secrets that expire, with minimum scope and minimum role — module 4's discipline applied to delivery.

The flow is drawn, but it does not exist yet. And its first link is the most basic one and the one Contoso is missing entirely today: a single, reliable place where the code lives, with history, with review and with rules that do not depend on goodwill. In the next lesson, Azure Repos, you will create the contoso-reservas repository, migrate Diego's local repository preserving its history, choose the team's branching strategy and — most importantly — put policies on the main branch so that no change reaches production without review, without a linked work item and without a successful build. That is where the emailed ZIP disappears forever.

Azure Course

Module 1: Introduction to Azure

Module 2: Core Azure Services

Module 3: Azure Databases

Module 4: Security in Azure

Module 5: Azure DevOps

Module 6: Advanced Azure Services

Module 7: Monitoring and Management

Module 8: Cost Management and Optimization

Module 9: Case Studies and Best Practices

© Copyright 2026. All rights reserved