SOLID, CQRS and functional dependency injection

Posted on Updated on

I was prompted to write this after reading Mark Seemann’s post (http://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/)

From http://kozmic.net/2012/10/23/ioc-container-solves-a-problem-you-might-not-have-but-its-a-nice-problem-to-have/:

Fol­low­ing Sin­gle Respon­si­bil­ity Prin­ci­ple will lead you down the road of hav­ing plenty of small classes.

Open Close Prin­ci­ple will lead you down the way of encap­su­lat­ing the core logic of each type in it, and then del­e­gat­ing all other work to its depen­den­cies, caus­ing most of those small classes to have mul­ti­ple dependencies.

Inter­face Seg­re­ga­tion Prin­ci­ple will cause you to abstract most of those big num­ber of classes by expos­ing an inter­face or an abstract class, fur­ther mul­ti­ply­ing the num­ber of types in your application.

Liskov Sub­sti­tu­tion Prin­ci­ple will force you to clearly shape your abstrac­tions so that they can be used in a uni­form way.

If you pursue the single responsibility principle to its conclusion then you end up with CQRS. What are commands and queries if not functions? Sure, they’re wrapped up in classes with abstractions, but that’s only because most languages (I’m looking at you, C#) require it.

Example:

public class Customer
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

public interface IGetCustomerQuery
{
    Customer Execute(Guid customerId);
}

public class GetCustomerQuery : IGetCustomerQuery
{
    private readonly IEnumerable<Customer> _allCustomers;
    
    public GetCustomerQuery(IEnumerable<Customer> allCustomers)
    {
        _allCustomers = allCustomers;
    }
    
    public Customer Execute(Guid customerId)
    {
        return _allCustomers.Single (x => x.Id == customerId);
    }
}

public class Client
{
    private readonly IGetCustomerQuery _getCustomerQuery;
    
    public Client(IGetCustomerQuery getCustomerQuery)
    {
        _getCustomerQuery = getCustomerQuery;
    }
    
    public Object Index(Guid customerId)
    {
        var customer = _getCustomerQuery.Execute(customerId);
        
        return View(customer);
    }
}

Here is the same domain in F#:

type Customer = {
    Id: Guid
    Name: string
}

type GetCustomerQuery = Guid -> Customer

let GetCustomer allCustomers customerId =
    _allCustomers.Single(fun x -> x.Id = customerId)

type Client(getCustomer: GetCustomerQuery) =
    member this.Index customerId =
        customerId
        |> getCustomer
        |> View

Instead of having a class to represent the “get customer” query, we simply define a standalone function. The type “IGetCustomerQuery” has changed to “GetCustomerQuery” and gone from an interface to a type alias, just to be a little clearer. What about the dependencies that the query had before in C#? They have moved from the class onto the function along with the other arguments to the function. But before we had a function that just took a customerId; now we have a function that requires a sequence of customers *and* a customerId. That’s where F#’s partial application comes in; you’ll see here how it becomes relevant to dependency injection and how functional programming really is an alternative to OO. If you look at the signature of GetCustomerQuery it’s “Customer seq -> Guid -> Customer”. Explanation: that’s “a function that takes a sequence of Customers and returns a function that takes a Guid and returns a Customer”. Since we created the type alias IGetCustomerQuery = Guid -> Customer, we could also write that signature as “Customer seq -> IGetCustomerQuery”. Now it’s a bit more obvious what we need to do: calling GetCustomerQuery with a sequence of Customers will return an IGetCustomerQuery. So, in order to instantiate the controller, we just need to write:

let allCustomers = ... // Get the customers from somewhere
let getCustomer = GetCustomerQuery allCustomers
let controller = Client (getCustomer)

Finally, if you fol­low Depen­dency Inver­sion Prin­ci­ple your types will not only expose abstrac­tions them­selves, but also depend on abstrac­tions rather than con­crete types.

One thought on “SOLID, CQRS and functional dependency injection

    dineshramitc said:
    2014-08-19 at 13:52

    Reblogged this on Dinesh Ram Kali..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s