Flow: A Pragmatic Approach to Composable Business Logic in C#

Engineered Composable Flows (approx. 200 BCE) - Khuzestan, Iran
Engineered Composable Flows (approx. 200 BCE) - Khuzestan, Iran

I've been a software engineer for a long time, but only recently, after reading the book Effect Oriented Programming, did the true benefits of functional programming fully click for me: the beauty of composition, the containment of side effects, and the decoupling of intent from execution.

This realisation led me to look at a large C# codebase I was working on, a critical service at EarnIn, and see a clear opportunity to apply these ideas.

And so began a journey that led to the creation of Flow.

The Pain: When Best Practices Weren't Enough

The service I was working on was well-designed and comprehensively covered by resilience patterns like retries and timeouts, along with extensive logging and metrics.

But I noticed that the code was not readily understandable for our AI assistants (our "genies") to grasp. The path of data and execution was not always obvious to follow, which made it difficult for them to contribute effectively.

My first instinct was to refactor using bread-and-butter OOP design patterns like builders and adapters. But it felt like I was only scratching the surface.

The real challenge was that, to be able to abstract over repeated patterns, I needed to separate the business logic and cross-cutting concerns (resilience, logging, metrics, error handling). And, as you may have guessed, I simply could not do that.

I even tried implementing my own bespoke versions of Option, Either, and Try, and added Polly to the mix to handle the resilience patterns.

But the code was still far from DRY.

I couldn't compose the pieces without constantly wrapping and unwrapping values and enclosing everything in try-catch and if-else blocks.

The "Aha!" Moment

After one too many failed attempts, a thought hit me like a freight train: WHAT IF I was attacking the problem from the wrong angle? What if, instead of trying to wrangle side effects, I should have been using a C#-friendly effect system to compose them cleanly?

I, obviously, did a thorough search but couldn't find a library that could strike the right balance of power and pragmatism for a busy programmer. That was when Flow was born.

Introducing Flow v1.0.0 🎉

Today I'm absolutely stoked to announce the 1.0.0 release of Flow, the open-source .NET library that lets you:

  • Build clean, composable, and extensible business logic pipelines.
  • Define your operations as declarative, reusable 'recipes'.
  • Get the benefits of an effect system without having to learn a new paradigm.

Why Flow, and Why Now?

The timing for Flow feels right, for a few key reasons:

  • The C# language has evolved beautifully, with features that are great for writing expressive libraries.
  • The async/await model is now incredibly reliable and mature.
  • 🧞‍♂️ Most importantly, the rise of genies (a.k.a. LLMs, Agents, GenAI, AI Assistants) has made the clarity of our code more critical than ever.

In my experience, the cleaner and more declarative the codebase, the more predictable and effective the genie becomes.

They'd require less handholding, produce higher-quality code, and, crucially, the code they write is far easier for us to review.

Flow is designed to create the kind of clean, declarative structure that turns your genie into a (usually 😅) helpful collaborator.

Dive In and Explore

This is just the first step for Flow. The vision is to continue polishing its behaviours, extend its testing support, and simplify its interaction with external systems.

But for now, the API is solid, and it’s ready to be put to the test.

I hope you take some time to explore Flow and see how it might help you tame the complexity in your own projects.

Flow was born from a real-world struggle to write better, cleaner, and more maintainable code. I’m incredibly excited to share it with you, and I look forward to hearing your thoughts.

Comments