Functional Workflow in C#

A colleague of mine called me over to his desk one day and asked me to help him refactor and clean up his code. He was working on a solution that involved the execution of various email tasks. His code worked but was quite difficult to reason about.

What we needed to do was more thoroughly decompose the problem and compose a more comprehendible solution.

In addition to decomposing the problem into smaller pieces, it was also necessary to handle errors, write the results of operations to a log, and compose multiple Task like operations together into some type of workflow.

It happened to be that during this time, I was reading Functional Programming in C# by Enrico Buonanno. Being already very excited about what I had read and learned from Enrico’s book, this seemed to be the perfect opportunity to put some of it into practice.

I’ve put together a demo that demonstrates some of what we implemented into our solution.  If you are at a minimum comfortable using C# and LINQ, I think you’ll be able to follow and understand the code.  There may be a few constructs you aren’t familiar with, such as the Either type, but I think you’ll understand what it does when you see it in context.

To better understand the demo and how it’s put together, you may want to study it from the bottom-up so to speak in the following order.

  1. Tasks.Runner
  2. Tasks.Services
  3. Persistence.Services
  4. Logging.Models
  5. Logging.Services
  6. Domain.Models
  7. Domain.Interfaces
  8. Common.Services

The benefits of employing functional programming in my solutions have been numerous. After putting together this solution, two key things stuck out to me:

  1. FP has built-in constructs for composing functions together to create a workflow.
  2. FP has built-in types for handling errors such as the Either type without the need to throw exceptions.

If you would like to know more about Functional programming, I highly recommend you pick up a copy of Enrico’s book. It’s one of the best I’ve read on the subject. In addition to this, check out the C# Language Ext library.

Reflection: The solution my colleague was working on is a “small” and non-mission-critical application. This being the case, it represented a low-risk way to try out a more functional approach to solving problems.

Reflection: The demo is a bit contrived because it wouldn’t make much sense to download emails and attachments separately.  It does however, I think demonstrate how you can compose multiple tasks together with a functional workflow.

Reflection: I debated using delegates, interfaces, or funcs for dependency injection. I ultimately settled on delegate instead of func because it could be declared once. I chose delegates over Interfaces so that I could just call a function instead of InterfaceName.Function.

Reflection: I considered putting CreateFolder inside the save method of the Attachment and Mail repository as I did with PathReader.Read, but part of the reason for creating the demo was to allow me to experiment with a more functional workflow and compose operations together via Map and Bind with the Either type.

Reflection: I considered making this demo part of a larger solution. I was particularly concerned about the Domain and how people might misunderstand or misuse what is illustrated in the demo in their own solution. For the demo, the domain is the Eagetmail Mail and Attachment classes, as well as the classes defined in the Domain layer. In a larger solution, these wouldn’t necessarily be the domain, that solution may have another domain problem it’s trying to solve. Here’s an example of how the demo projects might appear in a larger solution.

  • Presentation
    • YourSolution.Presentation.Site
  • Application
    • YourSolution.Application.Models
    • YourSolution.Application.Services
  • Domain
    • YourSolution.Domain.Models
    • YourSolution.Domain.Interfaces
    • YourSolution.Domain.Services
  • Infrastructure
    • Persistence
      • YourSolution.Infrastructure.Persistence.Services
    • Email
      • YourSolution.Infrastructure.Email.Models
      • YourSolution.Infrastructure.Email.Interfaces
      • YourSolution.Infrastructure.Email.Services
    • Tasks
      • YourSolution.Infrastructure.Tasks.Services
      • YourSolution.Infrastructure.Tasks.Runner
    • Logging
      • YourSolution.Infrastructure.Logging.Models
      • YourSolution.Infrastructure.Logging.Services
  • Tests
    • YourSolution…

Disclaimer: The code sample should be considered a toy whose purpose is primarily pedagogical. I endeavor to make code samples just real enough to be interesting but not so complex that they overwhelm.

Note: You will need to change the mail server settings in App.config and perhaps the IsIncluded predicate in the domain to run the program without receiving errors.

Functional Origami

I just released a FREE course on Udemy titled Functional Programming with Origami. The course utilizes Origami and C# to teach elemental constructs of Functional Programming.

A description of the course is given below. You can enroll in the course by clicking here. You can download the source code for this course by clicking here.

  • I took my inspiration for creating this course by remembering how one learns as a child. Whether it was learning to count on your fingers or the realization of symmetry, one comes to by building things with toy blocks.
  • The origami examples in this course are designed to help you understand what is being demonstrated via the code examples both visually and tactilely.
  • There are many code examples in this course written in C#, with each module’s examples building on the previous.
  • The core of this course centers around the types List, Option, and Either; you’ll learn what these types model and how they add an “effect” to other types.
  • The functions Return, Map and Bind are demonstrated in numerous code examples, and you’ll see how they can be “composed” and used together.
  • You’ll learn the difference between Total and Partial Functions and how to turn Partial Functions into Total Functions.
  • At the crescendo of this course, the “patterns” Functor and Monad are unveiled and explained in simple and easy-to-understand terms.
  • Toward the end of the course, you’ll be given links to several resources to help you continue your functional programming journey.