Applying Working Effectively With Legacy Code

Having recently read “Working Effectively With Legacy Code” (WEWLC) my work provided me the oppertunity to put it into practice. I had been handed a small program to maintain : it has a few issues that needed fixing. The product is written in VB.NET, uses a mixture of module level functions and classes to acheive it’s aims. There is no clear design or documentation and it relies upon COM calls to an external API of a product that I do not have a licence for (and it would be expensive to obtain). It had no unit test coverage. By all definitions this is Legacy code.

To be fair the application did have a set of wrapper functions that were used to access the API.
The first stage was to put these methods into a class and use “Lean On The Compiler” to find where to create the class. Having done so I was able to add some methods to the class so that it provided a better abtraction from the COM API (the same three COM calls were being made in sequence across the App). Once I had these I was able to reduce a fair amount of duplication.

Having extracted a class that access the COM API (which I could not yet unit test) I was able to perform “Extract Interface”. Given that COM API’s are extensively interfaces they are very easy to mock (except that the interfaces are execisive wide). By mocking one of the COM interfaces I was able to re-implement the extracted interface. This finally allowed me to get some of the application under NUnit.

Eventually the bug turned out to be in the data access code – there was a remove method with an optional second parameter. The second parameter controls whether to remove the item from the underlying database.

By using the techniques in WEWLC I was able to get an unwieldy application at least partially under unit test. However I was not quite able to meet the stringent requirements of unit tests taking less than 0.01 seconds. In addition the policy of not touching the database in the unit test meant that I had not been able to find the given bug directly. I had managed to prove that the method that called it was otherwise working.

I can see WEWLC becoming a classic along the lines of Refactoring.
It provides the answers to the questions that would prevent most people from attempting to get their code under a test harness and thereby allows TDD to be used on non-greenfield projects.

VB.NET not so painful

I have recently taken over the maintenence of a VB.NET project.
I don’t have to to rewrite it in C# (as I would like).
It was not as painful as I had expected.

The VS.NET IDE varies depending upon the language that you are using.
The VB.NET version makes it harder to find event handlers associated with an object.
It’s automatic reformating is painful – it tries too hard.
In addition there is a major flaw with the editor assingning line breaks – if you declare a private variable starting with an underscore then the line under the section break obscures the underscore
leaving you with apparently a diffferently named variable.

The automatic complilation can be useful – it does not work automatically when you only change the scope of a variable.

All-in-all it is not an unplesant language to use (which is different from the old VB) but I would not choose to use it for a new project.

Unit testing stored procedures

Here is a xUnit suite for stored procedures in SQL Server.

Here is the version for Oracle

This is a slight pain having two suites for the various databases.

I am not sure what the author of “Working Effectively WIth Legacy Code” would make of these.
His definition of a unit test involves not touching a database – which would make this difficult.

Working Effectively with Legacy Code

This book covers the adoption of Unit Testing and TDD into existing (Legacy) applications.
The author defines Legacy code to be any code not covered by unit tests (which is rather strict).
He also insists that individual unit tests that take 0.1 seconds are slow.
This prevents unit tests from relying upon databases.

I have a slight problem with implementing that – the main projects that I work on have a fair amount
of stored procedure code. These need unit test coverage (plus the interfaces with the rest of the code also needs to be tested).

The book also provides strategies to get Legacy code under test.

Referenced Book:

Rober C Martin’s Agile Software Development : Principles, Patterns and Practices (Pearson Education, 2002).

Oracle vs SQL Server

I have been using SQL Server for the last few years.
It is very user friendly and has a gentle learning curve.

Investigating a port to Oracle has been a real culture shock.
Out of the box Oracle only has a command-line interface.
To get the equivalent of Query Analyser in Oracle you need to
use a third party tool such as TOAD or PL/Developer.

SQL Server is also more flexible when dealing with stored procedures – you can directly return recordsets. Oracle is very strict when dealing with stored procedures all output must be via parameters.

To Oracle’s benefit they have much stronger error handling. SQL Server stored procedures cannot be used to catch constraint validation errors. This is rather annoying and forces a look before you leap approach.

Useful SQLPlus Commands

The SQLPLUS utility is the Oracle equivalent of iSQL.

It includes a few shortcuts to make life easier:

@FILENAME

This will excecute FILENAME (or FILENAME.SQL)

SHOW ERRORS

This will show the detailed errors for the last command.

L

This lists the last command entered.

Beware that stored procedures or functions cannot include blank lines (as far as i can tell – I got so many errors that I removed them).

Without some of these commands it is as user-friendly as a cornered rat.

Recordsets from Oracle Stored procedures

This is link to an article that explains how to Oracle stored procedures to return recordsets.

The main trick is to add:

//<![CDATA[
<!–
document.write('’);
document.write(‘ .scripthide { display: none; }’);
document.write(‘ .scriptinline { display: inline; }’);
document.write(‘ .scriptblock { display: block; }’);
document.write(”);
//–>
//]]>
<style type=”text/css”><!– .noscripthide { display:none; } .noscriptinline { display:inline; } .noscriptblock { display:block; } //–></style>
//<![CDATA[
<!–
if (document.getElementById) {
document.write('’);
document.write(‘ .script12hide { display: none; }’);
document.write(‘ .script12inline { display: inline; }’);
document.write(‘ .script12block { display: block; }’);
document.write(”);
}
//–>
//]]>

//<![CDATA[
<!–
if (document.getElementById) {
document.write('’);
document.write(‘ .lnav { position: absolute; }’);
document.write(‘ .lnavch { margin-left:23.0ex;}’);
document.write(”);
}
//–>
//]]>

//<![CDATA[

//]]>

//<![CDATA[
<!–
// ———————————-
// visibility functions
function tog() {
// tog: toggle the visibility of html elements (arguments[1..]) from none to
// arguments[0]. Return what should be returned in a javascript onevent().
display = arguments[0];
for( var i=1; i
//]]>

//<![CDATA[

//]]>

//<![CDATA[

//]]>

//<![CDATA[

//]]>
Extended Properties=”PLSQLRSet=1″ to your connection string.

The cursor itself must be defined as a ref cursor :

CREATE OR REPLACE
PACKAGE Types AS
  TYPE cursor_type IS REF CURSOR
END;

Oracle 9i introduced the SYS_REFCURSOR type for this purpose.

Here is a valid example:

CREATE OR REPLACE
PROCEDURE USP_GET_UNIT(p_recordset OUT SYS_REFCURSOR) AS
BEGIN
    OPEN p_precordset FOR
       SELECT UNIT, DESCRIPTION FROM UNIT;
END;

On the delphi side don’t add the cursor as a parameter.