© s. demeyer, s. ducasse, o. nierstrasz migration.1 5. testing and migration what and why ...
Post on 19-Dec-2015
216 views
TRANSCRIPT
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.1
5. Testing and Migration• What and Why
Reengineering Life-Cycle
• Tests: Your Life Insurance !Grow Your Test Base IncrementallyUse a Testing FrameworkRecord Business Rules as Tests…
• Migration StrategiesMake a Bridge to the New Town
• Conclusion
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.2
What and Why ?Definitions• Restructuring refers to transforming a system from one
representation to another while remaining at the same abstraction level. — Chikofsky & Cross, ’90
• Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code, yet improves its internal structure — Fowler, ’99
Motivation• Alter the source-code to
solve problems identified earlier without introducing new defects and while the system remains in operation
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.3
The Reengineering Life-Cycle
Requirements
Designs
Code
(0) requirementanalysis
(1) modelcapture
(2) problemdetection (3) problem
resolution
(4) program transformation
(3) problem resolution(4) program transformationissues• reliability• time• risk
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.4
Roadmap• What and Why
Reengineering Life-Cycle
• Tests: Your Life Insurance ! Grow Your Test Base Incrementally Use a Testing Framework Record Business Rules as Tests …
• Migration Strategies Make a Bridge to the New Town
• Conclusion
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.5
Forces — Testing• Many legacy systems don’t have tests• Software changes introduce new bugs• You can’t test everything• Concurrency and user interfaces are hard to test• Testing is usually everyone’s lowest priority• Knowledge concentration poses high risk• Customers pay for features, not tests• Customers don’t want buggy systems• Good programmers don’t need tests• New tools and techniques are more fun than
testing• Testing is akin to street-cleaning
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.6
Tests: Your Life Insurance!
Write Tests to Enable Evolution
Grow Your TestBase Incrementally
Manage testsUse a TestingFramework
Test the Interface,Not the Implementation
Record BusinessRules as Tests
Design tests
• Test Fuzzy features• Test Old Bugs• Retest Persistent Problems
Write Teststo Understand
Regression Testafter Every Change
Migration Strategies
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.7
Write Tests to Enable Evolution
Problem: How do you minimize the risks of change?Solution: Introduce automated, repeatable, stored tests
Automated Tests
System ConfidenceTurnover Risk minimization
System documentation Architectural evolution
Long-term evolution
Automated tests are the foundation of reengineering
Confidence in Change
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.8
Grow Your Test Base Incrementally
Problem: When can you stop writing tests?Solution: When your tests cover all the code!… however
you're paid to reengineer, not to write tests testing ALL the code is impossible design documentation is out-of date
» semi-automated black-box testing is not an option
• Answer: Grow Your Test Base Incrementally- first test critical components
(business value; likely to change; …)- keep a snapshot of old system
(run new tests against old system)- focus on business values- test old bugs + new bugs that are reported
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.9
Use a Testing FrameworkProblem: How do you encourage systematic testing?Solution: Use a framework to structure your tests
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.10
Running tests
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.11
Test the Interface, Not the Implementation
Problem: How do you protect your investment in tests?
Solution: Apply black-box testing
• Test interfaces, not implementationsBe sure to exercise the boundaries
• Test scenarios, not pathsUse tools to check for coverage
• Beware;Enabling testing will influence your design!
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.12
Write Tests to UnderstandProblem: How to decipher code without
adequate tests or documentation?Solution: Encode your hypotheses as
test cases
• Exercise the code• Formalize your reverse-engineering
hypotheses• Develop tests as a by-product
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.13
Record Business Rules as Tests
Problem: How do you keep your system in sync with the business rules it implements?
A Solution: Good documentation + Good design• … however
business rules are too complex to design well documentation & design degrades when the rules
change business rules become implicit in code and minds
Solution: Record Business Rules as Tests
- canonical examples exist- can be turned into input/output
tests
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.14
Example: Payroll Business Rule
A person or couple gets an amount of money for every child he, she or they raise. Basically parents get CHF 150,- per month for every child younger than 12 years, and CHF 180,- for every child between 12 and 18 and for every child between 18 and 25 as long as the child is not working and is still in the educational system. A single parent gets the full 100% of this money as long as he or she is working more than 50%. Couples get a percentage of the money that is equal to the summed working percentages of both partners.
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.15
Example: Payroll Test Case
"--- input-cases are extracted from a database"singlePerson80WithOneKidOf5 := extract....couplePerson40occupationWithOneKidOf5 := extract....couplePerson100occupationWithOneKidOf5 := extract....couplePersonWithOneKidOf14 := extract....
"--- tests compare expected output against actual output"self assert: singlePerson80occupationWithOneKidOf5 moneyForKid
= 150.self assert: couplePerson40occupationWithOneKidOf5
moneyForKid= 150*4.
self assert: couplePerson100occupationWith2KidsOf5 moneyForKid= 150*2.
self assert: couplePersonWithOneKidOf14 moneyForKid= 180.
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.16
Other patternsRetest Persistent Problems
Always tests these, even if you are making no changes to this part of the system
Test Fuzzy Features Identify and write tests for ambiguous or ill-
defined parts of the system
Test Old BugsExamine old problems reports, especially
since the last stable release— DeLano and Rising, 1998
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.17
Roadmap• What and Why
Reengineering Life-Cycle
• Tests: Your Life Insurance ! Grow Your Test Base Incrementally Use a Testing Framework Record Business Rules as Tests …
• Migration Strategies Make a Bridge to the New Town
• Conclusion
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.18
The Reengineering Life-Cycle
Requirements
Designs
Code
(0) requirementanalysis
(1) modelcapture
(2) problemdetection (3) problem
resolution
(4) program transformation
(3) problem resolution(4) program transformationissues• reliability• time• risk
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.19
Forces — Migration• Big-bang migration often fails• Users hate change• You need constant feedback to
stay on track• Users just want to get their work
done• The legacy data must be available
during the transition
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.20
Migration Strategies
Migrate SystemsIncrementally
ConserveFamiliarity
HowUse Profiler
before Optimizing
Build ConfidenceInvolve the UsersHow Why
Why
Present theRight Interface
DeprecateObsolete Interfaces
Distinguish Publicfrom Published Interfaces
Make a Bridgeto the New Town
Always Have aRunning Version
Regression Testafter Every Change
How
Tests, yourLife-Insurance
Prototype theTarget Solution
Where to
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.21
Involve the UsersProblem: How to get users to accept
change?Solution: Get them involved by giving
them what they want
Start with the Most Valuable First• Prototypes can help raise enthusiasm,
but may also raise expectations too high• Deploy early to increase commitment
Diverts energy from developmentPays back in quality feedback
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.22
Build ConfidenceProblem: How do you overcome skepticism?Solution: Deliver results in short, regular
intervals
• Requires time to sync with users• Requires effort to support the changes• Requires care not to alienate original
developers• Requires regular, big demos to convince
management
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.23
Migrate Systems Incrementally
Problem: When should you deploy the new system?
Solution: As soon as possible
• Decompose the legacy system into parts• Tackle one part at a time (Most Valuable First)• Put suitable tests in place• Decide whether to wrap, reengineer, or
replace• Deploy, support and obtain feedback• Iterate
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.24
Prototype the Target Solution
Problem: How do you evaluate the target solution?
Solution: Develop a prototype
• Evaluate the technical risks New system architecture Migrating legacy data Adequate performance …
• Exploratory prototype? Explore specific issues, then throw it away!
• Evolutionary prototype? Capture new architecture Migrate, wrap, reengineer or reimplement parts
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.25
Always Have a Running Version
Problem: Maintaining confidence during development
Solution: Integrate changes on a daily basis
• Use version and configuration management tools
• Maintain exhaustive regression tests where needed
• Plan short iterations — Continuous Integration If necessary, re-architect the system to enable
short build times
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.26
Regression Test After Every Change
Problem: Making sure changes don’t break the system
Solution: Run the regression tests at each “stable” point
•You must relentlessly write tests!Write new tests whenever new (untested) bugs are
discoveredTake time to convince your team of the Joy of Testing
•If testing takes too long, categorize testsBut run all the tests at least once a day
•Consider writing tests up front•Remember to Retest Persistent Problems
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.27
Make a Bridge to the New Town
Problem: How to migrate data?
Solution: Convert the underlying files/databases/…
... howeverLegacy and new system
must work in tandemToo much data; too many
unknown dependenciesData is manipulated by
components
Bridge
1:read() 2:write()
1.1:read()
1.2:write()
2.1:write()
Legacy System
New System
Data Store
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.28
Present the Right InterfaceProblem: How do you prevent the legacy
design from polluting the new system?Solution: Wrap old services as new
abstractions
• Identify the new abstractions you want• Wrap the legacy services to emulate the
new interfaceAvoid directly accessing old procedural
interfacesAvoid wrapping as pseudo-OO «utility»
classes
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.29
Public vs. Published Interface
Problem: How to design interface for target solution?
Solution?: Think deeply• ... however
Enable migration to target system ASAP Avoid freezing the interface of target component Costly ripple-effects of changes to public interface
Solution: Distinguish between "public" and"published" interface
- "public" = stable target interface- "published" = available, but unstable
(use at your own risk)-language features (protected, friends, …)-naming conventions
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.30
Deprecate Obsolete Interfaces
Problem: How to modify an interface without invalidating all clients?
Solution: Flag the old interface as «deprecated»
• Old and new interfaces can co-exist for a timeDeprecated usage can be lazily patched
• Various techniques possibleDocumentation (easy to ignore)Move or rename old interfaces (painful)Add warnings to deprecated code (should be non-
intrusive)
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.31
Conserve FamiliarityProblem: How to avoid disrupting
Users’ work? Solution: Avoid radical changes
• Avoid alienating users• Introduce a constant, small
number of changes with each release
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.32
Use Profiler Before Optimizing
Problem: When should you rewrite inefficient code?
Solution: Only when you have benchmarks that prove it is worthwhile
• “Do it, then do it right, then do it fast”
© S. Demeyer, S. Ducasse, O. Nierstrasz Migration.33
ConclusionAvoid risk
small increments ("chicken little")develop suite of regression tests
… at acceptable costMigration costs as much as new
development !But you avoid "hidden costs"
• team morale in maintenance team• satisfying two customer bases