The launch went well, and now the system has to run for the next ten years. That is software maintenance, and it is where most of a system's life and most of its budget go.

This post opens our series on the phases of the software development life cycle. We start at the end, with the phase most guides rush through; the earlier phases have posts of their own: requirements analysis, the design phase and software testing.

What is software maintenance, and why does it matter?

Software maintenance is the process of updating, improving, and correcting a software application after its initial release to ensure its continued effectiveness and alignment with user needs and technological advancements.

Arkadiusz Drysch, CTO, Stratoflow

In practice it covers everything that happens to a system after its first release: fixing bugs, applying security patches, upgrading the runtime and libraries, adapting to new browsers, APIs and regulations, and adding the features users ask for once they actually use the product.

Why does it deserve its own plan? Because software decays even when nobody touches it. The code stays the same, but the world around it changes: a library gets a critical vulnerability, an operating system reaches end of support, a payment provider retires an API version. A system that is not maintained does not stay where it was; it falls behind.

The phases of the software development life cycle: planning, requirements, design, development, testing, deployment and maintenance. Maintenance is the last phase and the longest; it feeds new requirements back into the cycle. This article covers maintenance.THE SOFTWARE DEVELOPMENT LIFE CYCLEPlanningRequirementsDesignDevelopmentTestingDeploymentMaintenanceyou are herechange requests feed the next cycle
Maintenance is the last phase of the cycle and the one that never ends: what users ask for after launch becomes the input for the next round of changes.

Maintenance is also where the earlier phases pay off or send their bills. Clear requirements, a sound design and good tests make a system cheap to maintain; shortcuts taken before launch come back as maintenance work, with interest. The posts on requirements, design and testing show how.

The four types of software maintenance

The maintenance standard, ISO/IEC/IEEE 14764, names four classic types, and they fall into two groups: corrections, which fix what is wrong, and enhancements, which change what is right but no longer enough.

The four classic types of software maintenance in two groups. Corrections: corrective maintenance fixes faults found after release, and preventive maintenance fixes latent faults before they cause failures. Enhancements: adaptive maintenance keeps the software working as platforms, APIs and regulations change, and perfective maintenance improves and extends what users already have. In Robert Glass's figures, enhancement accounts for about 60% of maintenance cost and error correction for about 17%.FOUR TYPES OF MAINTENANCE, TWO GROUPSCORRECTIONS (ABOUT 17%)ENHANCEMENTS (ABOUT 60%)CorrectiveFix faults found after releasePreventiveFix latent faults before they hurtAdaptiveKeep up with new platforms, APIs, rulesPerfectiveImprove and extend what users haveShares of maintenance cost: Robert Glass, IEEE Software, 2001. The rest is not broken down.
The four types and the share of maintenance cost Robert Glass reported for corrections and enhancements (IEEE Software, 2001).

Corrective maintenance: fixing what broke

Bugs reported by users or caught by monitoring, from a crash that needs a hotfix tonight to a wrong total on a report that can wait for the next release. Corrective work is reactive by nature; the goal is to keep it small with good tests and fast feedback from production.

Preventive maintenance: fixing what is about to break

Finding latent problems before they cause failures: refactoring a fragile module, removing dead code, adding tests around code nobody dares to change, fixing the warning that will become an outage at ten times today's traffic. It is the type most often cut from budgets, and the one that makes the other three cheaper.

Adaptive maintenance: keeping up with the environment

Changes the system needs because the world around it changed: a new Java version, a database upgrade, a cloud migration, a partner's new API, a new regulation. For Java systems this has a calendar of its own; our Java end-of-life calendar lists when each version loses support.

Perfective maintenance: improving what users have

New features, better performance, a smoother workflow: everything users ask for once the product is in their hands. Despite the name "maintenance", this is where most of the money goes. In Robert Glass's summary of the research, enhancement accounts for about 60% of maintenance costs and error correction for about 17% (IEEE Software). Maintenance is mostly about adding new capability to old software, not about fixing it.

The software maintenance process, step by step

Whatever the type, a change to a live system goes through the same five steps. The difference between a calm maintenance practice and a chaotic one is mostly how seriously each step is taken.

1. Identify and analyze the problem

Every piece of work starts as a report: a bug, an alert, a vulnerability finding, a feature request, an end of support notice. The first job is to understand it: reproduce the bug, find the root cause rather than the symptom, and estimate the impact. A good analysis often shows that three reports are one problem.

2. Design the change

Decide how to make the change within the system's current architecture, and what else it touches. A fix that is quick to write but adds a special case nobody will remember is a future maintenance task in disguise.

3. Implement and test

Make the change and prove it works without breaking anything else. This is where an automated regression suite earns its keep: it is the only practical way to know that a change in one place did not quietly break another. Our overview of types of software testing covers which tests do what.

4. Deploy and monitor

Release the change, ideally through an automated pipeline, in small steps that can be rolled back, and watch production afterwards: error rates, latency, resource use and the business metrics the change was meant to affect. A change is not done when it is deployed; it is done when it has behaved in production.

5. Learn and improve

Close the loop. Write down what caused the problem and what would have caught it earlier, update the runbook, and feed recurring issues into the next round of preventive work. Teams that skip this step fix the same class of bug every quarter.

The costs of software maintenance

How much of a software budget goes to maintenance? Usually more than the budget that built the system.

The classic figure comes from Robert Glass's summary of software engineering research in IEEE Software: maintenance consumes about 40 to 80% of software costs, 60% on average (Glass, 2001). Over the life of a typical system, the first version is the smaller part of the bill.

Where the money goes over a system's life, using Robert Glass's figures: maintenance consumes 40 to 80 percent of software costs, 60 percent on average, so building the first version is about 40 percent of the total on average. Within maintenance, enhancement is about 60 percent and error correction about 17 percent.LIFETIME COST OF A TYPICAL SYSTEM, ON AVERAGEBuild the first versionabout 40%Maintenanceabout 60% (40 to 80% across systems)Enhancement 60%Fixes 17%Inside maintenance:Source: Robert Glass, IEEE Software, May 2001.
The split for an average system; the maintenance share ranges from 40% to 80% depending on how long a system lives and how much it changes.

What does that mean per year? A quick illustration, not a benchmark: a system that cost $1 million to build and runs for ten years with the average 60/40 split will need about $1.5 million of maintenance over that decade, or about $150,000 a year, roughly 15% of the original build cost every year. Systems that live longer, change faster or carry more technical debt sit at the high end of Glass's range.

Other measurements point the same way:

  • In Stripe's survey of developers, the average developer spent 17.3 hours of a 41.1-hour week on maintenance: dealing with bad code, debugging, refactoring and modifying existing code (The Developer Coefficient, 2018).
  • The US federal government spends more than $100 billion a year on IT, and agencies report spending about 80% of it on operations and maintenance of existing systems (GAO, 2025).

What drives maintenance costs up

  • Age and size: the longer a system lives and the bigger it gets, the more it costs to change.
  • Rate of change: a system the business changes every month costs more than one it leaves alone.
  • Dependencies: every framework, library and external API brings its own update schedule.
  • Technical debt: shortcuts from earlier phases come back as slower, riskier changes.
  • Missing tests and documentation: each change starts with archaeology.
  • Knowledge loss: when the people who built the system leave, the next team pays to relearn it.

The cheapest maintenance is the kind that is planned. A support budget agreed in advance, with a share reserved for preventive work, almost always costs less than a series of emergencies paid for one by one.

Software maintenance best practices

These are the practices we apply to every system we maintain, whether we built it or inherited it.

Eight good practices for software maintenance: know what you run, with an inventory of components and their support end dates; patch small and often, updating dependencies on a fixed rhythm; test before you touch, with regression tests guarding each change; watch production with alerts, dashboards and runbooks; release in small, automated and reversible steps; budget for maintenance as a fixed share of every sprint; write down why decisions were made, next to the code; and share the knowledge so no system is known by one person only.EIGHT SOFTWARE MAINTENANCE PRACTICES1Know what you runInventory with support end dates2Patch small and oftenDependencies on a fixed rhythm3Test before you touchRegression tests guard each change4Watch productionAlerts, dashboards and runbooks5Release in small stepsAutomated, reversible deployments6Budget for itA fixed share of every sprint7Write down the whyDecisions kept next to the code8Share the knowledgeNo system known by one person only
Eight practices that keep maintenance predictable. Each is explained below.

1. Know what you run

Keep an inventory of every component, with its version and the date it loses support: the runtime, the framework, the database, the operating system and the libraries. It turns surprise migrations into planned ones.

2. Patch small and often

Update dependencies on a fixed rhythm, monthly or with every release, rather than once a year. Small updates are boring; big-bang upgrades after three years of neglect are projects with their own risks.

3. Test before you touch

Before changing a part of the system without tests, add tests that pin down how it behaves today. Then change it. This single habit removes most of the fear from maintaining old code.

4. Watch production

Alerts on the things that hurt users, dashboards for the business metrics, logs you can search and a runbook for every alert. Problems found by monitoring are cheaper than problems found by customers.

5. Release in small, reversible steps

An automated pipeline, small releases and a rollback path make every change less dramatic. Feature flags help ship code before switching it on.

6. Budget for maintenance explicitly

Reserve a fixed share of every sprint or month for maintenance and preventive work, instead of squeezing it in between features. Glass's figures say the work will happen either way; budgeting decides whether it happens on your schedule.

7. Write down the why

Code shows what a system does; it rarely shows why. Keep short decision records and integration notes next to the code, so the next engineer knows which odd behavior is a bug and which is a requirement.

8. Share the knowledge

No system should be understood by one person only. Rotate who handles incidents, pair on unfamiliar parts and review each other's changes. It is the cheapest insurance against the most expensive maintenance problem.

Maintaining legacy systems, and how we do it

Maintenance gets harder as systems age. Once the runtime or framework falls out of support, routine patching turns into an upgrade project, and an upgrade project postponed long enough turns into a modernization. Our guide to legacy software systems covers how to live with old code, and legacy system modernization when living with it is no longer enough.

We have maintained business-critical Java systems for years at a time. FastPost, the accounting platform we developed for Legerity, was in production from 2013 and evolved by our team for nearly ten years (case study). For a wine merchant's fifteen-year-old store and back office, we moved the system from Java 17 to Java 25 in about four weeks, with no feature freeze (case study).

If you need a team to take over the maintenance of a Java system, our managed Java application support starts with a two to three week onboarding of your system, then agrees coverage, responsibilities and a monthly budget before support begins.