Saturday, September 5, 2009

Sufferings with switch smell


Introduction
In my first blog, Using enum in C# for smart coding, described code snippets suffer with switch smell. So, here, I am explaining what the switch smell is, what’s wrong with it and how to avoid it?
 
Most of the time, our source code suffers with several bad smells. Authors of a great book, Refactoring: Improving the Design of Existing Code, explain these smells with refactoring techniques. Here, I try to explain how switch smell introduces unnecessary complexity, reduces flexibility and leaves a class with vague responsibilities (from caller’s point of view).



Code Explanation
In the following two samples (Sample 1 & Sample 2), I have written a class, Calculator which can perform four basic arithmetic operation addition, subtraction, division and multiplication on two numbers.
Note: Here all code snippets are written in C#.


Sample 1:
public enum Operation
{
    Add,
    Subtract,
    Multiply,
    Divide
}
public class Calculator
{
    public double Calculate(double firstNo, double secondNo, Operation operation)
    {
        switch (operation)
        {
            case  Operation.Add:
            {
                return (firstNo + secondNo);
                break;
            }
            case Operation.Subtract:
            {
                return (firstNo - secondNo);
                break;
            }
            case Operation.Multiply:
            {
                return (firstNo * secondNo);
                break;
            }
            case Operation.Divide:
            {
                return (firstNo / secondNo);
                break;
            }
            default:
            {
                throw new ArgumentException("Incorrect Argument");
            }
        }
    }




Sample 2:
public class Calculator
{
    public double Add(double firstNo, double secondNo)
    {
        return (firstNo + secondNo);
    }
    public double Subtract(double firstNo, double secondNo)
    {
        return (firstNo - secondNo);
    }
    public double Multiply(double firstNo, double secondNo)
    {
        return (firstNo * secondNo);
    }
    public double Divide(double firstNo, double secondNo)
    {
        return (firstNo / secondNo);
    }
}




Calculator of Sample 1 provides these functionalities with its Calculate() method whereas Calculator of Sample 2 has four methods for four specific functionalities.
In Sample 1, I introduce switch statement inside Calculate() method to distinguish the request of client code whether it (client request) wants to add, subtract, multiply or divide. On the other hand, in Sample 2, as each functionality is implemented in separate method I haven’t bothered with condition-checking (switch statement).



Comparison
Now, the question is: Which class is better than other one?
From design point of view Calculator is responsible for four distinct arithmetic operations, so it should have four methods in implementation level.
In Sample 1, Calculator has only a single method, Calculate() which perform four arithmetic operations. As a result it represents poorly self-documentation and introduces unnecessary complexity. It suffers with switch smell. As a result Calculator responsibilities is not concrete here. So, caller of the Calculate() method has to decide what it (caller) wants from Calculate() method by setting the parameter.
On the other hand, in Sample 2, interface of Calculator is clearer and also it is self-documented.
Sample 2 is more flexible than Sample 1. Suppose if I want to provide another functionality to add three numbers.
For Sample 2, I quickly write overload Add() method as follows with reusability.





public double Add(double firstNo, double secondNo, double thirdNo)
{
    return Add(Add(firstNo, secondNo), thirdNo);
}




But what’s for Sample 1?  :-((. I have to follow some ugly and stupid ways to implement this functionality which introduces more complexity, code repetition, procedural thoughts etc.


More..
In Refactoring: Improving the Design of Existing Code, Authors explain this problem (Sample 1)  under bad small of switch statement and also show several ways (‘Replace type code with Subclasses’, ‘Replace type code with State/Strategy’, ‘Replace Parameter with Explicit Method’ how to refactor this smell. At the same time, authors describe ‘Parameterize Method’ which seems reverse of our discussion.


Conclusion
Each method of a class should represents a single activity, must be concrete and self-documented. One more activities in a single method (by switch smell) or one activity in several methods (I will discuss it another day) introduces complexicity and ambiguous interface, hinders changes, intencifies duplication and leave the class poorly self-documented.




Source : Sufferings with switch smell (http://ztiemoon.blogspot.com/)

No comments:

Post a Comment