Sunday, September 15, 2013

TDDing to ILock

My guiding star: when faced with a difficult TDD problem, refactor to make it easy. There are many techniques for doing so (I only know a handful).

What if we use dependency injection?

1. Wrap the `lock` keyword in a custom class.
2. Pass in that custom object
3. In tests, pass a mock of that custom object instead.

Here's the resulting implementation of Counter:

    class Counter
    {
        readonly ILock @lock;
        public Counter(ILock @lock)
        {
            this.@lock = @lock;
        }
        internal int MoveNext()
        {
            using (this.@lock.Acquire())
            {
                return CurrentValue++;
            }
        }
        public int CurrentValue { get; private set; }
    }

One way of looking at what I've done here is addressed the Primitive Obsession around the _syncRoot object in the conventional pattern. You can't get much more primitive than System.Object!



Note that I explicitly called out which steps were RED, GREEN, and REFACTOR. 

5b36285 REFACTOR; Rename `MyLock` -> `Lock`
c149f15 REFACTOR: Rename `Lock()` -> `Acquire()`
66518d7 GREEN: Simple `Lock()` and `IsLocked`
9b27a8c RED: LockedLockShouldBeLocked

Also, as the code currently stands (https://github.com/JayBazuzi/TddLocks/tree/IDisposableLockToken/LocksExperiment1/LocksExperiment1), there are 3 implementations of ILock:

MonitorLock, which attempts to duplicate the behavior of the `lock` keyword in C#, according to the language specification.
MockLock, which makes it easy to confirm that code is locking as expected.

SingleThreadedLock, which actually doesn't lock at all.

I created the different Lock implementations with TDD. All 3 pass the exact same set of unit tests.

Fun stuff.

Conventional threadsafety

The conventional approach is to use the `lock` keyword to wrap operations that are sensitive to threading.

    class Counter
    {
        readonly object _syncRoot = new object();
        int i = 0;
        internal int GetValue()
        {
            lock (_syncRoot)
            {
                return i++;
            }
        }
    }
It's popular, and there's nothing wrong with it per se, but my goal is to use TDD. I can write a test that motivates the non-lock parts of this code, but I don't know how to write a test that demands the locking.


TDD and multithreaded code

I recently watched a video of a talk by Venkat Subramaniam called "Test Driving and Unit Testing Thread Safety". http://www.agilealliance.org/resources/learning-center/test-driving-and-unit-testing-thread-safety

My first understanding of the title of the talk was that Venkat was going to describe a novel way to test code for thread safety. That understanding makes sense if you think of unit testing as a way to measure & ensure the quality of code.

However, I keep having to remind myself that TDD is not primarily a testing activity; quality assurance is not its primary goal. The primary purpose of TDD is design - to help you write well-designed code. That works because you can't test things in isolation if coupling is high.

Any time you're doing TDD and have code you don't know how to test in isolation, you have 3 options:
  • Don't test it.
  • Test it in context, in an integration test / manual testing / etc.
  • Refactor.
That last one is the gift TDD offers, and that's what Venkat was recommending in his presentation.

As I was watching Venkat code, I realized that what he was creating looked very familiar. I went back and found this blog post from 9 years ago: http://blogs.msdn.com/b/jaybaz_ms/archive/2004/05/06/127480.aspx. What's interesting to me here is that we came up with that code without doing TDD. We were only coding for fun, and we didn't understand TDD at the time. We just refactored mercilessly and that's what we ended up with.

I've also been reading Arlo Belshee's blog. He talks about mocks as a code smell, and the pattern of using simulators instead of mocks for external dependencies.

Thinking about Venkat's talk, Arlo's blog, and my old blog post, I decided to attack this problem again as a kind of kata. Specifically, I wanted to practice some ideas I've been studying recently:

  • Strict RED/GREEN/REFACTOR
  • Work Tiny.
  • NCrunch.
  • Letting TDD drive the design.
  • Treating mocks as an invitation to develop multiple useful implementations
Problem statement

Write a threadsafe counter. It supplies sequential integers to callers from multiple threads.

That is, make this threadsafe:

    class Counter
    {
        int i = 0;
        internal int GetValue()
        {
            return i++;
        }
    }