Cracking open a legacy code 'black box'...

Legacy code and integrations can seem black box when you see them for the first time. You’re expected to get familiar quickly. No matter how much time you’re given to get familiar with your new project, you could always use more time.

The first time this hit me in the face was when I was given a 2-day deadline to add a feature to a legacy project. It seemed simple enough so I agreed that I could do it. When I opened the project, I felt sick. It was in VB.NET. I had spent years learning C#. C# was the language I was supposed to be using for everything. How could I ship something in VB.NET in 2-days?

As a C# developer with a deadline, a VB.NET method looks intimidating:

Public Shared Function WordWrap(ByVal input As String, 
		ByVal len As Integer, 
		ByVal delimiter As Integer) As String

    ' If the input String is less than the lenght specified, no delimitors
    ' are necessary.
    Dim strBuilder As String = String.Empty
    Dim seps() As Char = {" ", "\n"}
    Dim words() As String = input.Split(seps)
    Dim curLineLength As Integer = 0
    Dim word As String
    For Each cword As String In words
        word = cword.Trim()
        If curLineLength + word.Length > len Then
            If curLineLength > 0 Then
                strBuilder = strBuilder + Chr(delimiter).ToString
                curLineLength = 0
            End If
            While (word.Length > len)
                strBuilder = strBuilder + word.Substring(0, len - 1) + "-"
                word = word.Substring(len - 1)
                strBuilder = strBuilder + Chr(delimiter).ToString
            End While
            word = word.TrimStart()
        End If
        If curLineLength > 0 Then
            word = " " + word
        End If
        strBuilder = strBuilder + word
        curLineLength += word.Length
    Next
    Return strBuilder
End Function

There were many more methods like this, looking entirely foreign to me. There was no way I was going to learn the language in 2 days.

I found a better solution… tests.

Since VB.NET and C# both compile with the CLR down to the same machine language, I can write tests for VB.NET code in C#. If I can write tests for the VB.NET code, I will only have to learn the language features I need in order to get the work done.

I started with a first test, just trying to run the code… trying to get a first test to pass:

[Fact(DisplayName = "What does WordWrap do?")]
public void What_does_wordWrap_do() {

    var input = "This is a string I'm going to use as input just to see what this method does";

    var output = CommonUtilities.WordWrap(input, 10, 1);

    Console.WriteLine(output);
}

Here’s the stdout:

This is a\x1string I'm\x1going to\x1use as\x1input just\x1to see what\x1this method\x1does

So this method puts a character at every len value in a string. Looking at the coverage of the test, looks like I did pretty well:

Notice we didn’t cover all of the method… there’s branching logic that the original developer had to add - either because a) he anticipated it or b) he ran into a bug caused by not having that logic.

So I’ll cover it:

[Fact(DisplayName = "When WordWrap input has a string that is longer than the len parameter")]
public void WordWrap_when_string_is_larger_than_len_value() {

    var input = "Thisisasuperlongstring";

    var output = CommonUtilities.WordWrap(input, 10, 1);

    Console.WriteLine(output);
}

Here’s what passing in a word that’s larger than the len variable does:

Thisisasu-\x2perlongst-\x2ring

The method adds a “-” to break the string up if it exceeds the len parameter.

That was just a simple example, but what if you’re needing to look at methods with an endless number of parameters and 100s of lines of code?

Public Shared Sub BulkWrite(ByVal RecordId As String,
	ByVal session As UniSession,
   	ByVal uFile As UniFile, 
   	ByVal writeType As String, 
   	ByVal sqh As SalesQuote, 
   	ByVal numberOfDetails As Integer, 
   	ByRef writer As LogWriter)

 	// 300 lines...

End Sub

By taking the same incremental testing approach as I have above, I would be able to get a handle on what this code is doing, without even knowing VB.NET.

You can use tests as a tool for working with legacy code. Testing is more than just making sure your code doesn’t break when you push it to your build server or production. When applied to legacy code, tests can reveal what’s going on inside of “black boxes.” This is true even when the production code is written in a language you’ve never seen before.

I have more to talk about regarding testing, so make sure you sign up for my newsletter to get these posts sent right to your inbox!


Related Posts:

Tweet
comments powered by Disqus