Tuesday, January 17, 2012

Big thanks to Ganesan and the rest of DC DNUG for having me present tonight.  They asked great questions and even provided a speaker gift!  

And Metro delivered me on time and got me safely home on a surprisingly pleasant January night.

Tuesday, January 17, 2012 10:02:33 PM (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Sunday, December 18, 2011

I followed through on my threat to do a presentation on using tiny objects. My supposition is that most developers (myself included) resist creating trivial (tiny) objects even when they could clean up code. Objects don’t have to possess lots of properties or methods to become useful.

Let’s take this example…

Random _randy = new Random();
public List<double> TestSeriesPoints(int numberOfPoints, double minValue, double maxValue)
{
    if(minValue >= maxValue)
    {
       throw new Exception("minValue must be less than maxValue");
    }

    List<double> points = new List<double>();
    for (int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
    {
        double point = _randy.NextDouble() * (maxValue - minValue) + minValue;
        points.Add(point);
    }
    return points;
}

It is a pretty straightforward method that returns some test data within the range of a min and max value.  It’s a short method, and pretty easy to grok, so 99 times out 100, it wouldn’t be given a second glance.  But there is a tiny object buried in here, one that will not only make this code cleaner, it will make modifying it easier too.

Any time we see two variables that are always used in tandem, it is time to make a Tiny Object…

Random _randy = new Random();
public List<double> TestSeriesPoints(int numberOfPoints, double minValue, double maxValue)
{
    if(minValue >= maxValue)
    {
       throw new Exception("minValue must be less than maxValue");
    }

    List<double> points = new List<double>();
    for (int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
    {
        double point = _randy.NextDouble() * (maxValue - minValue) + minValue;
        points.Add(point);
    }
    return points;
}

Where there’s a min value, there’s bound to be a max value. They don’t exist without each other, so let’s make the commitment and formalize the relationship…

public class DoubleRange
{
    public double MinValue = 0;
    public double MaxValue = 100;
}

By combining two floating (but always proximate) variables into a single Tiny Object, we’ve pulled ourselves out of procedural thinking and opened up the OOP world.  We could leave it like this and still get some some benefits.  But by its mere creation, our new Tiny Object has given us something concrete to work with and re-use. It gives us a place to add behaviors and properties that consuming code will no longer have to repeatedly re-implement.

Once this object has materialized, it becomes apparent we can ensure that our range is always valid by using a constructor and encapsulated properties.  And we can turn the actual range of our DoubleRange into a property, so the consuming code does not have to recalculate it. Finally, we can also create default constructor that sets our range to have common min and max values.

public class DoubleRange
{
    private double _minValue;
    private double _maxValue;

    public DataRange():this(0,100)
    {
    }

    public DataRange(double minValue, double maxValue)
    {
        if(minValue >= maxValue)
        {
             throw new Exception("minValue must be less than maxValue");
        }
        _minValue = minValue;
        _maxValue = maxValue;
    }

    public double MinValue
    {
        get{return _minValue;}
    }

    public double MaxValue
    {
        get{return _maxValue;}
    }

    public Range
    {
        get{return MaxValue - MinValue;}
    }
}

Our consuming code can boil off some logic that lives in the Tiny Object, so it looks like this…

Random _randy = new Random();
public List<double> TestSeriesPoints(int numberOfPoints, DoubleRange testDataRange)
{
    List<double> points = new List<double>();
    for (int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
    {
        double point = _randy.NextDouble() * testDataRange.Range + testDataRange.MinValue;
        points.Add(point);
    }
    return points;
}

Our Tiny Object has grown into something useful…

  • the consuming code is clearer, working with a DoubleRange object, not some implicitly related values
  • the unexplained (maxValue – minValue) expression in our calculation is explicitly defined in its new object home
  • the object handles its own validation

Finally, adding one small method to our Tiny Object will also make debugging  and logging easier…

public override ToString()
{
   return string.Format("Range {0:n4} to {1:n4}", _minValue, _maxValue);
}

Now, any time the object is added to a log statement, we’ll always see the current range values like so…

Range 0.0000 to 100.0000

That gives us three of the four joys of OOP -- abstraction, encapsulation,  and polymorphism – all in one Tiny Object. 

So the next time you see two or three variable spending a lot of time together, do the right thing move them into their own Tiny Object and see what other  wonderful attributes and behaviors blossom.

And always remember there are no Tiny Objects, only tiny developers.

OOP
Sunday, December 18, 2011 4:09:56 PM (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Wednesday, November 16, 2011

The links have the zipped versions of the before and after refactoring projects from the Break the If Habit presentation. 

Wednesday, November 16, 2011 12:29:11 AM (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 

I headed out to Columbia, Maryland this past weekend to speak at the CMAP Fall 2011 Code Camp. I was shocked that so many people wanted to see code refactoring at 8:45 on a Saturday morning, but was happy to have an excellent crowd.

The presentation was on breaking the If habit.  To steal the abstract…

Branching logic is one of the foundations of computer programming. But like vodka, the If statement is best consumed in moderation. While the first If is harmless, and maybe even a little thrilling, soon there's a second, a third, a fourth and before you know it -- you wake up under your desk with a method you don't even recognize much less understand.

In this session we'll explore some of the common If abuses and learn how to refactor them into more readable and adaptable code. We'll use design patterns to put the demon If back in its bottle and keep it there. Saner code is within reach, and this is the first step to break the the If habit.

The inspiration for this talk was some legacy code I had to update.  It was already sagging under a dense thicket of if statements that crossed two methods and already had 18 paths. I was supposed to add yet another set of if statements to support yet another variation of the report this code generated. 

I just couldn’t bring myself to do it.  It had taken me two hours to analyze where the changes had to be made so they wouldn’t break anything else. I knew adding these statements was just stuffing more complexity into two methods that were already bursting with branching logic.  The next change would require even more analysis and would more likely lead to something getting broken.

So, I started ripping out code.  I’d like to claim I was purposefully refactoring to a pattern, but it was really more instinctual, moving the code for each variation into its own class.  What it turned out I was doing was replacing a conditional with polymorphism, or implementing a strategy pattern.

The example from the talk started out looking like this…

public double CalculateProfitSharing(Employee employee, DateTime asOfDate, double grossProfit, EmployeeStats stats)
       {
           TimeSpan lengthofEmployment = asOfDate - employee.StartDate;
           double pool = grossProfit*0.04;
           double profitSharingAmount = 0;
           if(lengthofEmployment.Days > 182)
           {
               double basePartofPool = 1.0/(double)stats.EmployeeCount * pool;
               double loyaltyMultipler = lengthofEmployment.Days/stats.AverageLengthEmploymentinDays;
             
               //current year pro-rate
               double proratedRate = 1;
               if(lengthofEmployment.Days < 365)
               {
                   proratedRate = lengthofEmployment.Days/365.0;
               }
               profitSharingAmount = basePartofPool*loyaltyMultipler*proratedRate;

               if(employee.Sales)
               {
                   profitSharingAmount = 0;
               }
               else if(employee.Level < 4)
               {
                   if(employee.Level == 2)
                   {
                       profitSharingAmount *= 1.5;
                   }
                   else if(employee.Level == 3)
                   {
                       profitSharingAmount *= 2;
                   }
                   if (profitSharingAmount  > 10000)
                   {
                       profitSharingAmount = 10000;
                   }
               }
               else
               {
                   profitSharingAmount *= 2.5;
                   if(profitSharingAmount > 5000)
                   {
                       profitSharingAmount = 5000;
                   }
               }
           }
           if(profitSharingAmount <0 & employee.Level < 4)
           {
               profitSharingAmount = 0;
           }
           if(employee.Level == 4)
           {
               if(profitSharingAmount < -5000)
               {
                   profitSharingAmount = -5000;
               }

               if(profitSharingAmount > 0)
               {
                  
                   if((asOfDate - employee.LastOptionGrant).Days<= 365)
                   {
                       profitSharingAmount = 0;
                   }
               }
           }
           if(employee.Level < 4)
           {
               if(employee.ChoseDeferred)
               {
                   profitSharingAmount *= 1.25;
               }
           }
           return Math.Ceiling(profitSharingAmount);
       }

And ended up looking like this...

public double CalculateProfitSharing(Employee employee, DateTime asOfDate, double grossProfit, EmployeeStats stats)
{
     var profitSharingLevel = GetProfitSharingLevel(employee);
     return profitSharingLevel.CalculateProfitSharing(employee, asOfDate, grossProfit, stats);
}

private ProfitSharingEmployeeLevelBase GetProfitSharingLevel(Employee employee)
{
     if(profitSharingLevels.ContainsKey(employee.Level))
     {
         return profitSharingLevels[employee.Level];
     }

     return new ProfitSharingEmployeeLevelNullObject();
}

There is obviously some code in the new classes that encapsulates the variations so there is not a reduction in the total amount of code. But every method becomes much each easier to understand when you don’t have scroll to through pages of nested if statements.  It also becomes easier to change and maintain code when your rules for each variation aren’t tangled together in gobs of if statements.

The presentation also included how to use the Null Object Pattern so you can stop sprinkling your code with null checks (there’s an example above – just imagine GetProfitSharingLevel is public and is called by more than one other method). It was also supposed to show the replacement of branching logic with the Decorator Pattern, but we ran out of time. I’ll try to explore these in more detail in other blog posts, but not tonight.

I think the root cause of most If abuse is the refusal of developers to create objects, especially small ones.  I think there is an innate aversion to creating seemingly trivial objects no matter how helpful they might be.  Packaging two pieces of related information and/or a method together should be reason enough to make a new class, but that doesn’t seem to pass the “I need a new class” threshold for most developers. I know it’s below mine. 

For instance, implementing a calculation for a tiered sales commission is usually done with if statements. 

                double commission = 0;
                 if (yearSales < yearTarget)
                 {
                     commission = 0.005 * yearSales;
                 }
                 else if (yearSales < yearTarget*2)
                 {
                     commission = 0.01 * (yearSales - yearTarget) + 0.005 * yearTarget;
                 }
                 else
                 {
                     commission = 0.02*(yearSales - yearTarget*2) + 0.01 * yearTarget + 0.005 * yearTarget;
                 }
                 compensation += commission;

And it’s fine, it works, it is even fairly compact  – but it takes a while to understand, extending it requires additional if statements and it is buried inside a method – wholly unusable anywhere else.  But the worst sin is that we have a clear object here with two properties and a method, and we have denied its existence.

What we should do is create a small object…

public class CommissionTier
    {
        private double _tierStart;
        private double _rate;

        public CommissionTier(double tierStart, double rate)
        {
            _tierStart = tierStart;
            _rate = rate;
        }

        public double TierStart
        {
            get { return _tierStart; }
        }

        public double GetCommision(double sales)
        {
            return (sales - TierStart)*_rate;
        }

        public override string ToString()
        {
            return string.Format("Tier Start:{0:c0}, Rate {1:0.00%}", _tierStart, _rate);
        }
    }

Then we can use a looping structure that is more clear about what we’re doing. It is also now easily extensible.  To add a tier, we just need to add a new instance of the CommissionTier object to the collection – no logic changes required.  Heck we could even drive tier creation from a database…

_tiers.Add(new CommissionTier(yearTarget * 2, 0.02));
_tiers.Add(new CommissionTier(yearTarget, 0.01));
_tiers.Add(new CommissionTier(0, 0.005));

double commission = 0;
double workingSales = yearSales;
foreach (CommissionTier tier in _tiers)
{
    if (workingSales > tier.TierStart)
    {
        commission += tier.GetCommision(workingSales);
        workingSales = tier.TierStart;
    }
}  

By promoting the Commission Tier to an object instead of leaving it strewn about in manually related variables, magic numbers and calculations, all of sudden we have all the tools of OOP available to us. Our logic and our data are packaged together nicely.  The object has control of its data and we can leverage the power of collections. 

So instead continuing to pack procedural programming spaghetti into our methods, we need to be object oriented designers and create more frickin’ objects. Only then can we begin to break the If habit.

Wednesday, November 16, 2011 12:03:34 AM (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Wednesday, June 15, 2011

I have been doing more with LINQ and extension methods of late and thought I should delve a (little) more deeply into the somewhat mysterious => operator.  So I did a little reading, a little coding and little PowerPoint presentation and did a n00b presentation at RockNUG this month.

.NET | Lambda
Wednesday, June 15, 2011 8:23:49 PM (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 

Theme design by Dean Fiala

Pick a theme: