A Journey to TDD - Part 1
Dave Schinkel 10/08/2013 01:11:00 AM TDD
Well it's time to start up my blog again. No need for a long intro here. Lets just dive into the good stuff.
I've had a lot of things on my mind lately on what to blog about.
Some immediate thoughts that came to mind:
- Webstorm IDE
- IoC / Dependency Injection
However one of the most important that I think every developer in our trade should be doing is Test Driven Development. And now's about the time I start pushing myself to do it. No more procrastination or excuses, TDD is no longer a nice-to-have or "we'll get there". It's essential to high quality Software Development. Some may disagree and you are entitled to your opinion. I am not here to debate TDD. I know what it can do, its power, and how it can make our lives easier as a Software Engineer having only done a little bit of it, but not enough to get a good taste of it yet.
You see I am tired of seeing methods that are 5+ lines long. I'm tired of seeing only Unit Tests done after code, which are really just Integration tests; sorry to break it to you folks, but these are not true unit tests and there's a major difference here.
First, please watch the following video before you continue on.
I've seen integration tests that were complete messes because:
- Developers often admit they have no clue what to unit test; they keep asking themselves what should we test for x,y,z methods????
- well when you practice TDD, you write tests based on use cases or user stories. You don't have to in the end "wonder" what should have code coverage and what specifically should I be testing
- The tests were testing more than one thing per test
- well this is a blatant violation of TDD
- A unit test should test and assert ONE thing...not 2, not 3, and God forsake you test more (I won't even go there)
- and of course you will have MANY very small tests but that is the point! because when tests fail, they fail at the lowest level in code, thus pointing you to the root cause quickly because your tests were small
What TDD brings to the table:
- Clean, SOLID, Readable, already tested, and extensible code is a side-effect of TDD
- Most devs who do TDD follow SOLID principals
- Allows you to immediately find cause of failure at the lowest level of code
- When used in conjunction with Continuous Integration, you get instant feedback across your entire code base frequently and since it's automated it becomes engraned in your development team's culture and way of getting things done
- Promotes much more communication among fellow developers and in many cases the business
- Encourages the creation of simpler, more focused libraries and APIs
- Promotes LEAN development, meaning the test you write via TDD are directly related to business requirements from use cases. So you are only writing the very minimal code you need to meet that use case. Code waste is drastically reduced and time savings are exponential because of it for the entire team and the business
You see when you are Test Driven, SOLID and clean code are an end product and occur naturally as a result of doing TDD. When you do TDD, it makes you constantly think and reassess HOW you are coding what you code. In other words, clean code, SOLID, and readable code is not an afterthought. It's core to what you do while you write your tests.
But of course, we know that TDD isn't easy to learn or to do perfectly the first time:
- Big learning curve up front
- yes you will slow down and invest time up front at first, but eventually whittles down to being routine not a huge deal later on
- Also that slowing down period is good. It makes you think about the code you write. You're forced to think about clean code, just by the nature of doing TDD. When you test first, you have to think about what you really need at a bare minimum which leads to cleaner, more readable code
- It takes time to learn to write good tests
- but over time you become better; don't let that deter you or prevent you from writing them, just write them, even if they're not perfect
- Mocking is not easy at first, but is a necessity as part of unit tests
The cost in terms of time it takes to dedicate and stick with learning TDD is worth it to me. I'd rather spend my time learning to write Test Driven Development, then to troubleshoot may methods that are many lines long, or classes that are ridiculously long (violating badly the SOLID principals), etc. all while continuously popping Advil all day long because sloppy code is giving me head spins. I'd rather live a healthy life at work and at home which means cleaner code will be healthier for all.
You see I know there's a tipping point, where the "hard" part of TDD will eventually fade away after hard work of learning it, and you know what that means? It means I'll be able to go home at 5pm each day to be with my family because why? Because we write Test Driven code.
TDD is one of the biggest steps a team can make to having a sane and enjoyable development shop where you find bugs early, not after QA finds them. It means when the business asks me hey Dave, are you guys able to add this new feature quick? I can say certainly but more than that, I know that the code we create for that feature will be solid, reliable, and already tested. There is no guess to what you should test because we are not writing integration tests (unit tests after the fact), your tests drove the creation of your real code so there's nothing to wonder about which frees up all that time other teams are aimlessly trying to figure out what integration tests to write and end up writing a ton of tests that are frankly useless because they aren't doing TDD.
Before I dive into the next part of my journey which is to start doing TDD, I wanted to list some very good resources I've collected over time. These are resources I've read, watched, etc. and are high quality in my opinion as it relates to the topic of Test Driven Development:
- Understanding Test Driven Development
- Roy Osherove - Mocks & Stubs sneak Peak
- Understanding Mock Objects
- Unit Testing Best Practices - Roy Osherove - Art of Unit Testing
- Naming standards for unit tests - Roy Osherove
- Unit Testing Best Practices
- Bouvet Developer Meetup - Roy Osherove on Unit Testing Good Practices
- Unit Testing Worst Practices
- Readable, Maintainable, Trustworthy Unit Tests
- Pairing with TDD Videos
- TDD Pairing Session 1 with Raymond Lim and Roy Osherove
- TDD and Pairing Session 2c: Go Game Engine with Raymond Lim
(in this talks about a lot of basics too, not really all advanced so view this as an intro as well. Uncle bob codes and shows you how to do TDD in this one, it's an excellent video to watch when first starting out with TDD)Other good links
- The Downfall of Agile Hitler
- Test-driven development: Write better code in less time
- An Introduction to Test Driven Devlopment in .NET
- Automated Testing & Inversion of Control
I'm not going to go into all the semantics at this point of TDD such as write your tests to fail, then refactor to make them pass, yada yada. That's for you to research. A good start are the resources above.
And Finally, as we all should, I have a lot of pride as a Software Craftsman.
Pride means the following to me:
- The code I write has to be read and maintained by other developers; the least I can do for my fellow teammates is to do my best to write clean code
- don't you hate working with sloppy code? of course you do, everyone does
- Just like Mechanical Engineers, Industrial Engineers, etc., we are Software Engineers first and foremost
- We are professionals, not code monkeys, not slaves. We are paid to write working software but IMO software that stands the test of time and does not kill you to maintain and extend (AKA SLOP)
- and I highly agree with Uncle Bob here that Speed Kills
- What I have produced for the business has an immediate impact and immediate results not only now but I want to feel like I have tried my best to make sure it's clean, readable, reusable, and extensible as possible so that it may be useful and continue to have an impact in the future
- I can have confidence in what I code and the business can have confidence in its products
- I continue to learn good coding habits as a side-effect of TDD
- It means I take my job seriously as a Software Craftsman
The purpose of this journey is to share what I learn as I transition to making TDD a first class citizen in my work habits as a Software Engineer developing code. Part 2 will transition into actually doing some TDD...
Until next time, I highly urge you to check out the resources I've listed above. Some are surprisingly entertaining as you will find out :).