640 likes | 738 Views
Common Objections to TDD (and their refutations). Seb Rose Twitter: @sebrose Blog: claysnow.blogspot.com E-mail: seb@claysnow.co.uk Phone: 01721 788178. Agenda. Motivation Education Inappropriate project Cultural Time pressures Unclear benefits. Refutations. Really?. re·fute
E N D
Common Objections to TDD(and their refutations) Seb Rose Twitter: @sebrose Blog: claysnow.blogspot.com E-mail: seb@claysnow.co.uk Phone: 01721 788178
Agenda • Motivation • Education • Inappropriate project • Cultural • Time pressures • Unclear benefits
Refutations. Really? re·fute /rɪˈfyut/ verb(usedwithobject),re·fut·ed,re·fut·ing. • toprove to be false or erroneous, as an opinion or charge. • to prove (a person) tobein error.
TDD – in one slide • Test First predates XP and Agile • TDD has been around for a while • One of XP’s core practices • Widely referenced • Still quite controversial • I am not going to describe TDD in any detail • Red/Green/Refactor (and variants) • ‘T’ for Test has unfortunate connotations • First ‘D’ definitely stands for Driven • Second ‘D’ may stand for Development or Design
Survey • Simple survey ran for 3 months • Jan – Mar 2012 • 260 unique respondents • 896 objections • “What reasons are there not to practice TDD” • “The question wreaks of elitism - it should instead be ‘what reasons are there to practice TDD’”. • Free text made for a wide range of responses • Harder to analyse • Split into 18 types, grouped into 5 categories
Breakdown • Education (223) • Lack of Practice, Lack of Investment • Project (194) • Domain, Legacy, Environment, Tooling • Cultural (179) • Management, Team, Fanaticism, Demarcation, Egotism • Time (174) • Slowness of development, maintenance and execution • Benefits (120) • Lack of Proof & Experience, Alternatives
Interconnectedness of all things • Classification is subjective • Many responses could be categorised several ways • Respondents had different points of view • Their own objections • Objections they had heard others express • Further analysis required • Follow-up survey(s)
Software Crisis! The required techniques of effective reasoning are pretty formal, but as long as programming is done by people that don't master them, the software crisis will remain with us and will be considered an incurable disease. And you know what incurable diseases do: they invite the quacks and charlatans in, who in this case take the form of Software Engineering gurus. - Dijkstra(ACM Turing Award Lecture 1972)
Fanaticism and Fluff The steps of FDD are simple: • Take a tiny piece of fluff from the plate and put it on your head, holding your head quite still to ensure that the fluff does not fall off your hair. • Write a line of code. • Say, “I am the Fluff Lord, within the Dominion Of The Fluffists.” • Repeat. That’s it. Seriously, that’s all there is to it.
Agenda • Motivation • Education • Inappropriate project • Cultural • Time pressures • Unclear benefits • Wrap up
Hard to learn • “TDD is hard.” • Yes, it is • Any technique is hard to master • Fundamental changes are hard to adopt • 10,000 hours of practice • Did you stop trying to ride a bicycle when you fell off?
Where to start • “Sheer lack of knowledge on how to approach it appropriately. There are too many bowling examples and not enough practicality.” • How do you usually learn something new? • Unit Testing skills are foundational • Coding Dojo to practice TDD • http://cyber-dojo.com • Better used as a group, but still useful solo
Tests before code • “The compiler complains if I write tests before the code” • First step to get to green is to make the test compile • Only then can you move on to make the test pass
Tests will be buggy • “Your test code is just your production code, written from the other end (i.e. just as complex and likely to have bugs)” • No process is infallible • “To err is human …” • Safety in numbers • Pair programming • Peer review
Unfamiliar architectural style • “How will we ever know what’s going on if we can't see all of the code at once?” • TDD tends to lead to small, concise implementations • Low coupling • High cohesion • “Proliferation” of interfaces • Literate-ish programming
No design improvement • “My observations of code from TDD-based projects show no significant improvement in architecture, security, code style, testability, etc. over other projects built with testing in mind.” • TDD ensures testability • Tendency for smaller decoupled composition • YAGNI & Emergent Design • Other design concerns (e.g. security, performance etc.) not addressed by TDD
Learning several things at once • “In a new technology, it's too difficult to learn how to TDD as well as how to master that technology.“ • Even if you are experienced with TDD, it changes your perspective on the new technology • Idioms • Tooling • Kent Beck suggests reimplementingxUnit in the new language
Discipline • “TDD is a discipline and a work habit. It's very difficult to establish the habit.” • Habits are hard to form, but also hard to break. • Nothing works better than positive feedback • There are many self-help guides available • Switch – Chip & Dan Heath • Drive – Dan Pink
Agenda • Motivation • Education • Inappropriate project • Cultural • Time pressures • Unclear benefits • Wrap up
Too simple • "This code is too simple to need a test“ • Then the tests will be simple too • What’s simple to you may be opaque to others • As the code evolves, tests can help keep it simple
Just a spike • “Because you're prototyping an idea and it's much faster to spike without tests. If you do end up using the code then you can write tests and refactor.” • Use the right tool – TDD is not mandatory • Discipline to ensure spike does not mutate • “Write one to throw away” • TDD the spike anyway!
Not useful for all aspects of design • “I don't think that deriving a design by writing tests is a useful practice. Tests by themselves cannot cover many aspects of a design (designing for concurrency and performance in particular by writing tests is something that I've never seen anyone do).” • TDD is not the only tool in the toolbox • Probably wrong tool for performance testing • Can be applied to concurrency testing (but not recommended)
Not useful for functional/declarative programming • “Because it is largely adequate in imperative programming and not when you go functional and declarative - when code reads like specification.” • Orthogonal. • Absence of side effects makes testing MORE effective. • Discuss!
Legacy code • “Difficulty starting with legacy code. A simple change done through TDD can take orders of magnitude longer due to a need to redesign toward testability. ” • Working Effectively With Legacy Code – Feathers • Small, conservative steps, eventually tame fear and doubt • Consider less intrusive approaches initially • e.g. TextTest – texttest.org
Insufficient tooling • “There is no unit-test framework for the language I'm using, and I don't have time/inclination to develop one myself.” • There probably is. • You might not need one • “TDD in C” – OlveMaudal
GUI • “I do a lot of UI code and don't really know how to properly do that with TDD.” • “Subcutaneous” testing • Presenter First pattern • Based on MVC/MVP patterns • Very shallow view, with no business logic • Stateless presenter orchestrates interaction between view and model
Excessive coupling to data • “A test expresses a unit of change as data that fits the needed computation. Creating that data is harder than writing the program that accomplishes the change.” • Unit tests preferably utilise ‘small’ amounts of data • For domains where this is not possible • You will need large amounts of data irrespective of test approach • Bootstrap process with constructed data • Continue with captured data
Agenda • Motivation • Education • Inappropriate project • Cultural • Time pressures • Unclear benefits • Wrap up
Management antipathy • “Management want results NOW; very much willing to clean up small oversights later. 'Close is good enough' attitude.” • Management are generally result focused • Previous bad experiences affect appetite for change • Both ways! • Start small • Need to demonstrate benefit to ‘bottom line’
Team resistance • “Teammates are not prepared. They do not have enough knowledge or experience in unit testing.” • “No one tells me how to program!” • Changing behaviours is hard • “Fearless Change” has many patternsfor introducing change
I never make mistakes • “I already know what the code needs to do and it's low risk. I don't need a test for it.” • “My first design idea is always perfectly good.” • “My code always works the first time.” • Do people really believe this? • Even if they do, is everyone that ever touches the code going to be so talented?
Testing is for testers • “We don't need TDD, we've got a QA department. They'll find the bugs for us.” • TDD is not just about testing • Drives design • Refactoring/regression safety net • Write tests to explore EVERY defect you find • Living documentation • Helps future developers understand intended behaviours
All TDD-ers are fanatics • “It has become a cult. Its advocates have made it antithetical to ‘Individuals and interactions over processes and tools’. It is evangelized through coercion and browbeating -- necessarily, as it isn't compelling on it's own.” • “Someone needs to tell unclebob that he might be right, but he's part of the problem - to non-modern coders (which felt like the majority last time I looked) he comes across like a raving loony.”
Fluff (continued) If at any time you even THINK about writing a line of code before putting fluff on your head, then you’ve to delete all your code, shake all the fluff from your head onto the plate and start all over again. I have been practicing FDD for 12 years now; sometimes in the office, I have so much fluff on my head that my boss thinks I’m a hay-stack, only made of fluff. A sort-of fluff-stack, if you will. But one thing is beyond doubt: the code I write, when I’m in this fluff-zone, is the most high-quality code that anyone has ever seen.
Agenda • Motivation • Education • Inappropriate project • Cultural • Time pressures • Unclear benefits • Wrap up
More code to write • “Takes too much time to write test.” • How will your code get tested? • Test team? • Customers & Stack Trace Driven Development? • How much time will be spent figuring out how to make changes later? • What proportion of your time do you actually spend coding?
More code to maintain • “If I change something it will break a whole bunch of tests that I will have to fix and it will be more work for me in the end than just verifying my changes manually.” • It is USEFUL to know when behaviour changes • Foundational Unit Testing skills reduce brittleness • next 6 slides
Testability • Testability needs to be designed in • TDD ensures code is testable • Code with hidden dependencies is hard to test • Dependency Injection/Inversion • Pass dependencies into code under test • Write factories that permit injection of test doubles • Interfaces should be cohesive • Wide interfaces encourage unnecessary coupling • Avoid globals, singletons etc. • Retro-fitting unit tests is hard • Take small steps • Introduce a ‘seam’ – c.f. Working Effectively with Legacy Code
Necessity • Test observable behaviour • Don’t modify encapsulation to aid testing • If a behaviour isn’t observable through the public interface what is it for? • Don’t slavishly write one test per method • Test behaviours • Some methods may not need any dedicated tests • Methods that implement useful behaviours may need many tests • Choose test variants carefully • Edge conditions • Invalid inputs • Multiple invocations • Error signalling
Granularity • Test a SINGLE observable behaviour • It is tempting to combine related behaviours in a single test – DON’T • … even if EXACTLY the same steps are needed public void shouldSortTwoStringsAndReportCorrectSize() { SortedSet<String> animals = new TreeSet<String>(); animals.add(“Zebra”); animals.add(“Anteater”); assertEquals(2, animals.size()); assertEquals(“Anteater”, animals.first()); assertEquals(“Zebra”, animals.last()); }
Understandability • Name tests to describe the behaviour under test • Describe nature of the test • Is it checking that preconditions are enforced? • Is a dependency going to signal an error? • Long names are fine – you only type them once • Be precise • shouldReturnCorrectValue is not a good name for a test • shouldReturnCorrectSumOfTwoIntegersWithoutOverflow • should_return_correct_sum_of_two_integers_without_overflow • When a test fails you want to know WHAT WENT WRONG • You don’t want to reverse engineer the test • You don’t want to run smaller tests to isolate the failure
Maintainability • Unit Tests should be written to same quality as Production code • Tests will be maintained and read just as often as production code • Code is communication to other developers not just a compiler • Organise tests into cohesive suites • Refactor tests to avoid duplication • Use suites to perform common set up/tear down operations • Extract common code into methods • Extract common functionality into classes • Remove redundant tests
Reiteration: 5 -ities • Testability • Necessity • Granularity • Understandability • Maintainability • MUNGT ? • TeNGUM?
Mock-based tests rot • “Unit-test mock/stub assumptions rots” • Use collaboration and contract tests – J.B. Rainsberger • Collaboration tests make assumptions about the contract; contract tests try to justify those assumptions • A stub in a collaboration test must correspond to an expected result in a contract test • An expectation in a collaboration test must correspond to an action in a contract test
That library is third party • “API layers above and below you don't provide adequate mocks. Testing against the ‘real thing’ is hard/impossible.” • “Don't mock types you don't own” – Joe Walnes • Write adapters that provide a domain specific API • Write acceptance tests that verify the library’s behaviour • Run whenever adopting a new version
Slow execution • “Running the tests takes too long.” • For TDD to work tests need to (build and) execute in seconds • Some environments need careful configuration • C/C++ • Rails • Are they really Unit Tests? (See next slide)
A test is not a unit test if: • It talks to the database • It communicates across the network • It touches the file system • It can’t run at the same time as other unit tests • You have to do special things to your environment (such as editing config files) to run it (Michael Feathers’ blog, 2005)