Walking Dead TDD Daniel Hinojosa

Page created by Jesus Campos
 
CONTINUE READING
Walking Dead TDD
Daniel Hinojosa
TDD is Dead?
The Bait
“   Test-first fundamentalism is like abstinence-only sex ed: An unrealistic, ineffective morality campaign for
    self-loathing and shaming.

TDD is dead. Long live testing. (http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html)
DHH’s TDD Shaming
“   But whatever it started out as, it was soon since corrupted. Used as a hammer to beat down the
    nonbelievers, declare them unprofessional and unfit for writing software. A litmus test.
                                                                                      — David Heinemeier Hansson
                                                                                                      TDD is Dead
DHH’s TDD Conclusion
“   Yes, test-first is dead to me. But rather than dance on its grave, I’d rather honor its contributions than
    linger on the travesties. It marked an important phase in our history, yet it’s time to move on.

    Long live testing.
                                                                                       — David Heinemeier Hansson
                                                                                                       TDD is Dead
What is Test Driven Development?
Test Driven Development
 Using tests to drive your code

 Allows you to understand your code

 Model the API the way you want it to look

 Means of communicating an API before implementation
A little more about TDD
The TDD Rhythm
“   1. Quickly add a test.

    2. Run all tests and see the new one fail.

    3. Make a little change.

    4. Run all tests and see them all succeed.

    5. Refactor to remove duplication.

                                         — Kent Beck
              Test Driven Development by Example 2003
Another take on TDD
“   1. Write a failing test.

    2. Write code to make it pass.

    3. Repeat steps 1 and 2.

    4. Along the way, refactor aggressively.

    5. When you can’t think of any more tests, you must be done.

                                                                   — Neal Ford
                               Evolutionary architecture and emergent design 2009
Demo of TDD
Craps!
Benefits of TDD
 Evolutionary Design

 Ability to get rid of code

 Readable Code

 Refactoring with confidence

 Not Chained to your code and job

 Up front recognition of bugs

 Design software from the API perspective
But, What was DHH’s solution? Step one
“   Step one is admitting there’s a problem. I think we’ve taken that now.
DHH’s solution? Step two
“   Step two is to rebalance the testing spectrum from unit to system. The current fanatical TDD experience
    leads to a primary focus on the unit tests, because those are the tests capable of driving the code design
    (the original justification for test-first).
What is wrong with DHH’s TDD’s View?
 TDD never wants you not to do system testing.

 TDD is for instant feedback

 Don’t just solely relegate continuous integration to be testing heavy tests

 Clarifies later that unit testing (albeit after the fact) is valuable, though not TDD (Somewhat inconsistent)
TDD vs. Testing After the Fact
  Testing After the Fact is not TDD

  Testing After the Fact will never be TDD

  Testing After the Fact leads to inelegant solutions

  Testing After the Fact will often lead to: "Meh, Looks good" testing
Huge Point of Disagreement
“   System testing only and Test After the Fact leads to vastly different code.
Disagreeable Code That Could Possibly be Prevented with TDD?
Constructors do the real work
   new keyword in a constructor

   static method calls in a constructor or at field declaration

   Anything more than field assignment in constructors

   Object not fully initialized after the constructor finishes (watch out for initialize methods)

   Control flow (conditional or looping logic) in a constructor

   Code does complex object graph construction inside a constructor rather than using a factory or builder

   Adding or using an initialization block

Guide Writing Testable Code (http://misko.hevery.com/code-reviewers-guide/)
Digging into Collaborators
   Objects are passed in but never used directly (only used to get access to other objects)

   Law of Demeter violation: method call chain walks an object graph with more than one dot (.)

   Suspicious names: context, environment, principal, container, or manager

Guide Writing Testable Code (http://misko.hevery.com/code-reviewers-guide/)
Brittle Global State & Singletons
   Adding or using singletons

   Adding or using static fields or static methods

   Adding or using static initialization blocks

   Adding or using registries

   Adding or using service locators

Guide Writing Testable Code (http://misko.hevery.com/code-reviewers-guide/)
Class does too much
   Summing up what the class does includes the word “and”

   Class would be challenging for new team members to read and quickly “get it”

   Class has fields that are only used in some methods

   Class has static methods that only operate on parameters

Guide Writing Testable Code (http://misko.hevery.com/code-reviewers-guide/)

What about PowerMock?
Ambulance

But who do I blame for such transgressions?
We are humans!

 Human nature has rules to ensure that we meet criteria in a society

 ..or a project

 Humans break rules for both good and bad reasons

 What determines whether it is a good or bad reason is why it was implemented in the first place…(Programmer Confidence)

 Humans break rules prematurely because they believe they have enough experience to break those rules
We are humans!

 Humans are arrogant

 Unexperienced Humans are especially arrogant (I was one)

 Do you want to form a culture and project with arrogant unexperienced programmers?

 Money and lots of it is pumped into software projects, you are allowed to make certain demands if it is your project
There is bad code out there, and a lot of it!
  Gets worse without TDD

  TDD forms a way of thinking

  TDD creates decoupled code, therefore reuseable code

  Arrogance breeds bad code

  Bad Code (Long lines with margins deep)

  Large Cyclomatic Complexity
"Letting go of TDD" doesn’t work
  I don’t continuously work on the same project, I need to refamiliarize myself with an old project.

  Documentation? Ok. Documentation doesn’t have good relationship to the code.

  Method names are useless onto themselves, knowing how it works with a test suite that doesn’t require set up works well!

  I have let myself slip, due to deadlines, and I am an experienced programmer.

  Scattered logic caused me to delete my code and start again.
Kent Beck
“   "As a programmer, do you deserve to feel confident?" (Can you sleep at night knowing your code works)
                                                                                                   — Kent Beck
                                                                               Is TDD Dead? You Tube Video Series
Martin Fowler
“   "The primary benefit of TDD is self testing code"
                                         — Martin Fowler
                          Is TDD Dead? You Tube Video Series
My take on Martin Fowler’s Quote
“   Extends what the compiler does, to check with your domain if what you are doing is accurate.
Robert Martin
“   I know this sounds strident and unilateral, but given the record I don’t think surgeons should have to
    defend hand-washing, and I don’t think programmers should have to defend TDD.
                                                                                                            — Robert Martin
                                                        The Clean Coder: A Code of Conduct for Professional Programmers 2011
Michael Feathers
“   To me, legacy code is simply code without tests.
                                        — Michael Feathers
                    Working Effectively with Legacy Code 2004
Rich Hickey
“   "I think we’re in this world I’d like to call Guard Rail Programming… 'I can make change because I have
    tests!' Who does that? Who drives their car around, banging against the guard rails? Do the guard rails
    help you get to where you want to go?"
                                                                                                — Rich Hickey
                                                                                        Guard Rail Programming

Bringing back TDD from the dead…
Why do we fail?
  Takes a lot of time

  Mocking is kind of an inane practice

  Over Testing/Violating YAGNI/Testing Useless Stuff

  Poor exception handling

  We weren’t taught that way

  I don’t know what I want when I start

  We do not leave our code alone
Do the new or alternative testing frameworks help us make it easier?
Cucumber-JVM (Java)
Calculator.feature

  Scenario: The calculator should add two numbers from a feature
     Given a calculator instance
     When the sum method is given two numbers, 4 and 9
     Then the calculator should return the sum of the two numbers

https://github.com/cucumber/cucumber-jvm
Cucumber-JVM (Java)
 public class CalculatorFeatureSteps {
     private Calculator calculator;
     private int actual;
     private int expected;

     @Given("^a calculator instance$")
     public void a_calculator_instance() throws Throwable {
         calculator = new Calculator();
     }

     @When("^the sum method is given two numbers, (\\d+) and (\\d+)$")
     public void the_sum_method_is_given_two_numbers(int number1, int number2) throws Throwable {
         actual = calculator.sum(number1, number2);
         expected = number1 + number2;
     }

     @Then("^the calculator should return the sum of the two numbers$")
     public void the_calculator_should_return_the_sum_of_the_two_numbers() throws Throwable {
         Assert.assertTrue(actual == expected);
     }
 }

https://github.com/cucumber/cucumber-jvm
Do Alternate Languages help us?
Spock (Groovy)
 class Math extends Specification {
     def "maximum of two numbers"(int a, int b, int c) {
         expect:
         Math.max(a, b) == c

         where:
         a | b |   c
         1 | 3 |   3
         7 | 4 |   4
         0 | 0 |   0
     }
 }

http://spock-framework.readthedocs.org/en/latest/data_driven_testing.html
ScalaCheck (Scala)
 import org.scalacheck.{Prop, Properties}

 object BasicScalaCheckProperties extends Properties("Simple Math"){
   property("Sum is greater or equal to its parts") =
     Prop.forAll {(x:Int, y:Int) => x+y >= x && x+y >= y}

     property("Sums are associative") = Prop.forAll {
       (x:Int, y:Int) => x+y == y+x
     }
 }

Simple Properties Bites Quick and Fierce
 [info] ! String.Sum is greater than its parts: Falsified after 0 passed tests.
 [info] > ARG_0: 0
 [info] > ARG_1: 0
 [error] Failed: : Total 1, Failed 1, Errors 0, Passed 0, Skipped 0
Test.Generative (Clojure)
 (defspec integers-closed-over-addition
   (fn [a b] (+' a b))    ;; input fn
   [^long a ^long b]      ;; input spec
   (assert (integer? %))) ;; 0 or more validator forms
The Flying Wallendas
Links and Credits
  TDD is dead long live testing - http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html

  Mocks are not stubs - http://martinfowler.com/articles/mocksArentStubs.html

  Neal Ford - Evolutionary architecture and emergent design: Test-driven design, Part 1: http://www.ibm.com/developerworks
  /java/library/j-eaed2/

  Miško Hevery - Static Methods are Death to Testability http://misko.hevery.com/code-reviewers-guide

  Nicole Adams - 10 Most Horrific Accidents in History [http://listverse.com/2013/04/22/10-most-horrific-circus-accidents-
  in-history]
Questions?
Thank You
   Email: dhinojosa@evolutionnext.com

   Github: https://www.github.com/dhinojosa

   Twitter: http://twitter.com/dhinojosa

   Google Plus: http://gplus.to/dhinojosa

   Linked In: http://www.linkedin.com/in/dhevolutionnext

Last updated 2014-10-19 07:09:49 MDT
You can also read