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.
- private int GreaterNumber(int first, int second)
- {
- return (first > second) ? first : second;
- }
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,
- public void Drive(Vehicle vehicle)
- {
- if (vehicle.Type == "Car")
- Drive(vehicle);
- else if (vehicle.Type == "Aeroplane")
- Fly(vehicle);
- else if(vehicle.Type == "Train")
- Rail(vehicle);
- else
- Sail(vehicle);
- }
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,
- public interface IVehicle
- {
- void RunVehicle();
- }
- public class VehicleContext
- {
- private IVehicle _iVehicle;
- public VehicleContext(IVehicle ivehicle)
- {
- _iVehicle = vehicle;
- }
- public void RunVehicle()
- {
- _iVehicle.RunVehicle();
- }
- }
- public Bus : IVehicle
- {
- public void RunVehicle()
- {
- //Implementation
- }
- }
- public Aeroplane: IVehicle
- {
- public void RunVehicle()
- {
- //Implementation
- }
- }
- var vehicleContext = new VehicleContext(new Bus());
- vehicleContext.RunVehicle();
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,
- var iVehicleMock = new Mock<IVehicle>();
- //Run the client method
- Bus busObj = new Bus();
- busObj .RunVehicle(iVehicleMock .Object);
- // verify
- 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.
Join the conversation! Your thoughts help the community grow.