Today, I had the pleasure of attending a talk titled "API Design for Testability" that was given by Mr. Osherove himself. The talk's abstract reads:
The thing that I appreciated about this talk was that Roy was very easy going and he liked to mention that being Agile means "anything" is fine. There are definitely special cases where you would do some design up front before writing any code or tests (imagine that...) and that's alright.
Roy gave a simple definition (that he came up with) for writing unit tests. He states that a unit-testable system should be easy to write tests for that follow the PC-COF rules:
The rules above are intended for a base set of unit tests that can be run with not dependencies, you can simply right-click in NUnit/JUnit and see green across the charts. The idea is to create a "core" set of tests that are independent of configuration files / connection strings / static classes and more. Then create a layer on top of that to do integration and regression testing. According to Roy the "core" tests are the real unit tests.
The demos were very nice, I think I prefer technical demo's to completely theoretical, powerpoint driven, presentations. Roy's demos were clear and well prepared. He mentioned and demoed the Inversion of Control pattern is a concept, and an associated set of programming techniques, in which the control flow is inverted compared to the traditional interaction model expressed in imperative style by a series of procedure calls. Thus, instead of the programmer specifying, by the means of function calls, a series of events to happen during the lifetime of a programm, they would rather register desired responses to particular happenings, and then let some external entities take over the control over the precise order and set of events to happen. While that is quite a confusing definition Roy demos the Castle.Windsor framework (similar to Spring) that allows the developer to create containers in their startup test methods which grab/instantiate any necessary dependancies for a class (usually defined as an Interface in the constructor of that class) and use Castle.Windsor syntax container to hold any of these instances you may need in your testing framework. Read all about it at here.
Roy highly recommends Working Effectively with legacy code by Michael Feathers
I just completed a design pattern course given by Industrial Logic and I must say it was pretty good. The goal of the course was to learn and implement design patterns, as many as Josh (the instructor and founder of Industrial Logic) could fit in over 4 days. What I found refreshing was that we didn't just study the Gang of Four (GOF) book's implementations or simply applied patterns to known problems, we actually spent most of our time refactoring to the patterns of the GOF. The labs were given in three languages (C#, C++, and Java) and I got to play with Eclipse's refactoring kong fu and learned how to use ReSharper in a much more efficient way.
The last question Josh asked us was "what is your favorite design pattern?" While I have been a big fan of the Strategy Pattern this course, and it's hands on examples, led me to find my true favorite... the Template Method.
I believe that the knowledge of when to use patterns and when not to use them is the true skill to be honed by a professional software engineer. Knowing how to leverage each patterns strengths in an elegant solution is quite a pleasure for me and I think that TDD'ing to patterns should be a requirement on all agile practicing teams.
A GREAT reference (or poster) for design patterns can be found here. The two books we used for the course, that are very highly recommended are:
Over the past couple of months I have been exposed to quite a few talks about the greatness of TDD. In the Better Software Agile Development Practices conference in Orlando I heard a couple of great talks from people like Roy Osherove who showed how to use dependency injections for unit tests. Roughly a month prior to that Uncle Bob gave us a very nice demo of TDD, and this week I'm attending a Refactoring to Design Patterns course given by none other than Joshua Kerievsky. Even Microsofts newest employee Phil Haacked has been promoting TDD lately on his blog.
While I find myself to be pretty TDD happy lately I can't help but wonder... if so many people are pushing TDD isn't there a slight risk we will all become too TDD happy? I am, of course, referring to the famous phrase: "when all you have is a hammer everything looks like a nail". If you start mocking every object in your system and refactor your code until pigs fly how do you know when you've gone too far?
Luckily, we have design patterns to show us the correct way of going about solving a problem. Now, thanks to James Carr we have TDD Anti-Patterns. A catalog of bad TDD habits.
The Mockery Sometimes mocking can be good, and handy. But sometimes developers can lose themselves and in their effort to mock out what isn’t being tested. In this case, a unit test contains so many mocks, stubs, and/or fakes that the system under test isn’t even being tested at all, instead data returned from mocks is what is being tested. Success Against All Odds A test that was written pass first rather than fail first. As an unfortunate side effect, the test case happens to always pass even though the test should fail. The Stranger A test case that doesn’t even belong in the unit test it is part of. it’s really testing a separate object, most likely an object that is used by the object under test, but the test case has gone and tested that object directly without relying on the output from the object under test making use of that object for its own behavior. Also known as TheDistantRelative.
Sometimes mocking can be good, and handy. But sometimes developers can lose themselves and in their effort to mock out what isn’t being tested. In this case, a unit test contains so many mocks, stubs, and/or fakes that the system under test isn’t even being tested at all, instead data returned from mocks is what is being tested.
A test that was written pass first rather than fail first. As an unfortunate side effect, the test case happens to always pass even though the test should fail.
A test case that doesn’t even belong in the unit test it is part of. it’s really testing a separate object, most likely an object that is used by the object under test, but the test case has gone and tested that object directly without relying on the output from the object under test making use of that object for its own behavior. Also known as TheDistantRelative.
In other agile news I've recently started using ReSharper and while it's kind of slowing down my IDE I can already see improvement in my code, especially since I don't have to rely on NUnit's crappy UI to run my tests... a small step for man, a huge step for me.
I attended a good presentation on refactoring by J. B. Rainsberger. What stood out at this presentation (other than the fact that J. B. is a good presenter and his slides were very refreshing) was that not only did he make perfect sense but he made me want to follow his recipe for becoming a better refactor-er. His recipe is fairly simple and can be followed by any developer with basic developing skills.
Start Today! Don't wait until your code is in such bad condition that you simply can not refactor it at all. Start as soon as you possibly can, refactoring is an acquired skill! You will not master it overnight.
Practice Set aside 2 hours a week to practice refactoring (or more if your job permits and if you have time) and do the following:
Done refactoring? Feel good about yourself? Feel like you can check this code in? DO NOT !!! Trash it, throw away anything you've refactored over the last 2 hours. This will allow you to focus on becoming a better developer, you will focus on the skill of refactoring rather than on fixing a bug or two. J. B. preaches that after you have done this for a while (he mentioned it took him 6 months when he was spending more than 2 hours a day) and you are confident that what you did is useful, correct, and actually ads benefit to your project, you may start checking your code in.
Seems a bit harsh if you ask me, but it sounds like a very strict plan for success. I think I'm going to try it out and see how it works for me.
One other key point that I enjoyed was the Kent Beck's rules of simple design. When refactoring, use these rules to guide your judgment about what constitutes good design.
A simple design exhibits these properties:
The "father" of all refactoring books that was recommended by J. B. and written by Martin Fowler is Refactoring: Improving the Design of Existing Code I think it has true value and it's definitely a great book to have around the office for reference.
close