Foreach and Command Query Separation

In my previous post on getting into higher order functions I wrote about how I've been using higher order functions instead of foreach loops. All of the functions defined in that article were immutable, and had no side effects aside from returning data.

In real life though, we're forced to deal with side effects all the time (logging, databases, DateTime.Now, etc).

This separation was by design and is due to an old (in our industry anyway) principal known as Command Query Separation. Command Query Separation is the fundamental idea that we should divide functions into two distinct categories:

Queries: Return a result and do not change the observable state of the system (are free of side effects). Think Select, Where, Aggregate, map, filter, reduce
Commands: Change the state of a system but do not return a value.

List.ForEach() accepts an Action<T> rather than one of the Func<T> overloads. If we think about it, that's exactly what we'd expect for a Command; a function that accepts a parameter but returns nothing.

    Enumerable.Range(1, 1000).ToList().ForEach(x => Console.WriteLine(x));

The F# equivalent is List.iter, but F# also has Seq.iter which has the same concept as List.ForEach with the main difference being Seq is actually an IEnumerable rather than a List

    seq {1 .. 1000} |> Seq.iter (fun x -> printfn "%A" x)

Keeping List.ForEach and Seq.iter from pulling double duty as a Query is actually much easier than keeping a Query from infringing on being a Command. Because these functions return void and unit respectively the only way to also have them query is to append to another list from within the delegate a la the Shopping Cart approach

I've found that I write much fewer functions that return unit in F# than I did methods that return void in C#. I suspect the biggest reason is that I'm no longer updating object members. Basically, if you aren't performing some sort of side effect (updating db, logging, updating an object's member, modifying state etc) then there's no reason to call anything returning void.

I don't mean to suggest that side effects are bad. From my experience it's very difficult to write much of an application without performing side effects. However, side effects do make your code more difficult to test (unit, automated, or otherwise) because to truly reproduce behavior the side effected state must be in exactly the same state every time. Command Query Separation is one way to segregate your side effecty code so that you know exactly where those side effects occur and can better test around them.

Related Posts

Proudly published with Ghost