Software evolution Perdita Stevens February 2010
What is software evolution? Change over time. ◮ all kinds of maintenance: corrective, adaptive, perfective, preventive ◮ reengineering ◮ end-of-life, system withdrawal Various experts have asserted that most of the cost of software ownership arise after delivery, i.e. during “maintenance”. (E.g. > 90%, Erlikh, L. (2000). Leveraging legacy system dollars for E-business. (IEEE) IT Pro, May/June 2000, 17-23 !)
Why does software need to change? ◮ because it wasn’t built right; ◮ because something has changed: business environment, software environment, hardware environment...
Kinds of maintenance More precisely, even though software doesn’t wear out in the same was as physical artifacts, it still needs to be: ◮ fixed (corrective maintenance), ◮ adapted to changing needs (adaptive maintenance), ◮ improved in performance or maintainability (perfective maintenance) ◮ improved by fixing bugs before they activate (preventive maintenance) [ISO/IEC 14764, following Swanson]
What should we think of this? Success: tells of flexible systems that needn’t be thrown away? Failure: tells of systems that aren’t correct or flexible as built? Whatever... figures like these do tell us that how maintenance is done is important: doing it better may save money. (And doing it less may too, of course.)
Lehman’s laws Manny Lehman, the “Father of Software Evolution”, wrote many papers from the mid 70s onwards, proposing “Laws of Software Evolution” for “E-type systems”. Systems classified into: ◮ S-type: formally specified and verified; static by definition ◮ E-type: real-world system
Lehman’s laws (adapted from 2001 talk by MML) I Continuing An E-type system must be continually adapted else it Change becomes progressively less satisfactory in use II Increasing As an E-type system is evolved its complexity increases Complexity unless work is done to maintain or reduce it III Self regulation Global E-type system evolution processes are self- regulating IV Conservation of Average activity rate in an E-type process tends to re- Organisational main constant over system lifetime or segments of that Stability lifetime V Conservation of In general, the average incremental growth (growth rate Familiarity trend) of E-type systems tends to decline VI Continuing The functional capability of E-type systems must be con- Growth tinually enhanced to maintain user satisfaction over sys- tem lifetime VII Declining Unless rigorously adapted to take into account changes Quality in the operational environment, the quality of an E-type system will appear to be declining as it is evolved VIII Feedback E-type evolution processes are multi-level, multi-loop, System multi-agent feedback systems
Criticism of Lehman’s laws “Laws”? Based on data? Contentful?
Two kinds of scenario Let us consider separately: ◮ Business-as-usual software evolution: how things should work ◮ Disaster recovery software evolution: coping when things don’t work properly
Managing change Realising that software evolution is normal and necessary, have a process in place: 1. A bug report or change request is submitted, e.g. via an issue tracking tool; 2. Show-stopping problems may have to be dealt with immediately (maybe even by a binary patch); 3. But as a general rule, issues and bugs are classified and prioritised; 4. Subsequent software releases incorporate fixes for a selection of reported issues. There is always a trade-off between fixing old issues and introducing new functionality. Some problems are cheap to live with.
Why evolution doesn’t always go smoothly Maintenance is seen as uninteresting and low-status: hard to get the best developers to spend long on a maintenance team. There is always more work than can be done, so corners tend to be cut. Even if resource isn’t an issue, the intention behind the original design is easily lost. So the software gradually loses its integrity: architectural degradation .
Legacy systems A system which still has value, but which significantly resists modification and evolution. Stereotypically old – but that can mean 5 years. Problems include: ◮ architectural degradation ◮ reliance on unmaintained software or hardware ◮ loss of expertise ◮ not designed for evolution.
Bad situations There is a system: it is in use, but nobody deeply understands how it works. It needs to be changed, but there’s a problem. Maybe its source code is a mess. Maybe it can no longer be compiled. Maybe its source code has even been lost! (Perhaps only partially.)
So what to do? Basically three options: ◮ Soldier on ◮ Reengineer ◮ Scrap The attempt to understand the system is an essential part of the decision process.
Techniques for understanding legacy systems Program comprehension tools can help, well, comprehend the program. Many techniques can be used, providing different information useful in different circumstances. For example, a slicing tool can be used to identify which lines of a program affect the value of a specific variable at a point of interest. Reverse engineering tools construct a high level view of a system from a low level one. This may be source code from object code (useful if source code has been lost), a call graph in which nodes representing modules or functions are connected if one calls the other, or perhaps a UML class diagram.
And then what? If only small modifications are needed, may now be able to modify and rebuild the system, even if much of it is still undocumented. Or it may be more cost-effective to replace or reengineer. E.g. ◮ Reengineer: renovate the system by restoring a suitable architecture and updating as needed. ◮ Replace in a fairly mechanical way (with or without automation): e.g., where a system is written in an obsolete language, have it translated function-by-function into a modern language. ◮ Replace, starting from gathering current requirements. Consider using COTS (commercial off-the-shelf) software.
A complementary technique Sometimes you want to save, but not continue to modify, a legacy system or component. E.g., it’s written in an obsolete language, and/or it is incomprehensible (but apparently correct!) You can use the Adapter design pattern – wrap it in a well-defined interface (using a foreign function interface if necessary) usable from a modern language. All future code interacts with the legacy only through the adapter. Pro: Old code doesn’t “infect” new code Con: Limited to cases where you can isolate the valuable legacy.
Suggested readings M. M. Lehman. Software’s Future: Managing Evolution. IEEE Software 15(1):40-44, 1998 See also http://www.doc.ic.ac.uk/~mml/feast2/papers.html
Recommend
More recommend