QUESTIONS C S 3 5 1 - D e s i g n o f L a r g e P r o g r am s LAST TIME: - Administrivia; Opening rant: Who are you, TDD TODAY: - Administrivia - Deathbox questions - Discussion: Hacking; testing - Refactoring 1: The exploding class, interfaces, abstract classes HOMEWORK: - Join email list: http://mail.cs.unm.edu/cgi-bin/mailman/listinfo/cs351 >>>>>INCLUDE YOUR NAME IF IT ISN'T OBVIOUS FROM YOUR EMAIL!!!<<<<< HOMEWORK DUE >>TUESDAY AUG 27TH AT 9AM<< - Test and implement the DeathBox as discussed below - Turn-in instructions will be sent to the class email list: Subscribe now! RECIPES FOR DISASTER DEATH MARCH: The long, lingering final countdown to a ship date, involving 16-25-hour days, catnaps on couches, and plenty of 'flat food'; (food, mostly from vending machines, that you can slip under people's doors so they can keep working). `Microspeak' ADMINISTRIVIA - Attendance - Opening-day handout: READ IT - Be sure to SIGN and RETURN the back page, and pick a PIN - Get on the list: http://mail.cs.unm.edu/cgi-bin/mailman/listinfo/cs351 >>>>>INCLUDE YOUR NAME IF IT ISN'T OBVIOUS FROM YOUR EMAIL!!!<<<<< DEATHBOX QUESTIONS Q: I thought I saw that the deathbox was due next Tuesday at NOON. A: That's not a question. Q: Didn't the slides say deathbox was due at NOON? That's DURING class! A: Yes, that was a bug. We need it to be due _BEFORE_ the next class, because we are going to TALK ABOUT IT DURING the next class. Q: I've found this problem with the spec A: Don't tell us about it! Write it into your spec-problems.txt! Q: JUnit 3.8.1 or JUnit 4.x? A: Either is OK, at least for now. JUnit 4 has some technical advantages but is also a little more exotic (with those weird @Test 'annotation' things..) DISCUSSION http://paulgraham.com/gh.html - Define, defend, and attack Paul Graham's thesis in 'Great Hackers'. DISCUSSION http://paulgraham.com/gh.html - Define, defend, and attack Paul Graham's thesis in 'Great Hackers'. = Some people are (much much much) better hackers than others = They love to program; they('d) do it for fun = Tools and interesting projects matter = How do you hack at home? = Nasty little problems don't teach = Tuning out DISCUSSION http://paulgraham.com/gh.html - Define, defend, and attack Paul Graham's thesis in 'Great Hackers'. = Some people are (much much much) better hackers than others = They love to program; they('d) do it for fun = Tools and interesting projects matter = How do you hack at home? = Nasty little problems don't teach = Tuning out http://junit.sourceforge.net/doc/testinfected/testing.htm - Define, defend, and attack what the JUnit'ers are saying DESIGN - the size of code - toy and beyond - what programming is really all about - pictures, paper, principles - UML CRAFT - understanding specs - finding the corner cases - efficient work practices - clean coding ABC - TDD TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); f.setBaz(17); assertEqual(17, f.getBaz()); f.setBaz(3); assertEqual(3, f.getBaz()); .. TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); for (int i = 0; i<10; ++i) { f.setBaz(i); assertEqual(i, f.getBaz()); } .. TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); for (int i = -123456; i<246810; ++i) { f.setBaz(i); assertEqual(i, f.getBaz()); } .. TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); for (int i = -123456; i<246810; i += 35791) { f.setBaz(i); assertEqual(i, f.getBaz()); } .. TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); for (int i = -123456; i<246810; i += 35791) { f.setBaz(i); assertEqual(i, f.getBaz()); } .. - How much testing is enough? - 'Edge' cases .. 'corner' cases .. 'random' cases .. TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); for (int i = -123456; i<246810; i += 35791) { f.setBaz(i); assertEqual(i, f.getBaz()); } .. - How much testing is enough? - 'Edge' cases .. 'corner' cases .. 'random' cases .. = they were never wrong, the old masters TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications ..from the Foo spec.. "setBaz(int) sets Baz to the supplied argument." ..in 'class FooTest'.. .. Foo f = new Foo(); f.setBaz(Integer.MAX_VALUE); assertEqual(Integer.MAX_VALUE, f.getBaz()); .. - How much testing is enough? - 'Edge' cases .. 'corner' cases .. 'random' cases .. = they were never wrong, the old masters TDD - TEST DRIVEN DEVELOPMENT - Old days: Tests are a poor substitute for proofs of correctness! = "Tests can only expose flaws, they cannot prove there are no flaws" - New days: = Tests are like executable partial specifications = Tests are like executable 'how to use' comments on a bit of code = Tests are like executable design notes and clarifications = Tests are like frozen debugging snapshots - Debugging vs writing tests - Drinking the koolaid: = Writing all the tests first, _then_ implementing the methods CRAFT - REFACTORING CODE CRAFT - REFACTORING CODE - 'Refactoring' is changing the design of code WITHOUT changing what the code DOES. - (Why on earth would anybody do that?? Wouldn't that be a total waste of time?) CRAFT - REFACTORING CODE - 'Refactoring' is changing the design of code WITHOUT changing what the code DOES. - (Why on earth would anybody do that?? Wouldn't that be a total waste of time?) - Refactoring Hello World REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: (1) Add a method to the class, called perhaps 'run()' or something, (2) Migrate the behavior in the main to run(), (3) In the main, build an instance of the class and call run() on it REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: (1) Add a method to the class, called perhaps 'run()' or something, (2) Migrate the behavior in the main to run(), (3) In the main, build an instance of the class and call run() on it BEFORE: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } } REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: > (1) Add a method to the class, called perhaps 'run()' or something, (2) Migrate the behavior in the main to run(), (3) In the main, build an instance of the class and call run() on it DURING(1): public class HelloWorld { public void run() { } public static void main(String[] args) { System.out.println("Hello World"); } } REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: (1) Add a method to the class, called perhaps 'run()' or something, > (2) Migrate the behavior in the main to run(), (3) In the main, build an instance of the class and call run() on it DURING(2): public class HelloWorld { public void run() { System.out.println("Hello World"); } public static void main(String[] args) { } } REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: (1) Add a method to the class, called perhaps 'run()' or something, (2) Migrate the behavior in the main to run(), > (3) In the main, build an instance of the class and call run() on it DURING(3): public class HelloWorld { public void run() { System.out.println("Hello World"); } public static void main(String[] args) { HelloWorld hw = new HelloWorld(); hw.run(); } } REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: (1) Add a method to the class, called perhaps 'run()' or something, (2) Migrate the behavior in the main to run(), (3) In the main, build an instance of the class and call run() on it AFTER: public class HelloWorld { public void run() { System.out.println("Hello World"); } public static void main(String[] args) { HelloWorld hw = new HelloWorld(); hw.run(); } } -> External behavior completely unchanged by the refactoring (as always) -> Internal structure of code is now more useful, more _evolvable_ REFACTORING HELLO WORLD What: Evacuate 'public static void main(String[])' of any significant behavior. Why: Only Java _applications_ (as opposed to Java applets, for example) even call 'public static void main(String[])' How: (1) Add a method to the class, called perhaps 'run()' or something, (2) Migrate the behavior in the main to run(), (3) In the main, build an instance of the class and call run() on it AFTER: public class HelloWorld { public void run() { System.out.println("Hello World"); } public static void main(String[] args) { HelloWorld hw = new HelloWorld(); hw.run(); } } -> External behavior completely unchanged by the refactoring (as always) -> Internal structure of code is now more useful, more _evolvable_ -> This is not rocket surgery.. We have these patterns at our fingertips.