CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Raymond Lewallen

Framework Design, Agile Coach, President Oklahoma City Developers Group, Microsoft MVP C#, TDD, Continuous Integration, Patterns and Practices, Domain Driven Design, Speaker, VB.Net, C# and Sql Server

Learn from my mistakes - refactoring and fixing design smells using common patterns

So I’m working in a maintenance release right now.  Very little added functionality.  My current release at work is primarily to adjust to domain logic changes.  This starts by adjusting the unit tests to accomodate the changed logic, and then fixing the code to fix the tests.  Still, due to the nature of the changes, a lot of regression testing will still be involved.

This release also gives me an opportunity to go back and fix some serious design errors that I have lazily let make their way into the code.  I want to cover a few these now, tell you why they are design mistakes, and how to fix them.  Feel free to leave nasty comments here and add me to your wall of coding shame for some of these.  For the most part, I was being lazy, but recognizing these mistakes and fixing them as soon as I have the opportunity should award me back some brownie points, right?

Poor use of some static classes

Static classes are something that you usually don’t find too often in a framework, and rightly so.  They are there to only support the instance classes of the rest of your framework, but there is a right way and wrong way to do that.  Of the several static classes I have, the majority are designed correctly, but two of them are not.

Here’s the design mistake: I have 2 static classes that are a catch-all for miscellaneous methods that support the framework.  Let’s say you have an application for tracking car sales.  To mimic the design mistake, I have a static class such as the following:

Static Class GlobalMethods
     GenerateNewCarId() : Int32 // generates a new Car ID
     GenerateNewCustomerId() : Int32 // generates a new Customer ID
     VerifyEmail(email)  : Boolean // verifies a customer email address using RegEx
     Age(dateOfBirth) : Int32 // returns a Customers Age

Now, each of these are fine being static methods, but they are for the most part, unrelated.  Better organization needs to occur here.  I should create a new static class in the namespace for the Cars and another in the namespace for the Customers, and move each Id method to its corresponding static class so its coupled with the rest of its entities.  The Age function can be moved to the Customer instance class itself, where the dateOfBirth is already stored as part of the state of the object and we can remove the parameter from the function.  VerifyEmail can perhaps be made a private method inside the Customer instance class, and be called when we load the object state, or simply {get} the Email property.  How to handle the logic if the VerifyEmail fails is dependant upon your particular situation.  My actual code isn’t this blatently bad, but you get the idea.

Reducing If/Then and Switch logic

I could talk about this, but Jeremy has an excellent post on using the Strategy Pattern, which is I need to implement into some code that has become bloated and overly complex.

These next few pieces of design problems are all coupled together to reach a common goal.

Unify Interfaces

The idea around unifying classes (the actual refactoring applied here is referred to as Unify interface) revolves around evolving subclasses without evolving your interfaces or superclass.  As my application has evolved, so has a number of classes that either implement an interface or inherit a superclass.  The added methods to the subclasses don’t exist in the superclass, such as the following:

Public Class Vehicle
     NumberOfWheels : Int32
     Doors : Int32
     Color : ColorEnum
     Weight : Int32

Public Class Car : Vehicle
     ToHtml() : String
     NumberOfWheels : Int32
     Doors : Int32
     Color : ColorEnum
     Weight : Int32

As you can see, my subclass contains a method, ToHtml, that returns a description value to display on a webpage, that doesn’t exist in the superclass.  To unify the interfaces of both, I need to copy the missing methods to the superclass.  Now my superclass Vehicle looks like this:

Public Class Vehicle
     ToHtml() : String
     NumberOfWheels : Int32
     Doors : Int32
     Color : ColorEnum
     Weight : Int32

Now my subclass and my superclass share a common set of functionality, i.e. a common interface.

Extract Interfaces

Now that this is done, I’m ready for another refactoring to take place: Extract Interface.  So now I’m left with the following:

Public Inteface IVehicle
     ToHtml() : String
     NumberOfWheels : Int32
     Doors : Int32
     Color : ColorEnum
     Weight : Int32

Public Class Vehicle : IVehicle
     ToHtml() : String
     NumberOfWheels : Int32
     Doors : Int32
     Color : ColorEnum
     Weight : Int32

Public Class Car : Vehicle
     ToHtml() : String
     NumberOfWheels : Int32
     Doors : Int32
     Color : ColorEnum
     Weight : Int32

Now I’m much closer to a better design than what I started with for this set of classes.

Make unit testing easier

To take it one step further, imagine a class that relies on the Car object to do its work.  And let’s also say we have a unit test on this class, but in order for the test to work, we have to have a connection to the database.  Well, we don’t like that very much, so a good way to remove that database layer is to use dependency injection.  Take the following class:

class Ticket

    {

        private Car _car;

        private Int32 _carId;

 

        public Ticket() {}

 

        public Ticket(Int32 carId)

        {

            _carId = carId;

        }

 

        public void Load()

        {

            // do something to load the car

            // object using the carid, if it

            // is > 0

        }

    }

In order to test this class and its methods (that I didn't bother adding for the examples, but there are other methods on the class we need to test), we must have a Car object, but the only way we can get it right now is to load one from the database after calling the constuctor that takes a carId parameter.  Not very good.  Big design mistake on my part, and I have plenty of places where this needs to be fixed in my code.  Take time to curse me under your breathe right now.

How do we fix it?  If you read the above link, and you should have, you know the answer.  We implement dependency injection into the equation.  We are going to use a mock Car object, give that object to the Ticket class, and use that mock object to do our unit testing, rather than requiring a connection to the database.  When we’re done, and again, you know how all this ties in because you read the above link, we end up with this:

class Ticket

    {

        private IVehicle _car;

        private Int32 _carId;

 

        public Ticket() {}

 

        public Ticket(Int32 carId)

        {

            _carId = carId;

        }

 

        public Ticket(IVehicle car)

        {

            _car = car;

        }

 

        public void Load()

        {

            // do something to load the car

            // object using the carid, if it

            // is > 0

        }

    }

Now we can just give the Ticket class a Car to use to do its testing.  This wouldn’t have been possible if I hadn’t gone through the above Unify Interfaces and Extract Interface refactorings first.

So there are the major design smells that I’m going to be fixing over the next two months.  I hope you read this, learn from my design laziness and mistakes so that you don’t have to have a maintenance release.  The people signing your paycheck really, really hate maintenance releases, because they are paying you for ZERO or minimal functionality for that release.  Its best to avoid these mistakes altogether, but incase you need to sneak in a few similar fixes, hopefully my above roadmap will help you out.



Comments

Matt Berther said:

Hi Raymond,

Instead of using a static class for your identifiers, I have done something like this for my domain identity creation...

public class EntityID
{
   private string id;
   
   public EntityID(string id)
   {
       this.id = id;
   }
   
   public string Id
   {
       get { return id; }
   }
}

public interface EntityIDFactory
{
   EntityID GetNextID();
}

public class GuidEntityIDFactory
{
   public EntityID GetNextID()
   {
       return new EntityID(Guid.NewGuid().ToString());
   }
}

And then, anything that needs to generate an ID could take an EntityIDFactory in its constructor... This allows you to mock this up much easier, which is always a bonus for unit testing... especially if your real EntityIDFactory makes a database call.

The other thing that you notice here is that Im putting an object around the EntityID... a *real* bonus if that ID ever changes (say, a composite ID or something).

If that happens, I only have to go to the EntityID class to change it rather than futz with a whole bunch of methods.

Whenever possible, I look to put an object around any primitive types that represent domain concepts.

Just my $.02... YMMV...
# May 1, 2006 11:56 PM

Udi Dahan - The Software Simplist said:

ToHTML ?! What does that have to do with cars, vehicles, etc? What about separating presentation from logic?
# May 2, 2006 4:38 AM

Raymond Lewallen said:

Nice Matt.  I don't actually create Id's in my logic, I was just using it as an example, but no doubt what you've posted is of great help to others.
# May 2, 2006 8:34 AM

Raymond Lewallen said:

Udi, it was just an example.  Put whatever you want to in there to simulate the need for going through the above refactorings.  Call it CalculateMilage or CalculateSpeed(rpm, gear, tireSize).
# May 2, 2006 8:36 AM

Eric Marthinsen said:

Can you expand on your logic for implementing the IVehicle interface and the Vehicle base class? It looks like you've added a level of abstraction on top of another level of abstraction. What's your motivation?
# May 2, 2006 11:35 AM

Raymond Lewallen said:

Eric,

My Vehicle class serves as a base class with base functionality for subclasses that will derive from it.  Car, truck, van, motorcycle etc can all inherit from Vehicle, and either choose to inherit the default behavior (if the default value for the Doors property in Vehicle is Zero, then motorcycle will not need to override the property).  It allows me flexibility and the ability to expand the subclasses by simply adding new functionality to the base class.  Overriding Object.ToString in Vehicle is a good example of adding new behavior without changing every single subclass, unless required.

In this particular example, IVehicle was extracted from Vehicle in order to provide a means of unit testing via dependency injection, which is much more preferred over requiring a database connection to fill the Car object.  I, personally, and this is just personal preference, do not use interfaces all that often except in cases like stated for unit testing, because they don't provide the flexibility that abstract classes do.  Keep in mind, now that I do have the interface IVehicle, if I did add functionality to Vehicle, another Unify Interface refactoring would need to occur to make Car conform to the interface and provide the ability to completely test Car.
# May 2, 2006 1:54 PM

Jason Haley said:

# May 5, 2006 12:02 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Raymond Lewallen

Working primarily in the public sector during his career, Raymond has designed and built several high profile enterprise level applications for all levels of the government. Raymond now works as a solutions architect for EMC. Raymond is an agile coach, Microsoft MVP C# and also president of the Oklahoma City Developers Group and Oklahoma Agile Developers Group. Raymond spends a lot of his time learning and teaching such things as Test Driven Development, Domain Driven Design, Design Patterns and Extreme Programming practices and principles, to name a few. Raymond is also an advocate of Alt.Net. Raymond is primarily a framework guy, so don't ask him anything about UI :) Check out Devlicio.us!