12.3.6 Maintaining and Extending Existing Software
Releasing a program does not end its development. Faults may be discovered, requirements may change and the internal design may become difficult or inefficient. Developers therefore continue to analyse, modify and test software throughout its useful life.
The reason for a change determines its maintenance category. Corrective maintenance repairs a known fault. Adaptive maintenance responds to a changed requirement or environment. Perfective maintenance improves the quality, performance or maintainability of software that already behaves correctly.
By the end of this section, you should be able to:
- Explain why software requires continuing maintenance.
- Distinguish corrective, adaptive and perfective maintenance.
- Classify a change from the reason it is required.
- Describe a systematic corrective-maintenance process.
- Carry out an impact analysis for a changed requirement.
- Explain how refactoring can improve maintainability.
- Explain how a change can improve performance.
- Analyse existing pseudocode and amend it to extend functionality.
- Explain why changed software requires retesting and regression testing.
Why Software Requires Continuing Maintenance
Software does not physically wear away, but the conditions surrounding it do not remain fixed. New inputs, new devices, changed working practices and previously unseen paths may all reveal a need for change.
| Reason for continued work | Example | Likely response |
|---|---|---|
| A fault is reported. | An irrigation recommendation is wrong when soil moisture is exactly 18%. | Locate and correct the fault. |
| A requirement changes. | The allotment must now follow weekly water-restriction rules. | Extend the program to support the new rule. |
| The operating environment changes. | The dashboard must run on handheld devices used outdoors. | Adapt the interface and input handling. |
| The code becomes difficult to change. | The same moisture-validation code appears in several modules. | Refactor the repeated logic. |
| Performance becomes unacceptable. | Every screen refresh scans the complete sensor-history file. | Improve how the latest reading is found. |
The Three Maintenance Types
| Type | Main reason for the change | Question to ask | Allotment example |
|---|---|---|---|
| Corrective | An identified fault must be repaired. | Is the current program producing incorrect behaviour? | Moisture of exactly 18% receives the wrong watering duration. |
| Adaptive | The requirements or operating environment have changed. | Must the program now do something different or work somewhere new? | The scheduler must apply water-restriction rules. |
| Perfective | A working system is improved in quality, structure, maintainability or performance. | Does the behaviour remain essentially the same while the implementation improves? | Repeated validation is moved into one reusable function. |
Corrective Maintenance
The fault may be a logic error or a run-time error. It may affect every execution, or it may appear only under a particular combination of data and conditions.
| Reported symptom | Possible underlying cause | Evidence needed |
|---|---|---|
| Incorrect recommendation | Wrong comparison operator or formula | Input, expected result and actual result |
| Program stops | Invalid array position or arithmetic operation | Error message, call sequence and data |
| Program does not terminate | Loop-control variable is not updated correctly | Repeated variable values and loop condition |
| Stored data becomes inconsistent | Only one of several related records is updated | Database state before and after the action |
Why faults may appear after release
- The faulty path is rarely selected.
- The fault requires an unusual combination of valid data.
- A limit or boundary was not tested.
- The production environment differs from the test environment.
- A previous change introduced a regression.
- A large data volume exposes a problem that small test files did not reveal.
A Corrective-maintenance Process
- Record the report. Capture the program version, environment, user actions, input, expected result and actual result.
- Reproduce the fault. Repeat the reported conditions in a controlled environment.
- Reduce the failing case. Remove irrelevant actions or data until the smallest repeatable example remains.
- Locate the first incorrect state. Use traces, logging, breakpoints or watched variables.
- Identify the root cause. Do not assume that the visible symptom is the faulty statement.
- Design the correction. Consider which modules, interfaces and stored data may be affected.
- Implement the smallest safe change. Avoid unrelated edits during the correction.
- Retest the original failure. Confirm that the reported behaviour is now correct.
- Run regression tests. Check nearby boundaries and related existing behaviour.
- Update records and release the correction. Record the changed version, test evidence and deployment decision.
Original fault example
The requirement for an irrigation scheduler is:
- moisture below 18% β 24 minutes;
- moisture from 18% to 35% inclusive β 12 minutes;
- moisture above 35% β no watering.
The existing condition is:
IF Moisture <= 18 THEN
RETURN 24
ELSE
IF Moisture <= 35 THEN
RETURN 12
ELSE
RETURN 0
ENDIF
ENDIF
At exactly 18%, the first condition is true, so the function returns 24 rather than 12. The comparison should be:
IF Moisture < 18 THEN
| Moisture | Expected before correction | Actual before correction | Retest after correction |
|---|---|---|---|
| 17 | 24 minutes | 24 minutes | Pass |
| 18 | 12 minutes | 24 minutes | Pass after correction |
| 19 | 12 minutes | 12 minutes | Pass |
| 35 | 12 minutes | 12 minutes | Pass |
| 36 | 0 minutes | 0 minutes | Pass |
Adaptive Maintenance
The original program may be correct according to its original specification. The change is needed because the required behaviour or operating context is now different.
| Source of change | Allotment example | Possible adaptation |
|---|---|---|
| New organisational rule | Watering is restricted on selected weekdays. | Add restriction-day data and scheduling decisions. |
| New user need | Gardeners want recommendations for seedlings and established plants. | Add a plot-stage field and different duration rules. |
| New external service | A rainfall forecast becomes available. | Connect the scheduler to forecast data. |
| New operating environment | Staff need to use the system on outdoor tablets. | Adapt layout, controls and offline behaviour. |
| Changed data format | A sensor now transmits a decimal percentage rather than an integer. | Update interfaces, validation and storage. |
Impact Analysis Before Adaptation
A feature that appears small at the user interface may require changes to data, modules, interfaces, files, tests and documentation.
Change request
| Affected area | Possible change | Question to answer |
|---|---|---|
| Requirements | Define emergency and non-emergency restriction behaviour. | Are the limits inclusive? |
| Input | Add RestrictionActive. |
Who sets the value and when does it change? |
| Processing | Add restriction decisions after the normal recommendation. | Which rule takes priority? |
| Module interface | Pass the new Boolean parameter to the recommendation function. | Which callers must be updated? |
| Stored data | Record whether a recommendation was restricted. | Is a new record field needed? |
| Output | Explain when the normal duration has been reduced. | What message should the user see? |
| Tests | Add restriction and emergency cases. | Which existing tests must still pass? |
| Documentation | Update user instructions and module descriptions. | Which documents describe the old behaviour? |
Perfective Maintenance
Perfective maintenance generally preserves the required external behaviour. The improvement is mainly in quality, internal structure, maintainability or performance.
| Working-system issue | Perfective change | Benefit |
|---|---|---|
| Moisture validation is repeated in several modules. | Create one reusable validation function. | One rule and message need to be maintained. |
| One procedure performs input, calculation, storage and output. | Split it into focused modules. | Each responsibility can be understood and tested separately. |
Identifiers such as x1 and v are unclear. |
Rename them to express their purpose. | Future developers can follow the algorithm more easily. |
| The full history file is scanned for every plot display. | Maintain direct access to each plotβs latest reading. | Fewer records need to be examined. |
| The same conversion is repeated several times in one request. | Calculate once and reuse the result where safe. | Unnecessary processing is reduced. |
Improving Maintainability
Maintainability can be improved by:
- using meaningful identifiers;
- dividing long routines into focused modules;
- reducing duplicated code;
- using parameters rather than unnecessary global variables;
- keeping module interfaces clear and limited;
- using consistent coding and documentation conventions;
- removing unreachable or obsolete code;
- adding suitable comments that explain purpose or non-obvious decisions;
- maintaining automated regression tests where available.
Repeated validation before refactoring
REPEAT
INPUT Moisture
IF Moisture < 0 OR Moisture > 100 THEN
OUTPUT "Enter a percentage from 0 to 100"
ENDIF
UNTIL Moisture >= 0 AND Moisture <= 100
REPEAT
INPUT ReservoirLevel
IF ReservoirLevel < 0 OR ReservoirLevel > 100 THEN
OUTPUT "Enter a percentage from 0 to 100"
ENDIF
UNTIL ReservoirLevel >= 0 AND ReservoirLevel <= 100
After refactoring
FUNCTION GetPercentage(
BYVALUE Prompt : STRING
) RETURNS INTEGER
DECLARE Value : INTEGER
REPEAT
OUTPUT Prompt
INPUT Value
IF Value < 0 OR Value > 100 THEN
OUTPUT "Enter a percentage from 0 to 100"
ENDIF
UNTIL Value >= 0 AND Value <= 100
RETURN Value
ENDFUNCTION
Moisture β GetPercentage("Enter soil moisture")
ReservoirLevel β GetPercentage("Enter reservoir level")
Improving Performance
Performance improvements may reduce execution time, memory use, file access or network activity. The changed version must still produce the required results.
| Current approach | Possible improvement | Measure to compare |
|---|---|---|
| Scan every historical reading to find the latest value. | Maintain a direct latest-reading record for each plot. | Records examined and response time |
| Open and reread the same configuration file for every calculation. | Load the configuration once when appropriate. | File operations and elapsed time |
| Calculate the same daily summary for every screen component. | Calculate once and pass the result to each component. | Number of repeated calculations |
| Load all plot histories when one plot is requested. | Retrieve only the requested plotβs data. | Memory use and data-transfer volume |
Comparing the Maintenance Types
| Scenario | Type | Reason |
|---|---|---|
| Exactly 18% moisture receives 24 minutes rather than 12. | Corrective | The current program violates its existing requirement. |
| The scheduler must now obey a weekly water-restriction rule. | Adaptive | The required functionality has changed. |
| Repeated validation is moved into one function. | Perfective | The required behaviour remains the same, but maintainability improves. |
| The program must run on a new outdoor tablet platform. | Adaptive | The operating environment has changed. |
| A full-file search is replaced by indexed access. | Perfective | Working software is made more efficient. |
| A previous release sometimes stores the wrong plot identifier. | Corrective | An identified fault must be repaired. |
A quick classification method
- Identify the behaviour before the change.
- Identify the reason a change is requested.
- Ask whether an existing requirement is currently violated.
- Ask whether the requirement or environment has changed.
- Ask whether external behaviour is preserved while internal quality improves.
- Select the type and justify it using the reason.
Managing a Maintenance Change
Maintenance should follow a controlled process. Editing a released system without understanding the impact can introduce new faults.
| Stage | Main activity | Evidence produced |
|---|---|---|
| 1. Request or fault report | Record why a change is needed. | Change request or defect report |
| 2. Classification | Identify the maintenance type and priority. | Reasoned category and severity |
| 3. Impact analysis | Identify affected requirements, modules, interfaces, data and tests. | Impact list and risk assessment |
| 4. Design | Plan the amended behaviour and structure. | Updated algorithms, interfaces or data design |
| 5. Implementation | Change a controlled version of the code. | Version-controlled source changes |
| 6. Testing | Run new, direct-retest and regression cases. | Expected and actual test results |
| 7. Review and approval | Confirm that the change is safe to release. | Review decision or approval |
| 8. Deployment | Release the changed version and monitor it. | Version, release notes and monitoring evidence |
Analysing and Extending an Existing Program
Consider the original working function:
FUNCTION RecommendMinutes(
BYVALUE Moisture : INTEGER
) RETURNS INTEGER
IF Moisture < 18 THEN
RETURN 24
ELSE
IF Moisture <= 35 THEN
RETURN 12
ELSE
RETURN 0
ENDIF
ENDIF
ENDFUNCTION
New requirement
A new Boolean parameter named RestrictionActive must be supported:
- when no restriction is active, preserve the existing behaviour;
- during a restriction, a normal recommendation is limited to eight minutes;
- during a restriction, moisture below 10% is an emergency and receives twelve minutes;
- a recommendation of zero remains zero.
Step 1: preserve the original calculation
First calculate the existing recommendation. This reduces duplication and makes it easier to verify that unrestricted behaviour has not changed.
Step 2: apply the new rule
FUNCTION RecommendMinutes(
BYVALUE Moisture : INTEGER,
BYVALUE RestrictionActive : BOOLEAN
) RETURNS INTEGER
DECLARE RecommendedMinutes : INTEGER
IF Moisture < 18 THEN
RecommendedMinutes β 24
ELSE
IF Moisture <= 35 THEN
RecommendedMinutes β 12
ELSE
RecommendedMinutes β 0
ENDIF
ENDIF
IF RestrictionActive = TRUE THEN
IF Moisture < 10 THEN
RecommendedMinutes β 12
ELSE
IF RecommendedMinutes > 8 THEN
RecommendedMinutes β 8
ENDIF
ENDIF
ENDIF
RETURN RecommendedMinutes
ENDFUNCTION
Step 3: identify all affected calls
Every call must now supply the new argument:
Minutes β RecommendMinutes(
CurrentMoisture,
RestrictionActive
)
Step 4: design tests before release
| Moisture | Restriction | Purpose | Expected minutes |
|---|---|---|---|
| 9 | FALSE | Existing low-moisture behaviour | 24 |
| 9 | TRUE | Emergency during restriction | 12 |
| 10 | TRUE | Immediately outside emergency condition | 8 |
| 18 | FALSE | Preserve existing boundary behaviour | 12 |
| 18 | TRUE | Restriction cap applied | 8 |
| 36 | TRUE | No watering remains no watering | 0 |
Testing Maintenance Changes
Every maintenance change can introduce a regression, including a change intended only to improve internal structure.
| Testing activity | Purpose | Example |
|---|---|---|
| Direct retest | Check the original fault after correction. | Retest moisture of exactly 18%. |
| New-feature tests | Check added adaptive behaviour. | Test restriction and emergency combinations. |
| Regression tests | Check that existing behaviour still works. | Repeat unrestricted recommendation cases. |
| Interface tests | Check changed parameters and return values. | Confirm every caller supplies RestrictionActive. |
| Performance comparison | Check whether a perfective optimisation achieved its aim. | Compare records scanned before and after indexing. |
| Equivalence tests | Check that refactoring preserved externally visible behaviour. | Run the same validation inputs before and after refactoring. |
Documentation, Versions and Release
Maintenance changes should be understandable to future developers and users.
| Record | Information to update |
|---|---|
| Requirements specification | New or changed behaviour and acceptance criteria |
| Design documentation | Changed modules, data structures, algorithms and interfaces |
| Source comments | Purpose of non-obvious decisions rather than a history of every edit |
| Test plan | New cases, regression cases and recorded outcomes |
| Fault or change record | Reason, priority, affected version and resolution |
| User documentation | Changed screens, workflows or messages |
| Release notes | Version number, corrections, adaptations and known limitations |
Interactive: Corrective-maintenance Debugger
Follow a reported boundary fault through reproduction, diagnosis, correction and regression testing.
Interactive: Adaptive-maintenance Change Explorer
Select a new requirement and inspect the modules, data, interfaces and tests that may be affected.
Interactive: Perfective-maintenance Refactor Lab
Compare duplicated validation, a reusable routine and a faster latest-reading lookup. Observe which quality measure is being improved.
Common Mistakes and Misconceptions
- Calling every change corrective. Corrective maintenance specifically repairs a fault.
- Calling every new feature perfective. A changed required function is normally adaptive.
- Classifying from the edited code. The reason for the change determines the maintenance type.
- Editing before reproducing a fault. The original failing case provides evidence for the correction.
- Treating the symptom as the root cause. An incorrect screen value may originate in another module.
- Adding a requirement without impact analysis. Inputs, interfaces, data, tests and documentation may all change.
- Explaining perfective maintenance as βmaking code nicer.β State how maintainability, performance or resource use improves.
- Assuming refactoring cannot introduce faults. Working behaviour must be retested.
- Testing only the changed feature. Existing behaviour also requires regression testing.
- Failing to update documentation. Outdated interfaces and requirements make later maintenance risky.
Practice
Core questions
- Explain why a released system may require continuing maintenance.
- Define corrective maintenance.
- Define adaptive maintenance.
- Define perfective maintenance.
- Explain how the reason for a change determines its category.
- State five stages in a corrective-maintenance process.
- Explain why impact analysis is needed before an adaptive change.
- Explain how refactoring can improve maintainability.
- Give two examples of perfective performance improvements.
- Explain why regression testing is required after maintenance.
Scenario A: Corrective Maintenance
A greenhouse controller should open a vent when temperature is greater than 28Β°C. Users report that it also opens at exactly 28Β°C.
- Classify the maintenance type.
- Suggest a possible faulty condition.
- State the corrected condition.
- Give suitable reproduction and boundary tests.
- Explain which regression tests should follow the correction.
Scenario B: Adaptive Maintenance
A working workshop-booking system must now allow remote sessions with video links.
- Explain why this is adaptive maintenance.
- Identify four affected parts of the system.
- Suggest one new data field.
- Suggest one changed module interface.
- Write three tests for the new behaviour.
- State two existing behaviours that require regression testing.
Scenario C: Perfective Maintenance
A record-search program returns correct results, but it scans 80,000 records from the beginning for every query. Several modules also contain copied search code.
- Explain why perfective maintenance is appropriate.
- Suggest one maintainability improvement.
- Suggest one performance improvement.
- State what should be measured before and after the change.
- Explain how to check that search results remain equivalent.
Scenario D: Analyse and Amend
FUNCTION DeliveryPriority(
BYVALUE Distance : INTEGER
) RETURNS STRING
IF Distance <= 5 THEN
RETURN "LOCAL"
ELSE
RETURN "STANDARD"
ENDIF
ENDFUNCTION
A new requirement adds an Urgent Boolean. An urgent delivery should
return "EXPRESS" regardless of distance.
- State the maintenance type.
- Amend the function header.
- Amend the algorithm.
- Identify all calling code that may be affected.
- Design tests for urgent and non-urgent deliveries.
Review
| Prompt | A strong response should include |
|---|---|
| Corrective maintenance | Repair of an identified fault, followed by direct retesting and regression testing |
| Adaptive maintenance | A change required by a new specification, user need, interface or operating environment |
| Perfective maintenance | Improvement of working softwareβs structure, maintainability or performance |
| Impact analysis | Identification of affected requirements, modules, interfaces, data, tests and documentation |
| Maintainability | Ease of understanding, testing, correcting and modifying software |
| Regression testing | Repetition of relevant existing tests after a change |
| Extending functionality | Analyse the existing program, amend interfaces and logic, and test new and preserved behaviour |