SOLID, CQRS and functional dependency injection
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/)
Following Single Responsibility Principle will lead you down the road of having plenty of small classes.
Open Close Principle will lead you down the way of encapsulating the core logic of each type in it, and then delegating all other work to its dependencies, causing most of those small classes to have multiple dependencies.
Interface Segregation Principle will cause you to abstract most of those big number of classes by exposing an interface or an abstract class, further multiplying the number of types in your application.
Liskov Substitution Principle will force you to clearly shape your abstractions so that they can be used in a uniform 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 follow Dependency Inversion Principle your types will not only expose abstractions themselves, but also depend on abstractions rather than concrete types.
2014-08-19 at 13:52
Reblogged this on Dinesh Ram Kali..