Common Concerns with Automated Tests & Refactoring

Below is a list of common concerns that the average non-refactoring/non-automated-testing person might have towards Refactoring and Test-Driven Development.

All of these concerns have already been addressed, but I'll be going from memory. I want to make sure I still understand how Refactoring and TDD are supposed to help -- since I've been confronted as if I've lost my mind.

CONCERNS:

  1. Developers won’t be able to support it anymore.
  2. Developers will have to reverse engineer refactoring efforts which will decrease their productivity.
  3. Version Control becomes muddied: Refactoring design changes cannot be discriminated against bug fixes.
  4. It is not fair to other coders. It implies that their work is unqualified or sub standard.
  5. Refactoring nullifies any unit testing that the developers did in creating the classes which decreases accountability in system design.
  6. You can be sure I will be after the author is something breaks or needs to be redone. No need to make that a blurry picture.
  7. It does not project a “Team Spirit”.

REMEDY:

  1. Refactoring by definition is, "A code refactoring is any change to a computer program which improves its readability or simplifies its structure without changing its results". By making the code easier to read, it will be easier to support.
  2. See Remedy #1
  3. See Remedy #1
  4. It's a team. One team member that writes bad code, it can bring the entire team down. If anything, the team members that have their code refactored will be learning and will begin to write tighter code that has less defects in it. The company's ROI for that programmer increases over time.
  5. Were there tests to begin with? If there WERE tests that BROKE because of someones refactoring, was it for the better or worse? The unit-tests should be changed to reflect any business changes to the refactoring.
  6. Don't check in broken code. Simple as that. If you have unit-tests breaking, are you going to check it in?
  7. It projects "Lets work together and write better/cleaner code so we don't have to work 80 hour work weeks". I guess if your team really does love working on the weekends and 12-16 hour days , then keep on truck'n how you are.

Tales from the AntiTestingSide - The Stubborn Architect

Confrontation
Fresh into a new organization and handed a project. The person that did the handing off was the "Architect" (bridge-builder).

The bridge-builder does not like refactoring. The bridge-builder also wants automated tests to be developed AFTER the code works, not before. His motto, lets build a bridge without measuring anything and see if it's still standing 1 day after vehicles start driving on it.

So back to the code -- it's NOT in production yet, 80% complete, it DOES work to some degree, has ZERO requirements and analysis done, and ZERO unit-tests. Get it working. What is a Test- Driven developer to do? Start writing tests against this code? If so, the code is probably poorly designed due to the limited THINKING beforehand and is going to be hella hard to write tests for. Re-designing existing code is pretty much the only option at this point (while reusing the existing core-functioning-code, after all money was spent on getting the current executable). The last option (not the best in my opinion) is to write wrappers (adapters) for the classes under-test that will allow easier unit/integration testing.

Which option is better? In this case, the former!

Ultimatum
I refactored a lot of the code into more managable chunks. Having removed some duplication etc.. I was able to actually see what was going on. Of course, the infamous flame email came from the bridge-builder about how he has been an Architect for 12 years and that it's his life. Getting over that useless information, the fact still stands.

Releasing crappy code with ZERO analysis and ZERO tests for it is not my idea of a smart move for future maintenance. The time to do this was now since the code is NOT in production and has some time to make it BETTER than what the bridge-builder wants.

Moral
Don't piss off a stubborn bridge-builder, they always win. After pissing them off, continue to wrap tests around the code before it goes out to production. It's worth the time if theres available time to do it. In my case, I have the time, so I will proceed. Is it going against what the bridge-builder wants? Yes. Is what the bridge-builder wants good for the company? Yes and No.

Yes: it's a great idea and could benefit the company very well, if it does what it's supposed to
No: it will become a maintenance nightmare later on.

Side Note: I am fully aware that business needs must be fulfilled. But in this case there is ample time for this small project. Do it as right the first time as possible. Or else the ever popular problems arise that organizations always face.

Trivia.NET, save me from my self.

At times, one hears that the reason a husband/wife strays is because they aren't getting it at home. I don't know if that's true or not, but I do know that the latest batch of updates done to the project is directly related to the lack of coding I am getting to do at my paying gig.

And its the nature of this code, too. I am supposed to be doing TDD: writing tests and passing those tests with the simplest implementation. My blogging partner accused me the other night of making test cases that were a bit too complex. I, of course, would hear none of it, because I wanted to code.

I am not even supposed to be coding this project. In this exercise, I am supposed to be acting in the role of the Business, answering the questions of the developers.

BUT I NEEDED TO CODE, DAMMIT!!!

You see, while I have a job and I am paid as a developer, I haven't gotten to develop a whole lot lately. And the last thing I did get to code got a bit shredded in a code review after a disagreement over the definition of "elegance". So without that outlet, I have gone a bit over board in this latest implementation.

For those not familiar, the Trivia.NET project is essentially an attempt to implement an electronic scoreboard for the 20 question live trivia games that are played in bars and restaurants. We are focusing on the particular implementation that is done by Team Trivia (http://teamtrivia.com/) sponsored games. The concept is simple, the game is divided into halves (10 questions), and the halves are divided into 3 rounds of 3 questions each with a half-ending question(a half-time and a final question). The rounds themselves have points that available to be wagered, determined by the half. So a round in the first half will have points of 1, 3, or 5 per question, usable once per round. Its 2, 4, or 6 in the second half. The half-time and final questions behave a little differently. Half-time is generally a multi-part question that you get credit for each part (Name the original ABA teams that are still active today as part of the NBA, 2 points for each correct answer). The final question is generally a wager of 0 to 15 points that you will then gain or lose those points from your final score.

So after creating an initial test case to test something seemingly simple (like making sure that a point value cannot be re-wagered within the same round) I went deep down the rabbit hole, creating code and tests and refactoring, over and over and over again.

Now, I am done and very pleased with myself. After several refactors and re-tests, I have a very OO solution. Through the use of interfaces and abstract classes I am able to hit all the high points on A PIE (A PIE - as in "OO Developement is simple as a pie -- Abstraction, Polymorphism, Inheritance, and Encapsulation). I was also able to use Generics and got compile-time checks on the code (which caused me to drop a few tests. Actually, I was testing for a feature[placing 2nd Half Questions into 1st Round containers] that now cant be tested because it just wont compile unless its written right in the first place.

Note to Self: There has got to be a future piece in there somewhere about designing using compile-time checks to eliminate some tests.

At anyrate, I feel better now. I know Corey is going to look at what I have done and tell me I am missing it, that I am doing to much in my test cases and there for writing too much code to get them to pass. But hey, I had to code.

If you'll check out revision 37, you will see what I have added.

Red, Green, Constant Refactor

For any of you following along with our Trivia.NET instructional project, revision 31 should find you with a few changes.

I have begun implementing a new use case, and just writing one test and trying to get it to pass led to two hours of code. You have got to love that!

But the best part, is that I can narrow my development focus on getting the test to pass. And I know that when I decide to finish for the day, the code is left in a stable state, based upon tests. Much better than the classic "Well, it compiled" or the heinous "It works on my machine". It brings development into the realm of science, with repeatable experiments.

At anyrate, stay tuned to this channel for project updates.

Tales from the AntiTestingSide - Master Debugger

Confrontation
Came across a unit test with 2 lines of code. It was the only test in the entire suite. The first line of the test code created an instance of a class. The second line called the Execute() method on that instance. How did this test pass with no Assert methods? Easy. Set a breakpoint on the Execute() method and step through the code.

Ultimatum
Immediately I deleted the lines of code. Banished as if it were pr0n that accidentally popped up while checking out a technology site.

Moral
I'm not sure if I'd want to do the whole debugging a method to inspect code that I've never seen before. In this scenario I wrote a new test and continued on from there. One that actually did something.

Code-Coverage made easy with NAnt

I like automating things. And I like to do it fairly quickly. I wanted to automate my unit tests as well as run NCover to get feedback on coverage as soon as possible. Instead of using MSBuild which is in my current environment, I wanted to use something that I was more familiar with -- NAnt.

The NAnt script I whipped up runs my Unit Tests and then NCover. This script also brute force's an organization of the assemblies and their testing counter-parts into a clean structure. It may be be a little excessive -- to create test assemblies for each assembly under test -- but it's ok, I know what's what when first looking at it.

There was a post on this blog earlier about Simplest way to setup unit tests in a project. This script follows that convention.

<project default="code-coverage">
<property value="C:\Program Files\NCover\ncover.console.exe" name="ncover.executable"/>
<property value=".\NUnit\nunit-console.exe" name="nunit.console"/>
<property value=".\NCover\Coverage.xsl" name="ncover.stylesheet"/>
<property value="C:\ProjectsDirectory" name="projects.output.dir"/>

<target name="code-coverage">
<foreach property="test.assembly.folder" item="Folder">
<in>
<items>
<include name="${projects.output.dir}\*Test"/>
</items>
</in>
<do>
<regex input="${test.assembly.folder}" pattern="^.*(\\/)(?'asmregex'.*)$">
<property value="${asmregex}" name="assembly.test.name"/>
<property value="${string::replace(asmregex,'.Test','')}"name="assembly.under.test.name"/>
<property value="${projects.output.dir}\${assembly.test.name}\bin\Debug\${assembly.test.name}.dll //l Reports\Coverage.Log //a ${assembly.under.test.name}" name="ncover.path.arg"/>
<exec commandline="${nunit.console} ${ncover.path.arg} " program="${ncover.executable}"/>
<style style="{ncover.stylesheet}" out="Reports\${assembly.under.test.name}-Coverage.html" in="Coverage.xml$">
</do>
</foreach>
</target>
</project>

Yes, Virginia, there are monsters . . .

. . . but there are no silver bullets, or +4 vorpal blades of wounding, or any other [Insert magical, non-existent, deus ex machina method] to slay them with.

I am currently involved in a project that has a certain amount of mass and inertia associated with it. This bulk leads to essentially no one making changes to it that might be too massive. Why? Because no one knows what will break and stop working. Why? No tests. Writing tests was something that they'd get to. Someday. Maybe. If they hired somebody for that. Or maybe not. I mean, its not needed, right? We have gotten by this long with out it, right?

Right? Negative, Ghostrider, the pattern is full.

And yet, this bloated rotting code base sits there and taunts you. Because it knows its a monster and it knows that there is no such thing as silver bullets. And it also knows that the leadership is going to continue to search for that one line code solution (peppered with the correct amount of buzzwords), and therefore the code dragon can continue to grow and fester.

And laugh at me.

Touching fire

Why is it that developers know about automated testing -- how much time it can save you, how many headaces it can help prevent, etc... -- but don't practice it?

A team that WANTS to do automated testing, but just doesn't "do it", needs a automated-testing evangelist. That's a recipe for automated-tests to infiltrate the company. The evangelist will always push for it. Now that seems like common sense to most, but people that think it's common sense are either doing automated testing as a full-team of people or it's someone that can tell their developers to do automated tests in the first place.

If management doesn't buy into it right away, create a new assembly and just stick your tests in that and do them as you develop. Try to write a test before ANY CODE, regardless of deadlines. Deadlines usually aren't hit in the real world anyway -- unless you work for a company that has hit them for the past couple years.

TortoiseSVN and Windows Vista

If you've gone with Vista on your development machine, you may notice some issues with TSVN such as missing menu options and a lack of icon indicators. I used the last release and wasnt getting the experience I had grown used to in Windows Explorer.

I consulted the Well of All Knowledge (Google) and after some searching that not everyone was having the same experience I was. Some were, but those that werent seemed to be Windows users that had upgraded their Windows to Vista instead of using a fresh install as I did. After further research I found the recommendation for getting the very latest build (nightly build) of Tortoise to get proper integration with Explorer. The nightly build has an improved icon overlay. With this latest build/install I was able to get all of the context menu features that I have grown used to (it was a bit disheartening to right-click and only get 4 items to choose from, and no icons to let me know which ones where versioned).