Step-10 Refactoring Composition Root
This is step 10 of my blog series on Web Application Development in Fsharp using ASP.NET MVC
In the fsharp-phonecat application that we are creating as part of this series, to create the controller instances, we are using Pure DI. Though this composition root solves the problem of dependency injection, the quality of the code is not up to the mark.
In this blog post we are going to refactor this and make it shorter and more F# idiomatic.
The current state of GetControllerInstance method
It’s if full of if..else if.. else if.. else and the method is too long
As depicted in the above screenshot, the GetControllerInstance
method does the following three things for all the controller types in the application
- Checks the incoming controller type
- Creates the requested controller instance
- Returns the created controller instance
This can be refactored to a function
The function takes a type and returns an Option type of IController
Let’s do the same for an another controller creation which is little complex than this.
Here in this case to create an instance of PhoneController
we need two additional parameters, Phones sequence and anonymous id of the session.
With these functions in place, the GetControllerInstance
method would look like as below
Though the functions that have created has reduced the size of the method, it has introduced an another problem (Pyramid Of Doom) as indicated by the arrow in the screenshot.
We can get rid of this using a bind function as we did in validation step using rop.
The downside of the bind function is it’s not generic and we can’t reuse the existing bind function that we have created for doing validation.
So, going with this approach would lead to adding more code which is not in alignment with the objective of this refactoring.
What can we do ??
The answer is Active Patterns
Active Patterns allow programmers to wrap arbitrary values in a union-like data structure for easy pattern matching. For example, its possible wrap objects with an active pattern, so that you can use objects in pattern matching as easily as any other union type - F# Programming WikiBook
We are going to use Partial Active Patterns to refactor the composition root.
Creating Partial Active Patterns
Let’s start by creating a partial active pattern for HomeController
As described in the screenshot, it’s very similar to the createHomeController
function and the only difference is the addition of the Banana Clips (yellow ellipses). The _
symbol makes the active pattern partial.
The partial active patterns always returns an Option
type.
Partial active patterns support defining pattern with multiple parameters. So we can change the createPhoneController
function as below
Great! We are almost done with the refactoring. The pending step is leveraging these partial active patterns in the GetControllerInstance
method.
It’s where the beauty of pattern matching reveals!
What’s happening here?
- Based on the Active Pattern Name (
HomeController
), the control goes to the corresponding active pattern - The value we are matching (
controllerType
) passed as argument. - The value returned by the active pattern (instance of
HomeController
) is assigned to thehomeController
literal in the match expression - If none of the pattern has met the matching criteria, it executes the default match (raising the exception)
It does the same thing for the Active Patterns with multiple parameters
The only thing to note here is, the value against which we are matching is always passed as a last argument.
That’s it!!
After completing the creation of partial active patterns for all the other controller types in the application, the GetControllerInstance
would be shorter like this
Summary
Moving from C# to F#, it’s not just change in syntax! It’s much more than that. The perfect analogy for this refactoring is the classic proverb When in Rome, do as the Romans do. You can find the complete source code of this step in the phonecat github repository