Friday, January 25, 2008

Locking Objects And Base Types

If you have a class that can be accessed with multiple threads you will need to wrap any outside access to private level variables with a lock statement. See Figure 1.0 where we have a customer class and a process class with a customer inside.

Figure 1.0

public class Customer
{
private int _customerId;
private string _customerName;

public int CustomerId
{
get {return _customerId; }
set {_customerId = value; }
}
}

public class Process
{
private IList _customersToProcess;

public IList CustomersToProcess
{
get
{
lock(_customersToProcess)
{
return _customersToProcess;
}
}
set
{
lock(_customersToProcess)
{
_customersToProcess = value;
}
}
}
}


The lock statement only takes objects. In order to lock base types, you must declare them as objects and then initialize them with their base type. When you do this, the object will default similar to what happens with VB.NET. Booleans will default to false, and integers to 0, and DateTime to MinValue. Strings can be locked without using boxing and unboxing from an object type since they are already objects. When in the getter the object must be cast back into the base type. Take a look at the Figure 1.1 below.

Figure 1.1

public class Customer
{
private int _customerId;
private string _customerName;

public int CustomerId
{
get {return _customerId; }
set {_customerId = value; }
}
}

public class Process
{
private object _numberOfThreads= new int();
private IList _customersToProcess;

public int NumberOfThreads
{
get
{
lock (_numberOfThreads)
{
return (int) _numberOfThreads;
}
}
set
{
_numberOfThreads= value;
}
}

public IList CustomersToProcess
{
get
{
lock(_customersToProcess)
{
return _customersToProcess;
}
}
set
{
lock(_customersToProcess)
{
_customersToProcess = value;
}
}
}
}


The example above is for illustrative purposes only. In a later post we will talk about using events to do custom progress information.

Why TDD is bad

TDD (Test Driven Development) refers to creating an individual test first and then creating the code for that test. This is opposite of creating code and then at some later date, creating unit tests. Proponents of TDD claim that it promotes looser coupling and better code coverage. I agree that junior level developers would benefit from this; however for senior level developers it simply creates unnecessary work. I find that it is easier to create loosely coupled methods in a domain class and then simply generate the tests for those methods using a tool such as NUnit Test Generator. After the tests are generated, single tests can be run against the corresponding method in the domain class. Without code generation for unit tests, the developer has to manually create the unit tests, since the code does not exist yet. That is just about as fun as manually creating NHibernate mappings.




NUnit Test Generator is a great way to quickly create unit tests for NUnit, csUnit, MbUnit, or Microsoft Unit Tests. It does things like min/max/null testing too. Simple interface but powerful output.



The reason why TDD works well for junior level developers is that they tend to forget to write the unit tests at all. When you write the tests first, you can never forget to write them. However senior developers are used to checking the code coverage with tools such as NCover and TestMatrix. It can't be any more obvious, the untested areas of your code are highlighted in red. Another way to ensure that tests are being written is to set up a code coverage threshold on your continuous integration server. Cruise Control .NET can be set up to automatically fail when the code coverage falls below the threshold.





TestMatrix is a great testing tool that is integrated right into Visual Studio. It has a test runner, captures performance, and performs detailed code coverage. It is like a Swiss army knife, I wouldn't be surprised if the next version tested for cancer. I like it better than what is built into Microsoft Team Suite.


Below is an example of how TestMatrix highlights code slightly different than NCover. The covered areas are in green, the uncovered areas in red. The little yellow progress bars indicate the largest performance hit for particular lines. In the example below we see that logging the error is slightly more expensive than throwing it again.




When it comes down to it, your client wants the highest quality code at the lowest price. They could really care less if you wrote the tests first or the code first. A good way to blow money and time on your project is to write your unit tests manually. If you are on a fixed bid enterprise project, this can mean the difference between success and failure. I have seen it first hand.

Having unit tests with good code coverage ensures reliability but it does not ensure maintainability. You can still have a junior developer do TDD and create crap code. The only way around this is to do paired programming or code review.

Which ever way you choose to do your tests, creating the tests first, or creating the code first; you should always write them. There is no excuse for legacy projects that do not have tests. They should be created at the first opportunity. Unit test generation solves the problem to generate tests for legacy code and speeds along the process for new projects. To all of my fans, Q'apla! Which means success in Klingon.