Why .NET Developers Don’t Unit Test

Short answer: It’s Microsoft’s fault.

Long answer:

I am going to describe the journey of Well Intention Programmer (WIP).  He started writing software code in the mid-90s using this book:

image

and when .NET came out he slid over to C#

image

Along the way, he has written several highly-regarded programs that always exceed expectations and came in under-budget in the the 1st release but struggled in subsequent releases.  So the WIP decides to learn about how to improve his code quality to help him with the old code and to deliver more timely 2.x releases.  He picks up theses books:

imageimage

And  learns that he shouldn’t change a single line of code without covering unit tests.  Eager to try unit testing out, he opens up some legacy code and finds this:

public List<String> GetRegions()
{
    List<String> regions = new List<string>();
    String connectionString = @"Server=.;Database=Northwind;Trusted_Connection=True;";

    using(SqlConnection connection = new SqlConnection(connectionString))
    {
        String commandText = "Select * from Region";
        using (SqlCommand command = new SqlCommand(commandText, connection))
        {
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                regions.Add(reader["RegionDescription"].ToString());
            }
        }
    }

    return regions;
}

So the 1st thing the WIP might want to refactor is the hard-coded connection string in the function.  Microsoft has been telling the WIP for years that this string belongs in the .config file.  And it really does – not so much because you are going to swap out your DBMS (never happens) but because you should have environment-specific settings (that you don’t have on your local workstation).

To protect himself from the change, the WIP right clicks on the method name in VS2010

image

and he gets this out of the box test snippet like so:

[TestClass()]
public class NorthinwindFactoryTests
{
    [TestMethod()]
    public void GetRegionsTest()
    {
        NorthinwindFactory target = new NorthinwindFactory(); // TODO: Initialize to an appropriate value
        List<string> expected = null; // TODO: Initialize to an appropriate value
        List<string> actual;
        actual = target.GetRegions();
        Assert.AreEqual(expected, actual);
        Assert.Inconclusive("Verify the correctness of this test method.");
    }
}

He then alters it like so, using the Microsoft snippet to guide him.

[TestMethod()]
public void GetRegionsTest()
{
    NorthinwindFactory target = new NorthinwindFactory();
    Int32 expected = 4;
    Int32 actual = target.GetRegions().Count;
    Assert.AreEqual(expected, actual);
}

When he runs it, the test passes.

He then adds a reference to System.Configuration

image

The WIP comments out the initial line and then add a functionally equivalent line using a .config file:

//String connectionString = @"Server=.;Database=Northwind;Trusted_Connection=True;";
String connectionString = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;

He re-runs the unit test and it still passes.  Felling good, he checks the code back into source.  Unfortunately, when the build goes to TEST/QA, it breaks because they have a special .config they use and that build server doesn’t have that database installed.  After a couple of hours of wrangling, WIP gets the correct .config into all environments and includes Northwind as part of the build.

WIP then reads that unit tests shouldn’t have external dependencies like databases and .config files.  To unit test right, he reads, he should use a Mocking Framework and he heard that MOQ is the best out there (editor comment: he’s right).  So WIP downloads MOQ and tries to mock his ConfigurationManager:

image

After a couple of hours of researching, he decides that the ConfigurationManager cannot be mocked.  Unwilling to give up on mocking, he fires up Rhino Mocks.  Alas:

image

Still unwilling to give up, he hits F12 on the Configuration Manager to see if it uses an interface that he can mock.  Perhaps an IConfigurationManager?  Nope.

image

so now the WIP has spent several of hours and he is nowhere with Unit Tests.

So forgetting ConfigurationManager, he decided to mock SqlConnection.  It starts out well enough:

image

and then

image

So that is good.  he can create a mock connection like so but he can’t use it without casting.

image

image

So he just can’t set the connection string.  This violation of the Law Of Demeter makes it really hard.  All he wanted to do is set a String value called ConnectionString and instead he has to learn about the internal workings of the DbConnection class.

So the WIP decided that he needs to re-write the entire method and use Entity Framework.  After all, EF is the new new data access technology and it must be mockable.  So the WIP goes out to this great blog post and is disappointed to learn that EF is even harder to mock than ADO.NET classes.

The WIP then turns his attention to his UI and tried to unit test/mock the visual data controls in ASP.NET.  Already half-expecting the answer, the WIP is not surprised

image

WIP probably gives up.

So whose fault is it?

The books?  Low. The point of the books are to teach the language, not good coding practices.  And basic books that don’t have a UI to demonstrate a concept (versus using unit tests) would take attention away from the primary focus – learning the language.  The most successful books have real working, albeit simple, UI projects.

The developer?  Low. WIP is hard-working, want to do the right thing, and are going to try unit testing.  He also has deadlines.

Unit Tests Advertising? Low.  True that unit tests have generally been forced upon dev teams by people better paid, with cooler job titles if not smarter than them.  Also, these smarter people also likely introduce different, convoluted techniques of hundreds of lines long or that use parts of the .NET language spec that only Phds understand to work around the fact that lots of the .NET APIs are untestable.

The projects?  Medium.  Many .NET projects do not have any business logic – they are simply CRUD UIs on top of a database.  Unit tests can’t tell you if the Sql string returns the expected result.  And in lots of projects, that is all it has.  Also, in lots of .NET projects, any logic that could be tested is intermingled with the untestable code.  In the example above, the assumption tha GetRegions() is testable is false.

The API?  Absolutely. Every major class in Microsoft’s data stack are un-mockable and therefore un-unit testable.   Would it really kill MSFT to have an interface for these classes because perhaps, just perhaps, the classes won’t be only used in the way that they were thought of 15-20 years ago?  I get that Microsoft has been dragging code and outdated APIs though the different versions of .NET and it has to be frustrating to them that they can’t introduce changes easily.  However, until Microsoft starts making the classes that everyone uses Mockable, unit testing will not take off.  And it is not just ADO.NET, WinForms, WebForms, System.IO, etc… all are un-mockable.

So some people might ask.  Why not use VS2012 MSFT mocks?  Well, that is a clown show.  It flies in the face of iterative development – every new object, regenerate your mocks.  Also, the syntax pales in comparison to MOQ.  It is a compensation for poor class design that has been dragged forward – interest on technical debt if you will…  I think Microsoft should change their APIs, not build tools to get around their API’s failings.

Advertisements

Events && Multi-Threading

Dear Future Me:

When you need to write a vanilla event, use the following boilerplate:

public event EventHandler<EventArgs> MyEventName

And when you need to write a vanilla cross-thread function to update the UI in a WPF application, use the following boilerplate:

Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
    SomeUIControl.Text = someValueFromThisThread;
}));

And this is in System.Windows.Threading, which is not in the Client Profile

And when you need to write a vanilla cross-thread function to update the UI in a WinForms application, use the following boiler plate:

this.BeginInvoke(new Action(() =>
{
    StringBuilder message = new StringBuilder();
    message.AppendFormat("{0:hh\\:mm\\:ss}", e.ElaspedTime);

    SomeUIControl.Text += Environment.NewLine;
    SomeUIControl.Text = message.ToString();
}));

Love,

Present Me

PS: you really should exercise more…

ADO.NET and Connection Pooling

I decided that I needed to learn more about ConnectionPooling – especially ConnectionPool fragmentation.   I ran into a great article here that explains in the ins and outs of connection pool fragmentation.  I decided to try out some scenarios.

I first created a class library that calls a select on a Northwind table:

public class NorthwindFactory
{
    public Dictionary<String, String> GetRegions(String connectionString)
    {
        Dictionary<String, String> regionDictionary = new Dictionary<string, string>();

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            String commandText = "Select * from Region";
            using(SqlCommand command = new SqlCommand(commandText, connection))
            {
                connection.Open();
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    regionDictionary.Add(reader[0].ToString(), reader[1].ToString());
                }
            }
        }

        return regionDictionary;
    }
}

I then added a unit (really integration) test to run this function:

[TestClass()]
public class NorthwindFactoryTests
{

    [TestMethod()]
    public void GetRegionsTest()
    {
        NorthwindFactory target = new NorthwindFactory();
        string connectionString = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
        Dictionary<string, string> regionDictionary = target.GetRegions(connectionString);

        Int32 expected = 4;
        Int32 actual = regionDictionary.Count;
        Assert.AreEqual(expected, actual);
    }
}

I then opened up Sql Server Management Studio to see the impact that this call had:

select spid, loginame, status, program_name,cmd from master..sysprocesses where spid > 50

When I ran the test, nothing came out of sysprocess – by the time I flipped windows from VS to SSMS, the test ran and the connection went away.  I changed the code to allow me to flip over:

while (reader.Read())
{
    Thread.Sleep(TimeSpan.FromSeconds(3));
    regionDictionary.Add(reader[0].ToString(), reader[1].ToString());
}

Sure enough, when I run the test, I see the active connection

image

I then decided to see what would happen with two connections.  I went and added a second connection in serial:

[TestMethod()]
public void GetTwoRegionsInSequenceTest()
{
    NorthwindFactory target = new NorthwindFactory();
    string connectionString = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
    Dictionary<string, string> regionDictionaryOne = target.GetRegions(connectionString);
    Dictionary<string, string> regionDictionaryTwo = target.GetRegions(connectionString);

    Int32 expected = 8;
    Int32 actual = regionDictionaryOne.Count + regionDictionaryTwo.Count;
    Assert.AreEqual(expected, actual);
}

There is only 1 active connection at a time – the connectionPoolManager in action.

image

My next though was that if the connection is explicitly closed by the SqlConnection objects is not out of its using scope, would the connection stay open?

using(SqlCommand command = new SqlCommand(commandText, connection))
{
    connection.Open();
    SqlDataReader reader = command.ExecuteReader();
    while (reader.Read())
    {
        regionDictionary.Add(reader[0].ToString(), reader[1].ToString());
    }
    connection.Close();
    Thread.Sleep(TimeSpan.FromSeconds(10));
}

Sure enough, when I run this, the connection is “closed” on the client but on the Sql Server it is still active:

image

That is the connection pool manager keeping the connection alive.

So my next thought – does the connection pool manager work cross threads?  I created a new test like so:

[TestMethod()]
public void GetRegions_ParallelTest()
{
    NorthwindFactory target = new NorthwindFactory();
    string connectionString = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
    ConcurrentBag<KeyValuePair<String, String>> regionBag = new ConcurrentBag<KeyValuePair<String, String>>();

    Parallel.For(0, 2, i =>
    {
        Dictionary<string, string> regionDictionary = target.GetRegions(connectionString);
        foreach (KeyValuePair<String,String> keyValuePair in regionDictionary)
        {
            regionBag.Add(keyValuePair);
        }

    });

    Int32 expected = 8;
    Int32 actual = regionBag.Count;
    Assert.AreEqual(expected, actual);
}

And the GetRegions() has a 10 second delay built in.  I got this back on my dual-processor machine:

image

And to corroborate, I passed in two different times that the thread stays awake:

public Dictionary<String, String> GetRegions(String connectionString)
{
    return GetRegions(connectionString, 10);
}

public Dictionary<String, String> GetRegions(String connectionString, Int32 lengthOfSleep)
{
    Dictionary<String, String> regionDictionary = new Dictionary<string, string>();

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        String commandText = "Select * from Region";
        using (SqlCommand command = new SqlCommand(commandText, connection))
        {
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            while (reader.Read())
            {
                regionDictionary.Add(reader[0].ToString(), reader[1].ToString());
            }
            connection.Close();
            Thread.Sleep(TimeSpan.FromSeconds(lengthOfSleep));
        }
    }

    return regionDictionary;
}

Add the test that checks:

[TestMethod()]
public void GetRegions_Parallel_DifferentSleepTimes_Test()
{
    NorthwindFactory target = new NorthwindFactory();
    string connectionString = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
    ConcurrentBag<KeyValuePair<String, String>> regionBag = new ConcurrentBag<KeyValuePair<String, String>>();

    Parallel.For(0, 2, i =>
    {
        Dictionary<string, string> regionDictionary = target.GetRegions(connectionString, 5+(i*5));
        foreach (KeyValuePair<String, String> keyValuePair in regionDictionary)
        {
            regionBag.Add(keyValuePair);
        }

    });

    Int32 expected = 8;
    Int32 actual = regionBag.Count;
    Assert.AreEqual(expected, actual);
}

Sure enough, in the 1st five seconds:

image

And in the last 5 seconds (or so):

image

Next, I added a new test that uses two different types of connection strings – 1 for integrated security, 1 for Sql Server security:

[TestMethod()]
public void GetRegions_DifferentConnectionStringsTest()
{
    NorthwindFactory target = new NorthwindFactory();
    string sqlServerSecurityConnectionString = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
    string integratedSecurityConnectionString = @"Data Source=Dixon12;database=Northwind;Integrated Security=true";

    Dictionary<string, string> sqlServerSecurityRegionDictionary = target.GetRegions(sqlServerSecurityConnectionString);
    Dictionary<string, string> integratedSecurityRegionDictionary = target.GetRegions(integratedSecurityConnectionString);

    Int32 expected = 8;
    Int32 actual = sqlServerSecurityRegionDictionary.Count + integratedSecurityRegionDictionary.Count;
    Assert.AreEqual(expected, actual);
}

Sure enough, 2 connections

 

image

I then realized that my test so far do not show the number of connection pools in existence, rather it just shows the number of active Sql Connections for each scenario that may or may not be controlled by different connection pools.  What I need to do is to have something on the client that I can use to inspect the number of connection pools and connections within those pools.  I ran across this site which showed how to use reflection to resolve the hidden properties/fields of the SqlConnection class.  To that end, I created the following class that determines the the ConnectionPool for a given connection and then the number of connections in that pool.

public static ConnectionPool GetConnectionPool(SqlConnection sqlConnection)
{
    ConnectionPool connectionPool = new ConnectionPool();
    connectionPool.PoolIdentifier = sqlConnection.ConnectionString;

    Type sqlConnectionType = typeof(SqlConnection);
    FieldInfo _poolGroupFieldInfo =
      sqlConnectionType.GetField("_poolGroup", BindingFlags.NonPublic | BindingFlags.Instance);
    var dbConnectionPoolGroup =
      _poolGroupFieldInfo.GetValue(sqlConnection);

    if (dbConnectionPoolGroup != null)
    {
        
        FieldInfo _poolCollectionFieldInfo =
          dbConnectionPoolGroup.GetType().GetField("_poolCollection",
             BindingFlags.NonPublic | BindingFlags.Instance);
        
        HybridDictionary poolCollection =
          _poolCollectionFieldInfo.GetValue(dbConnectionPoolGroup) as HybridDictionary;

        foreach (DictionaryEntry poolEntry in poolCollection)
        {
            var foundPool = poolEntry.Value;
            FieldInfo _objectListFieldInfo =
               foundPool.GetType().GetField("_objectList",
                  BindingFlags.NonPublic | BindingFlags.Instance);
            var listTDbConnectionInternal =
               _objectListFieldInfo.GetValue(foundPool);
            MethodInfo get_CountMethodInfo =
                listTDbConnectionInternal.GetType().GetMethod("get_Count");
            var numberOfConnections = get_CountMethodInfo.Invoke(listTDbConnectionInternal, null);
            connectionPool.NumberOfConnections = (Int32)numberOfConnections;
        }
    }

    return connectionPool;
}

I also realized that I needed the number of ConnectionPools in total.  That is also available via the SqlConnection.ConnectionFactory property. 

public static List<ConnectionPool> GetConnectionPools(SqlConnection sqlConnection)
{
    List<ConnectionPool> connectionPools = new List<ConnectionPool>();

    Type sqlConnectionType = typeof(SqlConnection);
    PropertyInfo _connectionFactoryPropertyInfo =
        sqlConnectionType.GetProperty("ConnectionFactory", BindingFlags.NonPublic | BindingFlags.Instance);
    var connectionFactory =
      _connectionFactoryPropertyInfo.GetValue(sqlConnection,null);


    if (connectionFactory != null)
    {
        FieldInfo _connectionPoolGroupsInfo =
          connectionFactory.GetType().BaseType.GetField("_connectionPoolGroups",
             BindingFlags.NonPublic | BindingFlags.Instance);
        var dbConnectionPoolGroups =
          _connectionPoolGroupsInfo.GetValue(connectionFactory);

        IEnumerable enumerator = dbConnectionPoolGroups as IEnumerable;
        ConnectionPool connectionPool = null;

        foreach (var item in enumerator)
        {
            connectionPool = new ConnectionPool();
            PropertyInfo _valuePropertyInfo =
                item.GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance);
            var _valuePropertyValue = _valuePropertyInfo.GetValue(item,null);

            PropertyInfo _keyPropertyInfo =
                item.GetType().GetProperty("Key", BindingFlags.Public | BindingFlags.Instance);
            var _keyPropertyValue = _keyPropertyInfo.GetValue(item, null);

            if (_valuePropertyValue != null)
            {
                FieldInfo _poolCollectionFieldInfo =
                    _valuePropertyValue.GetType().GetField("_poolCollection",
                     BindingFlags.NonPublic | BindingFlags.Instance);
                HybridDictionary poolCollection =
                  _poolCollectionFieldInfo.GetValue(_valuePropertyValue) as HybridDictionary;

                connectionPool.PoolIdentifier = _keyPropertyValue.ToString();
                connectionPool.NumberOfConnections = poolCollection.Count;
            }
            connectionPools.Add(connectionPool);
        }
    }

    return connectionPools;
}

So my unit(integration) tests show that with the same connection string, you have 1 pool with as many connection.Open() you call that have not been cleaned up but the GC yet. 

[TestMethod()]
public void GetConnectionPool_1OpenConnectionTest()
{
    string connectionString = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
    SqlConnection sqlConnection = new SqlConnection(connectionString);
    sqlConnection.Open();
    ConnectionPool connectionPool = ConnectionPoolFactory.GetConnectionPool(sqlConnection);

    Int32 expected = 1;
    Int32 actual = connectionPool.NumberOfConnections;
    Assert.AreEqual(expected, actual);
    sqlConnection.Close();
}

Also, you can see the number of ConnectionPools that are active at any 1 time and the number of connections in those strings. 

[TestMethod()]
public void GetConnectionPools_2OpenConnectionsDifferentConnectionStringsTest()
{
    string connectionString1 = @"Data Source=Dixon12;database=Northwind;Uid=NorthwindUser;Pwd=password";
    SqlConnection sqlConnection1 = new SqlConnection(connectionString1);
    sqlConnection1.Open();
    string connectionString2 = @"Data Source=Dixon12;database=Northwind2;Integrated Security=true";
    SqlConnection sqlConnection2 = new SqlConnection(connectionString2);
    sqlConnection2.Open();
    List<ConnectionPool> connectionPools = ConnectionPoolFactory.GetConnectionPools(sqlConnection1);

    Int32 expected = 2;
    Int32 actual = connectionPools.Count;
    Assert.AreEqual(expected, actual);
}

Armed with that information, I could then confirm if different connection strings open new pools (it does) and that if different threads with the same connection string opens a new pool (it doesn’t). 

[TestMethod()]
public void GetConnectionPools_2OpenConnectionsSameConnectionStringsDifferentThreads_Test()
{
    string connectionString1 = @"Data Source=Dixon12;database=Northwind2;Integrated Security=true";
    SqlConnection sqlConnection1 = new SqlConnection(connectionString1);
    Thread threadOne = new Thread(sqlConnection1.Open);
    threadOne.Start();

    string connectionString2 = @"Data Source=Dixon12;database=Northwind2;Integrated Security=true";
    SqlConnection sqlConnection2 = new SqlConnection(connectionString2);
    Thread threadTwo = new Thread(sqlConnection2.Open);
    threadTwo.Start();

    List<ConnectionPool> connectionPools = ConnectionPoolFactory.GetConnectionPools(sqlConnection2);
    Int32 numberOfConnectionPoolsExpected = 1;
    Int32 numberOfConnectionPoolsActual = connectionPools.Count;
    Assert.AreEqual(numberOfConnectionPoolsExpected, numberOfConnectionPoolsActual);

    Int32 numberOfConnectionsExpected = 0;
    Int32 numberOfConnectionsActual = connectionPools[0].NumberOfConnections;
    Assert.AreEqual(numberOfConnectionsExpected, numberOfConnectionsActual);

}

This means that the connection pool manager is thread safe.  Note that Connections are not thread safe, which is why the # of connections are 0 on the main thread.  And yes, I know I could have looked at MSFT source code to figure this out and perhaps there is some documentation on Thread-Safety is available, but this was fun.

So the next question in my mind is what can have an impact on performance?  For example, if you have connection pool fragmentation (via different connection strings), what is the performance gain my combining all of the active connections into 1 pool?  This post has gotten long enough, so I will show that in another one.

Book Review: Head First Design Patterns

So I understand now why java developers are often accused of spending more time doing mental gymnastics then writing working code.  I am working through Head First Design Patterns as sort of a break from the projects I have been coding (on the advice of Steve Suing) and I am running into some interesting questions.

First,  I like how the authors have taken the Gang Of Four patterns and made them much more accessible.  Not that I like running through academic-prose and small talk examples (I don’t) like in Design Patterns, but the way the Head First books deliver content is great. 

Second, the examples they pick for a given pattern are really well thought-out.  Faster than your can say “Liskov Substitution Principle”, the first chapters explanation of the limitations of inheritance using ducks was spot on. 

Third (notice 2 nice things before 1 not-nice?  They teach that at the positive coaching alliance), I am disappointed that their idea of a “test harness” is a console app.  The next version of the book should use unit tests.

Finally, some code.  I was working though the examples when I got to chapter 3 (I am using C# and not java because I value secure software):

Base Class:

public abstract class Beverage
{
    public Beverage()
    {
        Description = "Unknown Beverage";
    }
    public String Description { get; internal set; }

    public abstract double Cost();
}

(I changed the Description from a field and getter method to a property.  The IL effect is the same, I believe)

The Decorator:

public abstract class CondimentDecorator: Beverage
{
    public new abstract String Description { get; }
}

And example Beverage:

public class Espresso: Beverage
{
    public Espresso()
    {
        this.Description = this.GetType().Name;
    }

    public override double Cost()
    {
        return 1.99;
    }
}

(I changed the Description setter from a hard-coded string to a method assuming the class name is the same.  And yes, ToString() should be overridden also)

And Example Condiment:

public class Mocha: CondimentDecorator
{
    Beverage _beverage;

    public Mocha(Beverage beverage)
    {
        _beverage = beverage;
    }

    public override string Description
    {
        get
        {
            return _beverage.Description + ", " + this.GetType().Name;
        }
    }

    public override double Cost()
    {
        return .20 + _beverage.Cost();
    }
}

So what is wrong?  Well, are you asking or telling Mocha?  If you are asking, then the method should be CalcualteCost().  If you are asking, then you should call GetCost() or its syntactical equivalent Cost{Get;} so you   really have a POCO.  And if you are doing a calculation in a POCO, you are doing something wrong.  So the method should be CalculateCost().  Syntax aside, that means that the Description should be CalculateDescription().  So this looks like a clear violation of command/query separation.  Is this violations the pattern’s fault or the authors?  I don’t know.  I don’t really care.  I guess I “get” the decorator pattern enough so I can have this conversation:

Jamie: Hey, how would you architect an application that needs pluggable components?

Some architect: What about using the Decorator Pattern?

Jamie: Have you ever implemented that, like, for real?

Some architect: Oh, I don’t implement.  I just design.  Want to see the UML?

Jamie: No Thanks.

This brings me to the next part of the book that I am still thinking whether I like or not.  As Bob Martin explains, software has 2 values: the primary value and the secondary value.  The primary is how well the software changes, the secondary is how well it meets the current requirements.  Quite often I see line developers with immediate deadlines looking to solve the secondary value talking to the architect who is interested in  the primary.  Who is right?  Does it matter?  Until technical debt is put on the balance sheet, I fear that secondary will always be put in the back-seat.  I guess code re-work is good for consultants.

Finally, the one thing I really disagree with the book are these captions:

imageimage

I disagree that they put in this global assumption that is a hold-over from the mainframe programming days.  Duplicate code is better than code that has to be changed.  With modern source control and refactoring tools used correctly, duplicate code is not bad.  In fact, if you duplicate code to make sure your follow the Single Responsibility Principle, that is OK.  If you want to refactor later to consolidate, that is fine as long as the unit tests still run green. 

And I think that is the conclusion that I have to my 1st sentence.  Design Patterns are not the end of themselves (most people agree in theory).  They are not even the beginning (Too many architects that I know disagree with that).   Patterns are what you back into and refactor to, not the other way around.  Not really this books fault – after all it is a book about design patterns – not writing working software.  To this end, I think you need to look at Refactoring to Patterns.

Thanks to this clip which I listened to 5 times repeatedly when doing this blog post):

Clean Code and SOLID

I am presenting at TriNug’s Software Craftsmanship SIG on February 27, 2013.  The subject of my talk is Bob Martin’s SOLD principles.  The reason I chose that topic was because at the December lightning talks, I demonstrated the open and closed principle and there were some people in the audience that seemed genuinely interested in all of the SOLID principles.  I already have the CleanCoders brownbag materials that I used last year as a baseline, so I thought I would augment it with some additional resources.

One of the better presentations I have seen on SOLID and software craftsmanship is by Misko Henry in his series of Google Tech talks.  I had so much fun watching his talks that I jumped over to non-SOLID talks that he did.  For example, check out this talk on what Singletons are bad.  Like, really bad.  Like, poke your eyes out bad.

I incorporated what Misko said into my SRP section of the SOLID talk.  Specifically, SRP is not:

  • Use Singletons
  • Classes should only do a single thing
  • Code should be written in a single place (kinda of a DRY principle)

Rather, the SRP argues that classes should have 1 and only 1 reason to change.  To understand the reasons for change, you need to look at the actors.  Where I depart from Uncle Bob slightly is that if two actors both use a class and both have the same reason to change that class, you are still SRP.

In any event, I am doing O tomorrow.  I plan to use the notification example that I showed in the lightning talks as the code examples.

Rock,Paper,Azure

I started playing Rock,Paper,Azure today – a great code contest sponsored by Microsoft.  I ran into some trouble with their out-of-the-box bits (more on that later) but I had some fun once I got a successful deployment going.

First, the problems.  I could not get the local emulator working.  Rather, I can get the Oct 2012 Azure Toolkit emulator running on my local Win7 machine,. but the RPA emulator solution does not work.  I got this weird exception:

image

That no one at Microsoft can figure out.  After about 3-4 hours of changes, I gave up and decided to just use the Azure site to test my Bots (is the plural of Bot “Botts” or “Bots”?).

Second, the logistics.  It was pretty painless setting up an Azure account for this context.  All I had to do was to follow the instructions on their website and I got almost all of the way there.  The one omission from their directions is that once you have your cloud service running,

image

you need to upload the BotLab so you can test your bots before entering them into the contest.  There are not any instructions on the RPA site.  What you need to do is onmce your provision your site, you click on its name to navigate to the upload page:

image

You then need to click on the Upload A New Production Deployment.  You then click on “From Local” for the package and configuration files that you created when you followed this RPA step.

image

Once the files are loaded, Azure spins for a couple of minutes and then you get your lab that you can navigate to and upload your bots.

image

I then loaded up a “Brick Only” Bot to my BotLab:

image

and then pushed it to the actual contest site:

image

Third, the code.

So now that I can upload to my lab and push to the contest, I thought about how to make a better Bot.  Instead of diving right into the code, I set up a new solution with a single project that had a single class.  I added the necessary references and coded up a Rock-only Bot with an associated unit test:

image

With the unit test like this:

[TestMethod()]
public void MakeMoveTest()
{
    RockOnlyBot target = new RockOnlyBot(); 
    IPlayer you = null; 
    IPlayer opponent = null;
    GameRules rules = null;

    Move expected = Moves.Rock;
    Move actual = target.MakeMove(you, opponent, rules);

    Assert.AreEqual(expected, actual);
}

And the class implementation like this:

public Move MakeMove(IPlayer you, IPlayer opponent, GameRules rules)
{
    return Moves.Rock;
}

Before writing my killer Bot, I then put several new classes that correspond to the examples included in the RPA bits into the project with associated unit tests.

image

An interesting thing is that for random moves, my unit test just checks to see if the move is not null (for now)

[TestMethod()]
public void MakeMove_ReturnsInstiantiatedObject_Test()
{
    RandomBot target = new RandomBot(); 
    IPlayer you = null; 
    IPlayer opponent = null; 
    GameRules rules = null;
    Move actual;
    actual = target.MakeMove(you, opponent, rules);
    Assert.IsNotNull(actual);
}

Another interesting thing is that the API that comes with the download does not include any implementations of the interfaces.  So for the BigBangBotTests, I need a instantiation of IPlayer you so I can keep track of you.NumberOfDecisions.  I thought, what a great place to use a Mocking Framework.  Since I am using VS2010, I decided to use MOQ to stub the IPlayer.

[TestMethod()]
public void MakeMove_ThrowsDynamiteOnFirstMove_Test()
{
    BigBangBot target = new BigBangBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.NumberOfDecisions).Returns(0);
    IPlayer opponent = null; 
    GameRules rules = null;
    Move expected = Moves.Dynamite;
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);
    
    Assert.AreEqual(expected, actual);
}

 

So to be safe, I should implement a test for moves 1-5 to make sure that dynamite only comes back.  But I am not safe.  What about moves 6+? For a mocking framework, I need to implement the Random method or just increment the mocked property.  The later seems easier, so that is where I started.  I first injected the Stub only returning NumberOfDecisions = 1 and I got red:

image

I then removed all of the individual runs and put the setup in the for..each loop:

[TestMethod()]
public void MakeMove_DoesNotOnlyThrowDynamiteAfterFifthMove_Test()
{
    BigBangBot target = new BigBangBot();
    var mockYou = new Mock<IPlayer>();
    IPlayer opponent = null;
    GameRules rules = null;

    int numberOfDynamites = 0;
    for (int i = 0; i < 95; i++)
    {
        mockYou.Setup(y => y.NumberOfDecisions).Returns(i);
        Move currentMove = target.MakeMove(mockYou.Object, opponent, rules);
        if (currentMove == Moves.Dynamite)
        {
            numberOfDynamites++;
        }
    }

    Int32 notExpected = 95;
    Int32 actual = numberOfDynamites;
    Assert.AreNotEqual(notExpected, actual);
}

And the test ran green.  As a side not, this test really rests the Random function.  After all, if it turns red, then the random function has returned 95 consecutive dynamites.

I then implemented unit tests for CycleBot like so (only the 1st test is shown):

[TestMethod()]
public void MakeMove_LastMoveRock_ReturnPaper_Test()
{
    CycleBot target = new CycleBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.LastMove).Returns(Moves.Rock);
    IPlayer opponent = null; 
    GameRules rules = null;

    Move expected = Moves.Paper; 
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);
    
    Assert.AreEqual(expected, actual);
}

Note that there is a condition in the implemntation if the last moves is Sissors – if the player still has dynamite.  I created tests for both conditions:

[TestMethod()]
public void MakeMove_LastMoveSissors_HasDynamite_ReturnDynamite_Test()
{
    CycleBot target = new CycleBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.HasDynamite).Returns(true);
    mockYou.Setup(y => y.LastMove).Returns(Moves.Scissors);
    IPlayer opponent = null;
    GameRules rules = null;

    Move expected = Moves.Dynamite;
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void MakeMove_LastMoveSissors_DoesNotHaveDynamite_ReturnWaterBaloon_Test()
{
    CycleBot target = new CycleBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.HasDynamite).Returns(false);
    mockYou.Setup(y => y.LastMove).Returns(Moves.Scissors);
    IPlayer opponent = null;
    GameRules rules = null;

    Move expected = Moves.WaterBalloon;
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);

    Assert.AreEqual(expected, actual);
}

And the battery of tests run green:

image

With the battery of tests done, I then wanted to deploy to Azure.  To that, I needed to add a BotFactory to my project and have it return the class that I am interested in competing:

public class BotFactory : IBotFactory
{
    public IBot CreateBot() { return new MyBot(); }
}

I then loaded the Bot to Azure and sure enough, I got it to compete:

image

With this framework in place, I am ready to start coding my killer bot!