This context provides a guide on how to refactor a null checking condition with object composition in TypeScript, using the Introduce Special Case pattern to improve code stability and maintainability.
Abstract
The context discusses the common occurrence of null checking conditions in TypeScript and Angular, highlighting the importance of refactoring these conditions to comply with the DRY (Don't Repeat Yourself) principle. It introduces the concept of a Special Case object, which can handle redundant null checking conditions by separating the common behavior to a single place. The context also explains the problem with null checking conditions, the power of object composition, and the benefits of using the Introduce Special Case pattern. It provides code examples and UML diagrams to illustrate the refactoring process.
Bullet points
The context discusses the common occurrence of null checking conditions in TypeScript and Angular.
It highlights the importance of refactoring these conditions to comply with the DRY principle.
The context introduces the concept of a Special Case object, which can handle redundant null checking conditions.
It explains the problem with null checking conditions, including the maintenance effort required to modify or extend the assignment of attributes.
The context discusses the power of object composition and the benefits of using the Introduce Special Case pattern.
It provides code examples and UML diagrams to illustrate the refactoring process.
The context concludes by summarizing the benefits of using the Special Case pattern, including compliance with the Open-Closed Principle.
How to Refactor a Null Checking Condition With Object Composition in TypeScript
Using the Introduce Special Case pattern to refactor a null checking condition
Early in my career, the most commonly occurring condition in TypeScript and Angular was the null checking condition. I think other developers have the same habit of making their code more stable. Such a condition isn’t bad, but when we check the same special value every time in different places in our code, we may have redundant code and we may not be complying with the DRYprinciple.
It is helpful to implement a Special Case object to handle such conditions when most or all of them have the same reaction to the particular value. We could separate that reaction to a single place.
In TypeScript, there are two different innate null checking conditions (and maybe more). One checks for null, while the other one checks for null and undefined:
There are some JavaScript helper libraries like lodashthat we can use to shorten the conditions:
“[…] this is the Special Case pattern where I create a special-case element that captures all the common behaviour. This allows me to replace most of the special-case checks with simple calls. […] If I need more behaviour than simple values, I can create a special object with methods for all the common behaviour. […]” — Martin Fowler, Refactoring
In simple words, regarding the null checking condition, we create a special object for the cases when a value or an object can be null so that a default class with common behaviour will be returned.
If we like object composition and our code is architected by many classes and interfaces, we will love this pattern.
The Problem With Null Checking Conditions
Firstly, we need to comb our code or rather related object families for null checking conditions. After that, we need to scan these conditions for the same reactions. If it shows the same behaviour, we are lucky and we can use the Introduce Special Case pattern for this.
In the following example, we can see how I handle null in the same way but with different context data in the else-sector. But the content is the same — there is no data:
There could be more places with no-weather-checks in the code base.
In my example, I need to implement only three attributes: title, state, and temperature. So if we have many places where a check against null is required and we need to assign many attributes with special values, this maintenance effort to change the code could be very high.
In summary, this approach is not DRY and the maintenance effort is draining when we need to modify or extend the assignment of the attributes.
Modules that contain null checking conditions.
The Power of Object Composition
In many cases, we have classes, interfaces, or other modules to represent a business case. In the example above, we have a weather class or a weather interface and fill the weather object with user-readable data to explain that there is or is no data.
Code against interfaces
So we have got nice class architecture conditions to use a Special Case object to refactor and to remove repeated null checking conditions by expanding the model with a No-Weather-Data class (or Null-Weather-Data class). I explicitly wrote “expand”because we’re complying with the Open-Closed-Principle. If there is not a nice class architecture, we need to refactor our code to be more polymorphic. Refactoring by Martin Fowler is an instructive book that shows we how to accomplish this.
UML to refactor a null checking condition
In this case, we do not need to modify the data of the WeatherData object at runtime and we can make the attributes immutable.
Expanded with immutable data
In the NullWeatherData class, we can assign fixed values for the attributes (e.g. Unknown or Unknown weather as the title). Whenever we need to change these values in the future, we will change them in one place only: inside the NullWeatherData class. We will no longer need to comb the entire code base:
Now we carry on and look at the code base to see if we can replace the previous return data logic inside the service (or in other places) with the polymorphic behaviour:
Wherever we request a weather object, we need to make sure to check the data before returning an object.
We comply with the Open-Closed-Principle with a simple null object,which is a special case of the Special Case pattern. We have got only one place where the NullWeatherData is created and maintained. Its only responsibility is to return the context that there is no weather data and show this to the user. That is all.
Conclusion
With the Special Case pattern, especially the null object pattern in this example, we can refactor null checking conditions to comply with the Open-Closed-Principle.
Thanks for reading! Follow me on Medium, or Twitter, or subscribe here on Medium to read more about DevOps, Agile & Development Principles, Angular, and other useful stuff. Happy Coding! :)