I've been reading Working Effectively with Legacy Code by Michael C. Feathers. It's a trove of useful information for turning your unreadable and unreliable code into the complete opposite.
- Here's a useful technique for dealing with dependencies that have problematic methods for testing. Mark the offending method as virtual and inherit from the class. Now you can use this new derivative class in your test methods in place of the original. Here's an example in C#.
public class MyClass
{
public MyClass()
{
Console.WriteLine("MyClass has been initialized");
}
public virtual void DifficultMethod()
{
Console.WriteLine(
"Difficult method makes testing difficult.");
}
}
public class MyClassDerived : MyClass
{
public MyClassDerived() : base()
{
}
public override void DifficultMethod()
{
Console.WriteLine("It's testable!");
}
}
public class ClassToTest
{
public ClassToTest(MyClass myclass)
{
Console.WriteLine("Initializing ClassToTest");
myclass.DifficultMethod();
}
}
The ClassToTest has a constructor that takes a MyClass parameter. Unfortunately, MyClass has the DifficultMethod which is a very...well, difficult method. By marking DifficultMethod as virtual we can override it in a derived class which can then be used to pass into the ClassToTest constructor. Handy.
- Here's the same idea in Python
class MyClass(object):
def __init__(self):
print "MyClass Initialized"
def difficult_method(self):
print "this makes things hard"
class MyClassDerivative(MyClass):
def __init__(self):
MyClass.__init__(self)
def difficult_method(self):
print "MUCH better"
class ClassToTest(object):
def __init__(self, myClass):
print "ClassToTest has been initialized"
myClass.difficult_method()
Do you have a function in your C# code somewhere that takes a parameter - the type doesn't matter - and then executes another function based on that parameter's value?
public void what_to_do(string param)
{
if (param == "this")
DoThis();
else if (param == "that")
DoThat();
else
DoSomethingElse();
}
Whenever I see "else if", my spider-sense starts tingling. Adding another "else if" is just too easy and the result can be cumbersome. I do use "else if" (and "switch" - it's just as vulnerable to this idea), but I don't always like it. The good news is that there is a fix - if you're willing to think "functionally". The bad news is it took me so long to piece it all together.
When did this epiphany come? At the latest MichiPUG meeting, while Mark Ramm was demonstrating a Python library for implementing generics, he displayed an interesting technique for avoiding the Python version of the above code. Here's my rendition of what he showed us:
whatToDoDictionary = {'this':do_this, 'that':do_that}
def what_to_do(param):
if param in whatToDoDictionary:
whatToDoDictionary[param]();
else:
do_something_else();
The key to this bit of Python is the values in the whatToDoDictionary. Instead of your standard string or integers, the values are functions. When we call the what_to_do method, we look to see if the parameter is present as a key in the dictionary. If it is, we simple execute the value portion of the key/value pair. VoilĂ ! No more "else if"!
Can we do this in C#? Sure. Let's do it using lambdas.
Dictionary<string, Action> dict =
new Dictionary<string, Action>();
public Lambda()
{
dict.Add("this", () => do_this());
dict.Add("that", () => do_that());
}
public void WhatToDo(string param)
{
if (dict.ContainsKey(param))
dict[param]();
else
do_something_else();
}
The concept is exactly the same. Build a dictionary of lambdas (functions in Python), see if the parameter passed to the WhatToDo(string) is in the dictionary and then execute the lambda if it is.