Today’s goal is to share with you an example of real code containing static shared state and to refactor it.
I will use F# in my examples (as I love it) but they can be reproduced in many other languages (original code was in C#).
So let’s start with the context, the purpose of the code below is to keep an in-memory cache (Store) available to quickly access some settings.
A setting can be of any type so what is stored in “Value” is the serialized version of the real value. A type is also provided to simplify the deserialization part.
Bookers are accessing settings by key and the settings are updated in a part that will not be covered in this article, I’m focusing only on queries here.
As you can see a lot of logic was kept inside Store module:
- Checking the key existence
- Checking if the asked type match the setting type
- Deserializing the value
- Returning default value if not found or on invalid type
Also the fact that Bookers have a direct access to the Store could lead to problem in the future and also prevent your tests to run in parallel.
So let’s inject proper functions into our Booker to retrieve our settings
Looks better but the issue now is if I need settings with n types I will need to inject n functions into my booker, not so cool anymore :/
As I’m in a type safe language I need a type that can represent all the values I would like to retrieve and after having retrieved this value to cast it to the final desired type.
BookingSetting seems to be the perfect candidate to play that role but as I should handle the fact that the setting could be missing in the store I will use BookingSetting option instead.
I now only have one function to inject inside my Booker and checking the key existence and defaulting is now managed by the caller of the function.
The store has now only one goal, storing and retrieving the data.
Thank you for your time :)