The tools were never the real problem. Two teams paid to want opposite things was the problem. Developers were rewarded for shipping change. Operations was rewarded for preventing it. Put those two groups on either side of a handoff and you do not get software delivery, you get a slow tug of war with production in the middle.
In Part 1 we defined DevOps as a way of working that shortens the distance between a code change and that change running live. This part is about the distance itself: what filled that gap before DevOps, why releases used to be terrifying, and what exactly broke. If you understand the disease, the rest of this series reads like the cure.
Here is a real shape of failure. A developer finishes a service, tests it on their laptop, and hands operations a build to deploy. Ops copies it up and restarts the service. Read the terminal from the top.
$ scp target/app.jar deploy@prod-web-01:/opt/app/app.jar
$ ssh deploy@prod-web-01 'sudo systemctl restart app'
Job for app.service failed because the control process exited with error code.
See 'systemctl status app.service' and 'journalctl -xeu app.service' for details.
$ ssh deploy@prod-web-01 'journalctl -u app -n 3 --no-pager'
app[24713]: Exception in thread main java.lang.UnsupportedClassVersionError:
app[24713]: com/acme/App has been compiled by a more recent version of the Java
app[24713]: Runtime (class file version 61.0), this Runtime recognizes up to 55.0
Nothing in the code was broken. Class file version 61 means the build used Java 17. Production still runs Java 11, which tops out at version 55. The handoff moved the jar file but not the environment it needed. The developer says it works on my machine, and they are telling the truth. That is the whole problem in one screen.
Before DevOps, development and operations were separate teams with clashing incentives. Work moved between them in big, rare handoffs, and each handoff dropped context: environment differences, undocumented steps, and no shared understanding of what changed. Releases were slow and scary, and when they broke, both sides blamed the other. DevOps attacks the handoff itself by giving both sides one goal and automating the steps that used to go wrong by hand.
If you are new to the field and have never sat through a bad production release, this part gives you the scars secondhand. Everything here is the reason the tools in later parts exist.
How work used to move
Picture the old model. Developers work for months on a release. When they judge it done, they package it and hand it to a separate operations team, often with a document describing how to install it. Ops has not seen the code, was not in the design discussions, and now has to deploy something they do not understand, usually during a weekend maintenance window. If it breaks, they are the ones awake at 2am, and the developer who wrote it is asleep.
This is the pattern the industry nicknamed throwing it over the wall. The wall is not a metaphor for a bad attitude. It is a real gap: different teams, different tools, different goals, and a single narrow handoff where all the context gets lost. The term DevOps was coined around 2009 precisely to name the fix for this split.
Why the two sides pull against each other
The conflict is not about personalities. It comes from how each side is measured. Give people a goal and they optimize for it, even when their goal fights the person across the table.
| Developers want | Operations wants | So the clash is |
|---|---|---|
| Ship features fast | Keep the system stable | Every change is a risk to uptime |
| Frequent releases | Fewer, controlled releases | Change gates and approval queues |
| Latest tools and versions | Known, proven versions | Environment drift between dev and prod |
| Move on to the next feature | Someone to own the running service | Nobody feels responsible after handoff |
Read the right column top to bottom. None of those clashes is anyone being lazy or difficult. Each is a rational team doing exactly what it was told to care about. That is why you cannot fix this with a stern email about collaboration. You have to change what both sides are on the hook for.
The four ways the handoff bites
1. Environment drift
The laptop and the server are never quite the same. Different runtime versions, missing libraries, different config. You saw it above with Java 17 against Java 11. Here is a version you can reproduce in ten seconds. Save this as drift.py:
match 2:
case 2:
print('the match statement ran')
Run it on a machine with Python 3.10 or newer and you get:
$ python3 drift.py
the match statement ran
Run the identical file on Python 3.9 or older and you get:
$ python3 drift.py
File "drift.py", line 1
match 2:
^
SyntaxError: invalid syntax
Same code, two machines, opposite results. The match statement arrived in Python 3.10. This is the tiny root of a thousand it works on my machine arguments, and containers exist mostly to kill it. We build those in Part 8.
2. Big-batch releases
When releases are rare, every release is huge. Months of changes ship at once, so when something breaks nobody can tell which of two hundred changes did it. A large batch is not just more work, it is exponentially harder to debug, because the number of possible interactions between changes explodes. Small, frequent changes are easier to reason about and safer to roll back.
3. Lost context
The person deploying did not write the code and was not in the room when decisions were made. They do not know the migration must run before the service starts, or that one setting has to change first. That knowledge lived in the developer head and did not survive the handoff.
4. Blame instead of learning
When an outage happens and two teams are involved, the meeting afterward becomes about whose fault it was. That is the worst possible outcome, because people who fear blame hide mistakes, and hidden mistakes cause the next outage. Healthy teams run blameless reviews that ask what in the system let this happen, not who did it.
What actually closes the gap
DevOps does not delete the handoff by wishing teams were friendlier. It attacks each cause directly. Shared ownership means the people who build a service help run it, so context does not get dropped. Small, frequent changes shrink the batch, so failures are easy to trace. Automation turns the fragile manual deploy into a repeatable pipeline that runs the same way every time. Blameless reviews turn outages into fixes instead of fights.
There is a strong reason to catch problems early, not late. A defect found while you are still writing the code costs almost nothing to fix. The same defect found in production costs far more: now there is an outage, users are affected, and you are debugging live under pressure. Every stage a bug survives multiplies the cost of fixing it, which is exactly why DevOps pushes testing and feedback as early as possible.
On a healthy team the deploy from the release-night story never happens that way. The build runs in a pipeline that uses the same runtime as production, so the Java 11 against Java 17 mismatch is caught in minutes on a test machine, not at 2am on a live server. The developer who wrote the service can see the pipeline result and fix their own build. No wall, no handoff, no 2am. That is not a tool doing magic. It is the environment and the ownership being shared.
The same feature, two worlds
Make it concrete. Say the task is to add a discount code field to a checkout page. Small feature, a day of coding.
The old world. The developer finishes on Tuesday and marks the ticket done. The change waits three weeks for the monthly release, bundled with forty other tickets. On release night ops runs a long checklist, hits the Java mismatch from earlier, and rolls the whole batch back at midnight because one unrelated change broke. The discount field, which was fine, ships a month late along with everything else. Nobody is sure which change caused the rollback, so the next release is even more cautious.
The DevOps world. The developer opens a change on Tuesday morning. A pipeline builds it against the same runtime production uses, runs the tests, and flags anything broken within minutes. A teammate reviews it, it merges, and it deploys on its own that afternoon behind a feature flag. If the discount logic misbehaves, the flag turns it off in seconds and only that one small change is in flight, so the cause is obvious. Same feature, same developer, same company. The difference is entirely in how the work moves.
Every practice in this series exists to turn the first story into the second. Keep that contrast in mind as we go, because it is the point of all of it.
The DevOps team trap, and why I push back on it
Here is my honest disagreement with how many companies adopt DevOps. They read that they need DevOps, so they create a new team called DevOps and route all the deployment work to it. It feels like progress. It is usually the old wall rebuilt with a fresh coat of paint.
Think it through. If developers still write code and toss it to a separate DevOps team to deploy, you have not removed the handoff. You added a third silo between dev and ops and gave it a trendy name. The people who wrote the code still do not own running it. This anti-pattern is well documented in the DevOps community, and it is the single most common way a DevOps effort quietly fails. A DevOps team can work if its job is to build the paved road, the shared pipelines and tools that product teams use to ship and run their own services. It fails when its job is to be the people you hand releases to.
So when you join a company and hear we have a DevOps team, ask one question: do the developers deploy and run their own services using that team platform, or do they hand work to that team? The answer tells you whether the wall is really gone.
What does throwing it over the wall mean, and why is it a problem?
Explain it as the old split where developers finished code and handed it to a separate operations team to deploy and run. The problem is lost context and clashing incentives: ops deploys code they did not write and cannot easily support, dev has no stake in whether it runs well, and failures turn into blame. Then land it by saying DevOps fixes the handoff through shared ownership and automation, not by adding another team.
Reproduce environment drift. Create the drift.py file from earlier. Run it with a modern Python, then install an older one and run the same file.
How to check: one run prints the match statement ran, the other throws a SyntaxError. You have just felt, on one machine, the exact reason a build can pass for a developer and fail in production.
You will meet the wall in disguise on almost any team. Maybe there is a ticket queue to get anything deployed, or a single gatekeeper who runs all releases. When you spot a slow, painful handoff, you now know it is not a personality problem, it is a structure problem. That framing makes you the person who suggests fixing the process rather than the person quietly cursing the other team. New engineers who think in systems get noticed fast.
A few things you might be wondering
Did operations teams just disappear? No. The operations work is still essential, someone has to think about reliability, capacity, cost, and security. What changed is that this work moved closer to the people building the software, and a lot of it became automated instead of manual.
Is the wall only a big-company problem? It shows up anywhere there is a handoff, even in a three person startup where one person writes code and another babysits the server. The smaller the team, the easier it is to fix, which is a good reason to build the right habits before you scale.
If small releases are safer, why did anyone do big ones? Because each release used to be expensive and risky, so teams batched changes to do fewer of them. It was a rational response to a painful process. Automation flips that math: once a release is cheap and safe, doing it often becomes the smart move.
Where does the cloud fit into all this? Cloud platforms let you create and destroy infrastructure through an API, which is what makes environments repeatable and automation possible. If that idea is new, the Cloud for Beginners series covers it from the ground up, and Python for Beginners builds the scripting you will lean on.
You now know the disease: clashing incentives, lossy handoffs, big scary releases, and blame. The rest of this series is the treatment, one practice and one tool at a time.
Coming up in Part 3: The DevOps lifecycle and a map of the whole toolchain, so you can see where every tool you will learn fits.
References
- DevOps Topologies, team structures and anti-patterns including the separate DevOps team
- Sonatype, What is DevOps and what it is not
- DORA, software delivery performance metrics


DrJha