160 likes | 288 Views
Something I understand about the book. Working Effectively with Legacy Code written by Michael Feathers. Contents. The Book Definition of Legacy Code Problems of the Conservative Approach The Automatic Test Approach Example of Characterization Test Breaking Dependencies (not yet ready)
E N D
Something I understand about the book Working Effectively with Legacy Code written by Michael Feathers
Contents • The Book • Definition of Legacy Code • Problems of the Conservative Approach • The Automatic Test Approach • Example of Characterization Test • Breaking Dependencies (not yet ready) • Seams (not yet ready) • Conclusion: the complaints/solutions matrix
The Book Robert C. Martin Series Michael C. Feathers Paperback: 456 pages Publisher: Prentice Hall PTR; 1 edition (October 2, 2004) http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
What is legacy code? (for me/us?) • Code that: • is difficult to understand • is fragile • is difficult to modify • is not (or not well) documented • has been inherited from others • But that : • is still useful!
What is legacy code? (M.Feathers) • M.Feathers says: Legacy Code ≡ Code without automatic tests • Why?
The conservative approach If it ain't broke don't fix it No automatic tests leads to Manual testing thatleads to High risk of introduce bugs that leads to Fear of change so You prefer add more mess instead cleaning up the existing code and the code get worse, the cost/time of adding features increases
Preserving Behaviour with Characterization Tests • Write tests for an existings program • Write a test that “Describe” the actual behaviour • Use these test as regression tests during the refactoring/feature addition. Please note that: “actual” is not always the same as “correct”.
Characterization Tests Example (1/5) public static int[] slaDjcl(double djm) { long ld, jd, n4, nd10; if ((djm <= -2395520.0) || (djm >= 1e9)) { throw new IllegalArgumentException("MJD out of valid range"); } ld = (long) djm; jd = ld + 2400001L; n4 = 4L * (jd + ((6L * ((4L * jd - 17918L) / 146097L)) / 4L + 1L) / 2L - 37L); nd10 = 10L * (((n4 - 237L) % 1461L) / 4L) + 5L; int[] ret = new int[3]; ret[0] = (int) (n4 / 1461L - 4712L); ret[1] = (int) (((nd10 / 306L + 2L) % 12L) + 1L); ret[2] = (int) ((nd10 % 306L) / 10L + 1L); return ret; }
Characterization Tests Example (2/5) @Test public void testSlaDjcl() { assertArrayEquals(new int[]{},slaDjcl(0.0)); } Testcase: testSlaDjcl(prova.ProvaTest): FAILED array lengths differed, expected.length=0 actual.length=3 junit.framework.AssertionFailedError: array lengths differed, expected.length=0 actual.length=3 at prova.ProvaTest.testSlaDjcl(ProvaTest.java:19)
Characterization Tests Example (3/5) @Test public void testSlaDjcl() { assertArrayEquals(new int[]{0,0,0},slaDjcl(0.0)); } Testcase: testSlaDjcl(prova.ProvaTest): Caused an ERROR arrays first differed at element [0]; expected:<0> but was:<1858> arrays first differed at element [0]; expected:<0> but was:<1858> at prova.ProvaTest.testSlaDjcl(ProvaTest.java:19)
Characterization Tests Example (4/5) @Test public void testSlaDjcl() { assertArrayEquals(new int[]{1858,11,17},slaDjcl(0.0)); } BUILD SUCCESSFUL (total time: 0 seconds)
Characterization Tests Example (5/5) @Test public void testSlaDjcl() { assertArrayEquals(new int[]{1858,11,17},slaDjcl(0.0)); assertArrayEquals(new int[]{-3617, 1, 24},slaDjcl(-2000000.0)); assertArrayEquals(new int[]{10346, 5, 23},slaDjcl(3100000.0)); assertArrayEquals(new int[]{24309, 9, 19},slaDjcl(8200000.0)); assertArrayEquals(new int[]{38273, 1, 15},slaDjcl(1.33E7)); assertArrayEquals(new int[]{52236, 5, 14},slaDjcl(1.84E7)); assertArrayEquals(new int[]{66199, 9, 10},slaDjcl(2.35E7)); assertArrayEquals(new int[]{80163, 1, 7},slaDjcl(2.86E7)); assertArrayEquals(new int[]{94126, 5, 6},slaDjcl(3.37E7)); assertArrayEquals(new int[]{108089, 9, 1},slaDjcl(3.88E7)); assertArrayEquals(new int[]{122052, 12, 29},slaDjcl(4.39E7)); assertArrayEquals(new int[]{136016, 4, 27},slaDjcl(4.9E7)); assertArrayEquals(new int[]{149979, 8, 25},slaDjcl(5.41E7)); assertArrayEquals(new int[]{163942, 12, 22},slaDjcl(5.92E7)); assertArrayEquals(new int[]{177906, 4, 20},slaDjcl(6.43E7)); assertArrayEquals(new int[]{191869, 8, 16},slaDjcl(6.94E7)); assertArrayEquals(new int[]{205832, 12, 13},slaDjcl(7.45E7)); assertArrayEquals(new int[]{219796, 4, 10},slaDjcl(7.96E7)); assertArrayEquals(new int[]{233759, 8, 8},slaDjcl(8.47E7)); assertArrayEquals(new int[]{247722, 12, 5},slaDjcl(8.98E7)); assertArrayEquals(new int[]{261686, 4, 2},slaDjcl(9.49E7)); }
The TDD algorithm • 0. Get the class you want to change under test. • 1. Write a failing test case. • 2. Get it to compile. • 3. Make it pass. (Try not to change existing code as you do this.) • 4. Remove duplication. • 5. Repeat.
Thanks Andrea Francia http://andrefrancia.it/ http://blog.andreafrancia.it andrea@andreafrancia.it These slide will be available at my blog.