Article
Card image cap for article

DevOps Theory and Implementation with Azure DevOps

Medical Devices

5/25/2026

Motivation

More than five years ago, I read the seminal book Continuous Delivery by Jez Humble and David Farley [1], and it impressed me with its promise: deliver software quickly, safely, and repeatedly through automation and disciplined engineering practices.

Yet, despite my interest, I did not truly understand the depth of the concept or fully grasp its practical advantages at that time. The ideas felt compelling on paper, but they remained mostly theoretical for me, far away from my semi-professional coding.

This changed only when I decided to implement DevOps principles in a concrete way for my own web project, which is publicly available at dirkmueller8.com. By setting up automated builds, tests, and deployments, I could observe firsthand how faster feedback, reduced manual work, and a more reliable release process transformed the way I develop and operate software. Concepts that had seemed abstract in the book suddenly became tangible, measurable improvements in my personal workflow.

The purpose of this article is therefore not to stay at the conceptual level, but to bridge the gap between theory and practice using a real web application as an example. I want to demonstrate how the principles described in Continuous Delivery can be translated into concrete pipelines, tools, and daily routines, even for a single-developer project.

Continuous Integration and Continuous Delivery (CI/CD)

Manual Deployment from the Past

When I first built my web application with the ASP.NET Core MVP framework, my workflow looked like this: I coded in Visual Studio, ran my unit and integration tests manually, and then deployed the application to the hosting server via FTP using FileZilla.

This setup worked, but every release felt fragile and error-prone. A single forgotten file, a missed configuration change, or a skipped test could easily introduce defects into production. More importantly, there was no real traceability: if something went wrong, it was hard to reconstruct what exactly had been deployed and why.

This "before" state is — as far as I have read and talked to others — still the everyday reality for many development teams and solo developers. Manual steps dominate the process, and success depends heavily on individual discipline rather than on a robust system. While this approach might be acceptable for very low-risk projects, it does not scale in terms of quality, security, or speed. As requirements grow and expectations for uptime and security increase, the limitations of ad-hoc deployment strategies become visible.

Azure DevOps as the Bridge

Azure DevOps became my bridge from this manual world to an automated, reliable delivery process. Instead of relying on my memory and a checklist, I started to encode the entire flow — from code commit to deployment — into a defined CI/CD pipeline.

Azure DevOps provided me with a place to version my code, define build and release pipelines, run automated tests, and track work items, all in a single environment. The same steps that I used to perform manually in Visual Studio and FileZilla became scripted, repeatable tasks executed on every change.

The pipeline offers the following advantages:

  • Repeatable — every deployment follows the same path, which greatly reduces the chance of human error.
  • Auditable — every run is logged, with clear information about who triggered it, which commit was deployed, and which tests were executed.
  • Secure — secrets are managed centrally, access is controlled, and the pipeline itself can enforce security checks before anything reaches production.

Every Change Triggers the Pipeline

As Jez and David write in their book:

"Every change that is made to an application's configuration, source code, environment, or data, triggers the creation of a new instance of the pipeline."

"It improves feedback so that problems are identified, and so resolved, as early in the process as possible."

"Releases should be boring, even in complex 'enterprise' environments. Software release can — and should be — a low-risk, frequent, cheap, rapid, and predictable process."

Only then, when the developer is nudged into updating the OS, software, and dependencies on a weekly or even daily basis, does the power of DevOps become fully evident.

Dependencies and Supply Chain Risk

In this context, dependencies are the external libraries and components that almost any application relies on so that its own code can run correctly and provide all intended functionality. There can be dozens or even hundreds of them in web projects.

An important side effect of DevOps is that staying up to date with dependencies becomes much easier. In a manual setup, updating libraries is often postponed because each update feels risky and expensive. With an automated pipeline and frequent small updates, dependency changes become routine: you bump a version, the pipeline builds, tests, and deploys, and you quickly see whether everything still works.

Addressing Vulnerabilities Immediately

This is a key element in defending against software supply chain risks, where vulnerabilities or malicious code can enter through third-party libraries [2].

High-profile incidents in popular package ecosystems — such as attacks in the npm ecosystem that impacted a large number of web projects [3] — have shown how quickly such supply chain issues can spread and how important it is to update dependencies regularly and verify them with automated checks.

SonarCloud

Azure DevOps integrates with static analysis tools such as SonarCloud, and these can be embedded directly into the CI/CD pipeline. This gives rise to a new element in the DevOps concept: DevSecOps. See my article on DevSecOps and Shift-Left here: Automation and Shift-Left of the Software Security Life Cycle Prior to Release to Market.

Example DevOps Pipeline Case

In this article, I will show how this transformation looks in practice for my publicly available web project at dirkmueller8.com.

Communication between GitHub and Azure DevOps

To set up Azure DevOps for my project, I first decided to keep my existing development workflow in Visual Studio and continue committing and pushing my code to a private repository on GitHub. This allowed me to preserve a familiar environment while preparing the foundation for a more professional delivery pipeline.

Next, I created a new project in Azure DevOps and connected it to my GitHub repository. To keep both systems synchronized without manual intervention, I set up an automation so that changes in GitHub are reflected in Azure DevOps. For this, I used a GitHub Action [4] by introducing a mirror.yml file in my project:

Whenever I push new commits, it updates the corresponding Azure DevOps repo using secure access tokens. These tokens act like time-limited, revocable keys that allow the automation to talk to Azure DevOps on my behalf without exposing my real credentials.

With this setup, my workflow became much smoother: I write code in Visual Studio, commit and push to GitHub as usual, and in the background the GitHub Action ensures that Azure DevOps always has the latest version of the repository. This means that my Azure DevOps pipelines can run on the most recent code without me having to manually copy or synchronize anything. It is a small technical change, but it is the crucial link that turns my GitHub-based development into a foundation for a fully automated DevOps pipeline.

Creating the Pipeline in Azure DevOps

In my Azure DevOps pipeline, every push to the main branch triggers a fully automated build, test, and deployment process for my web application. The pipeline restores all project dependencies, runs the tests before deployment, and only proceeds to deployment if all tests pass. Before updating the site, it automatically stops the IIS website and its application pool so that files can be replaced safely without locked-file issues.

The application is then built and published to a temporary folder, and a scripted robocopy step mirrors the changes to the live web folder while deliberately preserving sensitive configuration files on the server. Finally, the pipeline restarts the IIS application pool and website, bringing the updated version of the application online without any manual intervention.

The following YAML file — sanitized by replacing real paths with generic placeholders for security — defines the Deployment-as-Code pipeline.

Running the Azure DevOps Pipeline

Azure DevOps shows detailed, near real-time logs for each pipeline run, so it is easy to follow the process. At the end you get an informative summary of failed and successful runs.

Adding SonarCloud to the CI/CD Pipeline

SonarQube Cloud [5] is a SaaS platform for static code analysis that automatically detects code issues, code smells, security vulnerabilities, and risky dependencies in your projects.

I had no high-severity cases, but quite a lot at the medium level which still required refactoring and corrections. After half a day of work, I was able to address all 414 medium issues, ensuring clean source code and configuration data.

Learning Curve

The learning curve for DevOps pipelines is quite steep, and it includes trial and error. CI/CD pipelines sometimes fail with cryptic or unexpected errors, and troubleshooting them can be challenging. Issues may come from tooling, infrastructure, permissions, or subtle YAML mistakes rather than the actual application code.

Azure DevOps helps by showing detailed, near real-time logs for each pipeline run, so you can see exactly which step and script line is currently executing and where it stopped. With some patience, iterating on the YAML and carefully reading the logs usually reveals the root cause, even if it takes a few attempts.

Final Result

The reward for this initial effort is significant: once a pipeline runs successfully end-to-end, every future deployment follows the same automated path and becomes consistent, predictable, and much easier to trust.

Had I done this manually, it would have taken at least 15 minutes because there are nearly ten individual steps and I would have needed to stay focused the entire time. With the DevOps pipeline, the same process now completes in just over one minute.

Conclusion

For me, DevOps only became real when I implemented it in a small but public web project. What began as an effort to automate deployment evolved into a repeatable, auditable, and more secure way of working. Even for a single-developer project, Azure DevOps turned releases from a fragile manual task into a predictable engineering process.

References

  1. Humble, J. & Farley, D. (2011). Continuous Delivery: Reliable Software Releases through Build, Test and Deployment Automation. Addison-Wesley.
  2. Raj, K. The Bitwarden CLI Supply Chain Attack: What Happened and What to Do. Endor Labs. endorlabs.com
  3. Girnus, P. & Santos, J. Axios NPM Package Compromised: Supply Chain Attack Hits JavaScript HTTP Client with 100M+ Weekly Downloads. Trend Micro. trendmicro.com
  4. GitHub. GitHub Actions — Quickstart. docs.github.com
  5. SonarSource. SonarQube Cloud SaaS. docs.sonarsource.com

Go back