Branching Over A "Type Code" - A Code Smell

Introduction

Conditional clauses are a very important part of any programming language because they perform some operations based on certain conditions. It is like a hammer that is a very useful tool in all cases but can be evil in the case of misuse.  Sometimes conditional clauses like "If.. else, switch..case" are very difficult to manage in the case of more branching and are poorly designed. Here, I will totally focus on  the "if..else" branching code smell.
 
If... else branching is very good and can't be avoided in the below case.
  1. private int GreaterNumber(int first, int second)  
  2. {  
  3.     return (first > second) ? first : second;  
  4.   
  5. }  
A code without if...else statements is very difficult but more branches managed badly creates issues, because it increases the "Cyclomatic Complexity". Codes with the higher Cyclomatic complexity are very difficult to obtain full code coverage in unit tests.
 
Cyclocmatic complexity = Number of decision points + 1
 
The below table will explain the status of code based on Cyclomatic Complexity,

 Cyclomatic Complexity  Status of Code
 1-10  Normal
 11-20  Moderate
 21-50  Risky
 >50  Unstable

Branching Over Type

Branching might be good for normal cases but it is not good over type. Basically those codes which have branching in some types or variables of a certain type will be considered as a code smell because branching of a certain type has the possibility of numerous checks scattered around the codes and it makes maintenance very difficult. 
 
Below branching is a type of branching that is code smell,
  1. public void Drive(Vehicle vehicle)  
  2. {  
  3.   
  4.     if (vehicle.Type == "Car")  
  5.         Drive(vehicle);  
  6.     else if (vehicle.Type == "Aeroplane")  
  7.         Fly(vehicle);  
  8.     else if(vehicle.Type == "Train")  
  9.        Rail(vehicle);  
  10.     else  
  11.         Sail(vehicle);  
  12. }  
The above code has no abstraction and is very difficult to test. And it is very difficult for maintenance.  
 
Solution
 
The solution for this type of "Type Branching" is Polymorphism. It brings the branching decision closer to the root of the main code as much as possible. It makes the code very easy to test and maintain.
 
Below is  the refactored code of the above branching code,
  1. public interface IVehicle  
  2. {  
  3.     void RunVehicle();  
  4. }  
Now, its context class,
  1. public class VehicleContext  
  2. {  
  3.      private IVehicle _iVehicle;  
  4.   
  5.      public VehicleContext(IVehicle ivehicle)  
  6.        {  
  7.   
  8.            _iVehicle = vehicle;  
  9.        }  
  10.   
  11.     public void RunVehicle()  
  12.    {  
  13.         _iVehicle.RunVehicle();  
  14.    }   
  15. }  
Concrete classes for each vehicle that will implement interface like below,
  1. public Bus : IVehicle  
  2. {  
  3.     public void RunVehicle()  
  4.      {  
  5.          //Implementation  
  6.      }  
  7. }  
  8.    
  9. public Aeroplane: IVehicle  
  10. {  
  11.     public void RunVehicle()  
  12.      {  
  13.          //Implementation  
  14.      }  
  15. }  
  16.    
Execution of above cases,
  1. var vehicleContext = new VehicleContext(new Bus());  
  2. vehicleContext.RunVehicle();  
How is this code very easy for the unit test?
 
This code will be very easy for the unit test because now it is following abstraction with loose coupling. Now, the interface can be mocked. See the below code,
  1. var iVehicleMock = new Mock<IVehicle>();  
  2.   
  3. //Run the client method  
  4. Bus busObj = new Bus();  
  5. busObj .RunVehicle(iVehicleMock .Object);  
  6.   
  7. // verify  
  8. iVehicleMock.Verify(m => m.RunVehicle(), Times.Once());  

Conclusion

Branching over type in the code is a code smell. Polymorphism can avoid this smell. Hence, conditional or branching code should be refactored with polymorphism behavior because it makes the code more readable, maintainable and easier to write unit tests.


Similar Articles