Lean-Agile Engineering Practices... · –Emergent Design –Essential Skills for the Agile...
Transcript of Lean-Agile Engineering Practices... · –Emergent Design –Essential Skills for the Agile...
[email protected] www.netobjectives.com
1 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Lean-Agile Engineering
Practices A Free Seminar Event
Sponsored by
Alta Source Group
and
Net Objectives
2 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Seminar Agenda
Time Topic
5:30pm - 6:00pm Registration, Networking, and Pizza
6:00pm - 7:00pm Emergent Design
7:00pm - 7:15pm Break
7:15pm - 8:15pm Sustainable TDD
8:15pm - 8:30pm Wrap-up, Q&A
3 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Net Objectives: Who We Are
Vision Effective software development without suffering
Mission To assist companies in maximizing the business value returned from their efforts in software development and maintenance.
We do this by providing training, coaching, and consulting that directly assists and empowers our customers to create and sustain this ability
Services Training in sustainable product development Assessments Lean-Agile coaching and mentoring
Expertise Lean Software Development
Agile Methods (Scrum, XP, RUP)
Agile Analysis
Design Patterns
Test-Driven Development / Quality Assurance
4 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Scott Bain
Senior Consultant
Author: – Emergent Design
– Essential Skills for the Agile Developer
– Sustainable Test-Driven Development (upcoming)
Instruction in Agile Development, Design Patterns, Test-Driven Development
[email protected] www.netobjectives.com
5 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Emergent Design The Evolutionary Nature of
Professional Software Development
Scott L. Bain
Net Objectives
6 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
What Is Design?
Risk mitigation
Opportunity to reduce waste
Documentation of intent
The thought process behind the software
Exists at multiple levels:
– Architecture
– “Design”
– Code
7 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
When Do We Do Design?
After Analysis?
Before Implementation?
Do we test our design?
What if we get it wrong?
What if we overdo it?
How much design is enough design?
Analysis
Design
Implementation
Testing
Release
8 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Agenda
The natural flow of software development
The traditional view
A more realistic view
Qualities, Principles, and Practices
Disciplines: Testing, Refactoring, and Patterns
Emergent Design (an example)
Resources for further investigation
9 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Nature of Software Development
“Let the water take you…”
The water flows around the rocks, not through them.
10 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Traditional View
Analogous to Civil Engineering
Plan, do, review
Based on:
– Concrete Analysis
– Hi-Fidelity Communication
– Slow Pace of Change
– Planning around “knowns”
11 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
A Realistic Fit?
Analysis
Design
Construction
Inspection
Release
Requirements
Design
Coding
Testing
Deployment
Civil Engineering Software Development
12 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
“Inevitable” Decay
Time
Qu
alit
y as
Co
de
Ch
ange
s
Entropy
Code Debt
"That’s the way it is"
Functional Completeness
Cheaper to Replace
Release Maintenance
13 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Importance of Software
Software is permeating more and more of our businesses/lives/culture
The quality of our software is having a greater influence on the quality of our lives
Failures in software are now capable of doing greater and greater damage
Other professions are becoming increasingly vulnerable to software
14 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Rejecting Decay: Changing Change
Time
Qu
alit
y as
Co
de
Ch
ange
s
"First, do no harm"
Code what you know
Validation-Centricity
Validateable: What we think we know
Based on what we have learned
First Iteration
Further Iterations
15 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Changing Expectations, Changing Design
Let’s compare the “old way” of looking at design with this idea of emerging a design
While we believe we’re “letting the water take us”, we also want to respond to any vulnerabilities or potential waste in an agile process
So, as an analogy…
16 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Let’s Fly to Miami: Plan, Do, Review
Seattle
Miami Dallas
Large Correction
17 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Essence of Lean-Agile Development
Determine the most important thing to do next
Figure out how much of it you can do
Do it
Validate it
Repeat This step implies something…
18 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Let’s Fly to Miami: Act, Validate, Adjust
Seattle
Miami
…but lots of them!
19 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
What Is Changeable Design?
A design is changeable if:
– In changing it, you do not increase risk or waste
– It can be changed economically (ROI)
– It can be changed without decaying
We are guided by the Open-Closed Principle, which is manifested by Patterns…
20 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Open-Closed Principle
Based on the work of Bertrand Meyer, and ultimately a product of pre-OO thinking by Ivar Jacobsen
Jacobsen: “All systems change during their life cycles. This must be borne in mind when developing systems expected to last longer than the first version”
Meyer: “Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”
http://en.wikipedia.org/wiki/Open_Closed_Principle
21 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Applied to Classes: The Strategy Pattern
Client Context
+request(Strategy s)
Strategy
+operation()
Strategy_V2
+operation()
Strategy_V3
+operation()
New Requirement: add a class
Do not change the code in the context
Strategy_V1
+operation()
22 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Open Closed to Other Things: The Decorator Pattern
The Decorator Pattern is about adding one, two, or many optional behaviors on top of an existing behavior
For flexibility, we often accomplish this by placing the behaviors in a linked list (although this is not the pattern, only an example implementation)
If you’ve done streaming IO in Java or .Net, you’ve already used a decorator
23 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Decorator Pattern for Streaming IO
Client
TCPIPStream + flush()
FileStream + flush()
U128 + flush()
CompressStream + flush()
Stream
+ output()
+ flush()
StreamDecorator
0..1
1
Stream myStream = new U128(
new CompressStream(
new FileStream(filename)));
24 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Decorator's Structure and Behavior
Case: Convert to Unicode, Compress, Flush
Client
U128 Compress FileStream flush
Convert
to U128 compress send
flush flush
Single Behavior, sees only “Stream”
25 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Open-Closed to a New Decorator
Client
TCPIPStream + flush()
FileStream + flush()
U128 + flush()
CompressStream + flush()
Stream
+ output()
+ flush()
StreamDecorator
0..1
ScottsGreatIdea
+ flush()
1
26 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Open-Closed to More Things…
Client
FileStream SGI Compress
No change to the Client’s code…
27 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Open-Closed is a “Principle”
No matter how “Open-Closed” your system is, it could be moreso
Sometimes it’s overkill, especially if you know you can add it later
If we don’t go so far as to introduce it at the class or design level, we can still be guided by it…
28 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
What Is Changeable Code?
Code can be open-closed too
It has to do with:
– Cohesion (each class or method is “single minded”)
– Coupling (dependencies and side-effects are minimized)
– Non-duplication (one rule in one place)
…and these qualities are manifested by Patterns too
29 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Patterns Also Promote Code Quality
Client Context
+request(Strategy s)
Strategy
+operation()
Strategy_V2
+operation()
Cohesive: Implementation is separate
Decoupled: Implementations have no side-effects
Cohesive: Delegates an operation
Decoupled: No commitment to specific implementation
Strategy_V1
+operation()
Any duplication pushed up here
30 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
int BigOlHonkinAlgorithm(String parm) {
int rval = doStepOne(parm);
rval = doStepTwo(rval);
if (checkForStep3()) {
rval = doStepThree(rval);
return rval;
}
int doStepOne(String parm) {
// Little piece of the overall algorithm, sets myRval
return myRval;
}
int doStepTwo(int parm) {
// Little piece of the overall algorithm, sets myRval
return myRval;
}
bool checkForStep3(){
// business rule, sets rval
return rval;
}
int doStepThree(int parm) {
// Little piece of the overall algorithm, sets myRval
return myRval;
}
Open-Closed at the Code Level Method Cohesion
31 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Practices: – Are things you simply do,
always
– Are easy to do and teach others, which is why “always”
– Are never compromised because they are low cost and high value, regardless of circumstance
– Helps us to do well the things we are thinking about
– Example: let’s look at two…
Principles and Practices
Principles: – General wisdom about design
– Can be difficult to follow in some cases
– Are sometimes compromised when the costs are too high to follow them
– Helps us to think well about what we are doing
– Example: OCP
32 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Practice: Programming By Intention
class Transaction {
public Boolean commit(String command)
{
Boolean result = true;
String[] tokens = tokenize(command);
normalizeTokens(tokens);
if(transactionIsLarge(tokens)){
result = processLargeTransaction(tokens);
}else{
result = processSmallTransaction(tokens);
}
return result;
}
}
33 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Practice: Encapsulate the Constructor
A simple practice that promotes the separation of use from construction
Is the topic of another presentation (recorded)
I’ll show it simply here…
34 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Instead of This…
class Service {
public String doOperation(int x) {
//Whatever this does
return rVal;
}
}
class Client {
Service myService;
Client() {
myService = new Service();
}
public void m() {
// Other stuff
myService.doOperation(10);
//
}
}
35 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
We Do This…*
class Service {
private Service(){}
public static Service getInstance() {
return new Service();
}
public String doOperation(int x) {
//Whatever this does
return rVal;
}
class Client {
Service myService;
Client() {
myService = Service.getInstance();
}
public void m() {
// Other stuff
myService.doOperation(10);
//
}
}
*Based on a recommendation by Joshua Bloch in “Effective Java” and “Effective C#”
36 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
So Later We Can Do This…
abstract class Service {
public static Service getInstance() {
if(whateverCondition()) {
return new Service_V1();
}else{
return new Service_V2();
}
}
public abstract String doOperation(int x);
}
class Service_V1 : Service {
// impl1
}
class Service_V2 : Service {
// impl1
}
//… with little or no change to the client(s)
37 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Disciplines
A “Discipline” is similar to a practice, in that it is highly valuable, and should be understood by all
They are not, however, without cost
Therefore, for a Discipline to become a standard in our business, it must be worth the effort it requires
Three we’re sold on / teach:
– Pattern-Oriented Development
– Test-Driven Development
– Refactoring (in two different senses of the word)
38 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Testability and Quality
One big virtue of Test-Driven Development /Design is that it drives the “testability” issue to the forefront in design – A class that is too tightly coupled will be hard to test, because
all of its dependencies will have to be tested with it
– A class that is weakly cohesive will be hard to test, because all possible combinations of its multiple responsibilities will have to be tested, due to lack of encapsulation
– Redundancies in the system will produce redundancies in the test(s)
39 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Refactoring
“Improving the Design of Existing Code”
Behavior-Preserving Change of code
– Same outward effect as before
– Same tests pass as before
– Code Quality is Improved
Often seen as “Developer Obsession” with code cleanliness, because it does not produce new business value
Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts
40 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Refactoring Moves for Improving Cohesion
Extract Method
Very common need: take a method that has become poorly cohesive and pull details out into a new method.
Move Method
Very common need: take a class that has become poorly cohesive and pull details out into another class.
One often leads to the other.
41 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Two Kinds of Refactoring
Classic “Fowlerian” Refactoring: – Taking working code and making it better
– Improving its clarity
– Improving its design
Refactoring to the Open Closed – Taking working code that was fine when written
But is not open-closed to adding a new requirement
– Making it open closed (in a particular sense)
– …so you can enhance (add a feature) with less risk and less waste
– Eliminating risk and waste are business values
(Fowler understands this too…)
42 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Design as Evolution: Emergent Design
Software is valuable relative to the world around us, and the needs it has…
The world, and its needs, change
For software to retain its value, it must change
The pace of change is increasing
Software must always be in a state of evolution
Disciplines, Principles, and Practices make it possible…
43 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Practice: Programming By Intention
Application
+request() -op1() -op2() -op3()
public void request(){ op1(); op2(); op3(); }
If we’d neglected to do this (or someone else neglected to do this) the refactor would be extract method.
Testable?
44 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Testability: Refactor - Extract Class
Application
-myService1 +request() -op1() -op2() -op3()
Service1
+getInstance():Service1 +op1()
private void op1(){ myService1.op1() }
public Application(){ myService1=Service1.getInstance(); }
public static Service1 getInstance(){ return new Service1(); }
Service1Test
+testService1()
Application2 Application3
45 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Open-Closed Principle: Refactor - Extract Interface
Application
-myService1 +request() -op1() -op2() -op3()
Service1
+getInstance():Service1 +op1()
Service1A
+op1()
Service1B
+op1()
public static Service1 getInstance(){ if(use1A) { return new Service1A(); } else { return new Service1B(); } }
Service1
+getInstance():Service1 +op1()
Application2 Application3
46 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Patterns: Refactor – Introduce Proxy
Application
-myService1 +request() -op1() -op2() -op3()
Service1
-myService1Factory +getInstance():Service1 +op1()
Service1A
+op1()
Service1B
+op1()
LoggingProxy
+op1()
Service1Factory
+getInstance():ServiceFactory +getService():Service1
public static Service1 getInstance(){ return myService1Factory. getService(); }
47 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Patterns: Refactor – Evolve Decorator
Application
-myService1 +request() -op1() -op2() -op3()
Service1
-myService1Factory +getInstance():Service1 +op1()
Service1A
+op1()
Service1B
+op1()
LoggingProxy
+op1()
Service1Factory
+getInstance():ServiceFactory +getService():Service1
Decorator
+op1()
Dec1
+op1()
Dec1
+op1() 1
48 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Remember Where We Started?
Application
+request() -op1() -op2() -op3()
49 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Avoiding Over-Design
Complexity When You Need it – But not before you need it
Good practices reduce risk Risk is wasteful Over-Design is wasteful
Emergent Design uses refactoring to reduce over-design
and enable low-risk change Principles can guide us… Practices can protect us… Disciplines can empower us… You cannot stop thinking!
50 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Resource for Further Investigation
Design Patterns:
– www.netobjectivesrepository.com
51 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Pattern Repository
52 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Break Time
[email protected] www.netobjectives.com
53 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Sustainable Test-Driven
Development Making TDD work
Past the First Few Iterations
Scott L. Bain
Net Objectives
www.sustainabletdd.com
54 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
“Test”-Driven Development?
Test (těst) n.
A procedure for critical evaluation; a means of determining the presence, quality, or truth of something; a trial: a test of one's eyesight; subjecting a hypothesis to a test; a test of an athlete's endurance
A series of questions, problems, or physical responses designed to determine knowledge, intelligence, or ability
A basis for evaluation or judgment: "A test of democratic government is how Congress and the president work together" (Haynes Johnson)
The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004.
55 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Agenda
Re-Defining TDD
Which Tests to Write
– …and which ones not to write
Defining a “Good” Unit Test
Testing Qualities and Code Qualities
TDD as Test-Driven Design
Breaking Dependencies in Testing
The Role of Patterns in TDD
56 22 March 2012
Re-Defining TDD
57 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Impediments
TDD = “Write the Tests First”?
Test First is a technique, TDD is a paradigm
At first, developers writing tests (first) seems:
1. Nonsensical. You cannot “test” something you don’t have
2. Wasteful. Developers will be doing double the work
3. Cumbersome. The team will slow down
4. Unsustainable. The test suite will have to be maintained
The first three questions can be answered by re-defining what TDD is
The fourth issue is about what and how we test
58 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Example Problem
We’re tracking the amortization of a “Fixed Asset”
Asset has an initial value, and a term for writing it off (“useful Life”)
The calculation is simple: value/term or “Straight Line”
How do we document this?
Functional Spec 1.0 Blah blah blah Thus and so Unless this or that But always finally
59 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Documentation of Intent
Functional Spec 3.2 Blah blah blah Thus and so Unless this or that But always finally
How can we determine that this is still up to date, if we return six months later?
60 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
How About This? (JUnit)
public class AssetTest {
private Random any = new Random();
@Test
public void testAssetFirstYearStraightLineCalculation() {
double anyValue = any.nextDouble();
int anyTerm = any.nextInt();
int yearToWriteOff = 1;
double straightLineResult = anyValue / anyTerm;
Asset testAsset = new Asset(anyValue, anyTerm);
assertEquals(straightLineResult,
testAsset.getWriteOff(yearToWriteOff), .02);
}
}
61 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Nonsensical? Wasteful?
… in TDD, we do not write “tests”
They only look like tests
In TDD, we are conducting an analysis to create the functional specification
– …which you were going to do anyway, right?
– …and which will be automatically verifiable at any point in the future
When we’re done, these specifications can also serve as regressions tests for refactoring
Double the work? Nope
Multiple values from a single effort
62 22 March 2012
Which Tests to Write
63 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Asset, A New Requirement
A year goes by, and the federal government issues a new regulation
Assets with an initial value of more than $70,000 will amortize as $70,000
What tests do you write?
64 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
New Specification (JUnit)
@Test
public void testAssetsAreCappedAtAMaximum(){
double cappedValue = 70001.00;
double unCappedValue = 70000.00;
int term = any.nextInt();
int yearToWriteOff = 1;
Asset cappedAsset = new Asset(cappedValue, term);
Asset unCappedAsset = new Asset(unCappedValue, term);
assertEquals(70000.00 / term,
cappedAsset.getWriteOff(yearToWriteOff), .02);
assertEquals(unCappedValue / term,
unCappedAsset.getWriteOff(yearToWriteOff), .02);
} Quality Issue: Magic Numbers!
Quality Issue: Redundancy!
65 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Better Specification (JUnit)
@Test
public void testAssetsAreCappedAtAMaximum(){
double cappedValue = Asset.CAP + 1;
double unCappedValue = Asset.CAP;
int term = any.nextInt();
int yearToWriteOff = 1;
Asset cappedAsset = new Asset(cappedValue, term);
Asset unCappedAsset = new Asset(unCappedValue, term);
assertEquals(Asset.CAP / term,
cappedAsset.getWriteOff(yearToWriteOff), .02);
assertEquals(unCappedValue / term,
unCappedAsset.getWriteOff(yearToWriteOff), .02);
}
If this is a Spec, should it not show the current cap?
66 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Specifications Must Be Complete (JUnit)
@Test
public void specifyAssetConstants(){
assertEquals(70000.00, Asset.CAP, .02);
}
68 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Other Tests?
What about Asset.Cap / 2? Asset.Cap +10,000.00?
Theoretically no end to this – Though QA may have standards for adequate scenarios
In TDD the two tests: – At Cap + 1 : calculated against the cap
– At Cap: calculated normally
…define the boundary for behavior
The other tests would be duplication, and would pass and fail together
69 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Other, Other Tests?
Should we test that the algorithm for capping does not:
– Format the hard disk?
– Block port 5388?
– Start a new thread that incrementally allocates all the memory of the system?
– Etc…
In TDD we test for errors not malice
QA may, in fact, want to test some of these scenarios
TDD does not replace QA
70 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Sustainability
TDD adoption often goes like this:
– Initial adoption: Team is un-familiar with the process, slows down, experiments, resolves problems
– Competence: Team “gets it” starts clicking, speeds up and gains confidence
– High Function: Team becomes extremely productive, produces quality code in a predictable way, QA backlog shrinks, happy-happy joy-joy
– Struggle: A new requirement causes multiple tests to fail, which must be repaired. The number of test failures increases by iteration
– Collapse: Test suite becomes un-maintainable, tests get disabled, TDD collapses under its own weight
71 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Interpretation
Java 2007 Conference, Jim Coplien:
“... one of the things we see in a lot of projects is that projects go south on about their 3rd sprint, and they crash and burn because they cannot go any further.”
Is this because TDD is not sustainable?
Maybe it’s because the developers are not writing good TDD tests
Good QA tests are not always good TDD tests
What are good TDD tests?
72 22 March 2012
Defining a “Good” TDD Test
“virtue”
73 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Good
A Good TDD “test” has three characteristics
1. The test will fail reliably for an expected reason
2. The test will never fail for any other reason
3. There is no other test that will fail for this same reason
74 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Must Fail
A test must fail when the behavior it covers is wrong
A test that can never fail is worse than no test at all:
– We think we have safety we don’t have
– We think the system is working when it’s not
– We think our spec is accurate when it is not
In test-first we always fail the test before we implement the solution code, to ensure it can fail
When testing legacy code, you must force a failure
Right now this is not verifiable after the fact, but we’re working on this
75 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Must Not Fail
A test that fails for a reason other than intended will mislead the team
– We try to solve problems we don’t have
– We miss the problems we do have
– If the “other reason” is covered by another test, they will be failing together
– This is a baaaaaaad road to be on
76 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
No Other Failure
A test should fail alone
Two tests failing for the same reason is bad…
…and becomes 3
…then 13
…then 30
…then they all get disabled
77 22 March 2012
TDD as Test-Driven Design
78 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Remember Our Initial Test (JUnit)
public class AssetTest {
private Random any = new Random();
@Test
public void testAssetFirstYearStraightLineCalculation() {
double anyValue = any.nextDouble();
int anyTerm = any.nextInt();
int yearToWriteOff = 1;
double straightLineResult = anyValue / anyTerm;
Asset testAsset = new Asset(anyValue, anyTerm);
assertEquals(straightLineResult,
testAsset.getWriteOff(yearToWriteOff), .02);
}
}
79 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Making it Compile, and Fail (Java)
public class Asset {
public Asset (double value, int term){}
public double getWriteOff(int year){
return 0.0;
}
}
80 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Making it Pass (Java)
public class Asset {
private double myValue;
private int myTerm;
public Asset (double value, int term){
this.myValue = value;
this.myTerm = term;
}
public double getWriteOff(int year){
return this.myValue / this.myTerm;
}
}
81 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
This Second Test Fails, At First (JUnit)
@Test
public void testAssetsAreCappedAtAMaximum(){
double cappedValue = Asset.CAP + 1;
double unCappedValue = Asset.CAP;
int term = any.nextInt();
int yearToWriteOff = 1;
Asset cappedAsset = new Asset(cappedValue, term);
Asset unCappedAsset = new Asset(unCappedValue, term);
assertEquals(Asset.CAP / term,
cappedAsset.getWriteOff(yearToWriteOff), .02);
assertEquals(unCappedValue / term,
unCappedAsset.getWriteOff(yearToWriteOff), .02);
}
82 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Implementing the Cap… (Java)
public class Asset {
public static final double CAP = 70000.00;
private double myValue;
private int myTerm;
public Asset (double value, int term){
this.myValue = value;
this.myTerm = term;
}
public double getWriteOff(int year){
return Math.min(this.myValue, Asset.CAP) /
this.myTerm;
}
}
What happens to the first test when we make this change?
83 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Will Pass Sometimes, Fail Sometimes… (JUnit)
public class AssetTest {
private Random any = new Random();
@Test
public void testAssetFirstYearStraightLineCalculation() {
double anyValue = any.nextDouble();
int anyTerm = any.nextInt();
int yearToWriteOff = 1;
double straightLineResult = anyValue / anyTerm;
Asset testAsset = new Asset(anyValue, anyTerm);
assertEquals(straightLineResult,
testAsset.getWriteOff(yearToWriteOff), .02);
}
}
84 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Information About the Design
This is a simple bit of code, but even so…
The making the second test pass causes the first test to fail randomly. This means they are coupled…
…but they aren’t. One test has no reference to the other
The coupling has to be in the production code
This tells us to consider other designs
85 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
One Possible Solution
If we pulled the “Capping Behavior” into its own class, then we could test it on its own
Cap Test
This would be a design change
This would also improve the cohesion of Asset
86 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Implement the Relationship (Java)
public class Asset {
private double myValue;
private int myTerm;
private AssetCap myAssetCap;
public Asset (double value, int term) {
this.myAssetCap = new AsssetCap();
this.myValue = value;
this.myTerm = term;
}
public double getWriteOff(int IgnoreYear) {
return myAssetCap.capValue(this.myValue)/this.myTerm;
}
}
87 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
However!
The test for AssetCap can only fail if AssetCap does not work
The test for Asset can fail if Asset fails, OR if AssetCap fails
We don’t want that, and it’s because we’ve created a dependency
Cap Test Asset
Test
88 22 March 2012
Breaking Dependencies in Testing
independent spirit award
89 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Mocking
Breaking dependencies for testing is a big subject, and it a major aspect of developer training
We’ll look at one example, using a hand-crafted Mock object in place of the dependency
We’ll also look at one example of injecting the Mock at runtime, for testing only
There are other ways to do all of this
90 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Step One, Extract Interface
This is a relatively simple refactor
Most tools will do it for you
It does point out the advantage of designing to Interfaces in general
91 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Step 2, Create Mock Object
You can write this yourself, or have it generated by a tool
Always returns the same value given, no cap actually applied
92 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Step 2, Simple Mock Code (Java)
public class MockAssetCap implements AssetCap {
public double capValue(double aValue) {
return aValue;
}
}
93 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Step 3, Inject the Dependency at Runtime (Java)
public class Asset {
private double myValue;
private int myTerm;
private AssetCap myAssetCap;
public Asset (double value, int term) {
this(new AssetCapImpl(), value, term);
}
public Asset (AssetCap assetCap, double value, int term) {
this.myAssetCap = assetCap;
this.myValue = value;
this.myTerm = term;
}
public double getWriteOff(int IgnoreYear) {
return this.myAssetCap.capValue(this.myValue) / this.myTerm;
}
}
Remember, this is only one way of doing this…
94 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
An Often-Missed Issue…
We know that Asset works
We know that AssetCap works
We have 100% coverage… or do we?
Is there a change that we could accidentally make in the future, that would break the system even though all tests would still pass?
95 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Broken Code, Passing Tests (Java)
public class Asset {
private double myValue;
private int myTerm;
private AssetCap myAssetCap;
public Asset (double value, int term) {
this(new AssetCapImpl(), value, term);
}
public Asset (AssetCap assetCap, double value, int term) {
this.myAssetCap = assetCap;
this.myValue = value;
this.myTerm = term;
}
public double getWriteOff(int IgnoreYear) {
return myAssetCap.capValue(this.myValue) / this.myTerm;
}
}
public class Asset {
private double myValue;
private int myTerm;
private AssetCap myAssetCap;
public Asset (double value, int term) {
this(new AssetCapImpl(), value, term);
}
public Asset (AssetCap assetCap, double value, int term) {
this.myAssetCap = assetCap;
this.myValue = value;
this.myTerm = term;
}
public double getWriteOff(int IgnoreYear) {
return this.myValue / this.myTerm;
}
}
…and you’ll still show 100% code coverage too!
96 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
“Lies, Damned Lies, and Code Coverage”*
//Pseudocode
public ReallyImportantClass {
public void GoshAwfulImportantBehavior(int param) {
//Lots of complicated stuff that has no return
}
public int Foo() {
int i;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++; i++;
i++;
return i;
}
*http://www.sustainabletdd.com (Thanks to Paddy Healey for the example)
97 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Missing Test
Our tests to this point are about behavioral boundaries
The other kind of test we often need are tests of proper workflow
Mocks can help us here too, if we create them properly
Be careful not to overdo this
You don’t want more coupling between your tests and production code than you need to form a complete specification
98 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
A Slightly Smarter Mock (Java)
public class MockAssetCap implements AssetCap {
private boolean gotCalled = false;
public double capValue(double aValue) {
gotCalled = true;
return aValue;
}
public boolean didGetCalled(){ return gotCalled;}
}
99 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
A Work-Flow Test (JUnit)
@Test
public void testAssetUsesAssetCap(){
AssetCapMock mock = new AssetCapMock();
Asset testAsset = new Asset(mock,
any.nextDouble(),
any.nextInt());
testAsset.getWriteOff(1);
assertTrue(mock.didGetCalled());
}
100 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Conclusions
In TDD, good tests are unique
In TDD, the suite is written as a complete spec
– All behavioral boundaries, workflows, and constants
The “D” in TDD is about “Driven” but also indicates a role in helping to see alternative “Designs”
…good design is also what patterns are about!
107
101 22 March 2012
The Role of Patterns in TDD
102 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Turtles All the Way Down
The most widely known version today appears in Stephen Hawking's 1988 book A Brief History of Time, which begins with an anecdote about an encounter between a scientist and an old lady:
A well-known scientist (some say it was Bertrand Russell) once gave a public lecture on astronomy. He described how the Earth orbits around the sun and how the sun, in turn, orbits around the centre of a vast collection of stars called our galaxy. At the end of the lecture, a little old lady at the back of the room got up and said: "What you have told us is rubbish. The world is really a flat plate supported on the back of a giant tortoise." The scientist gave a superior smile before replying, "What is the tortoise standing on?" "You're very clever, young man, very clever," said the old lady. "But it's turtles all the way down."
103 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Decorator Pattern
104 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Decorator Pattern In Action
Easily Testable
Dependant on Delegation
"Turtles all the way down"
105 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
The Decorator Pattern, Tested
A Mock Turtle
106 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
107 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
An Empowering Question
Design is about decisions
When you: – Understand how tdd tests work
– Understand how dependencies and can be tested with mock objects
– Let patterns suggest specific techniques for testing
Then you can ask the question: – How Would I Test This?
…whether you actually write the test or not
108 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Our New Blog
Sustainable Test-Driven Development Book in Progress
– www.sustainabletdd.com
109 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Blog
110 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Resources
Resources: www.netobjectives.com/resources – Ezines (regular online magazine) – Streamzines (PowerPoint with audio) – Articles and whitepapers – Pre/post course support Supporting materials – Quizzes – Recommended reading paths
Blogs and podcasts: blogs.netobjectives.com Annotated Bibliography After-Course Support (students only) Additional Training Two User Groups
– http://tech.groups.yahoo.com/group/leanagilescrum – http://tech.groups.yahoo.com/group/leanprogramming
Join our e-mail list to receive regular updates and information
about our resources and training of interest to you
111 Copyright © 2007 Net Objectives. All Rights Reserved. 22 March 2012
Q & A