I’m impressed with the amount of work that you put in this article.
Rafał Zelek

Thank you very much :-) To answer your questions

  1. Yes, email notification is probably the right thing to do. I haven’t written it yet though. My plan is to save it for the next parts where I'll be tackling compositions of algebras and free applicatives (for concurrency)
  2. When you have many actions the good thing to do is to move things like type ProgramEx[A] = EitherT[Program, Error, A] to a separate trait, let’s call it FreeOps , and hide it there. Its actually pretty easy to write it generically once and reuse. Will it help?
  3. I believe that Free helps to keep the code organized (you’re separating logic from interpretation) and testable. In “Functional and Reactive Domain Modelling” by Debasish Ghosh you’ll find similar approach (chapter 5), so I take it as an evidence that it is not completely nuts :-)
  4. Well, I am strong believer in constant learning. If your team members do not get it, then you should walk the extra mile — educate them and help them to be comfortable with the solution. In my company we’ve had people who are comfortable with Free and other “advanced” FP stuff, and others who were not. So we eg. organized talks about this approach to spread the knowledge.
  5. Yes :-) I answered this partly in 3. I really recommend reading “Functional and Reactive …”, the author can probably explain it 100x better than me :-) To quote it:
Here are some of the major advantages that this pattern gives to your model:
Modularity and Testability. You can modularize your application based on free
monads. The algebra can be decoupled from the actual interpretation in a much
stronger way than many other design options. And with modularity you get the
flexibility to swap out implementations and replace with alternate ones. This is a great
advantage when you can plug in mock implementations for testing while go back to the
real one in the production environment. So free monads subsume patterns like
dependency injection.
Purity. We could keep things pure and algebraic even when we composed the whole
structure of the DSL. The free monad gave us the whole abstract syntax tree, much like
we would get from Lisp macros. And the whole thing is typed and checked during
compile time. So you have the structure that you can reuse in other context and reason
about mathematically. The separation between the algebra and the interpretation is
much more explicit.
Scalability. In Scala, which does not support generic tail calls, the free monad
implementation lets you scale your DSL to arbitrary levels of complexity without the
fear of blowing your stack. The scalaz.Free implementation uses trampolining that
trades heap space for stack [3].

And I can add from my perspective:

  • I do not have any mock library whatsoever in my project, I mock everything I need by swapping interpreters. I can have real unit tests without setting up db or complex dependency chains :-)
  • I can wrap the whole thing up with some kind of effect eg. WriterT for logging and I can have event-sourcing without even changing the signatures of my services (and they are completely oblivious to what’s happening)
  • Because you’re thinking in DSL terms, it’s quite hard to write “God-like” services which do everything
  • Last but not least, I have one place where I can see the logic. That’s indispensable for me: I do not have to discover the truth by chasing myriad of interconnected things.

Hope I was able to answer you. Let me know what you think.