Let’s look at a real-world example.
Imagine having to write this chunk of imperative code to handle a simple user onboarding step.
It’s defensive, noisy, and hard to follow. The core business logic is completely obscured by try/catch blocks, logging, and metrics.
async Task<Guid> SendWelcomeAsync(int userId)
{
User? user;
try
{
user = await _users.GetAsync(userId);
}
catch (Exception ex)
{
_logger.LogError(ex, "User lookup threw for {UserId}", userId);
_metrics.Increment("emails.lookup.exceptions");
throw;
}
if (user is null)
{
_logger.LogWarning("User not found: {UserId}", userId);
_metrics.Increment("emails.lookup.not_found");
throw new NotFoundException("User");
}
// ... more try/catch blocks for templating and sending ...
}
With Flow, you can refactor that into a clean, declarative code that clearly expresses the sequence of operations.
var onboardingFlow =
Flow.Succeed(userId)
.Chain(Users.FindUserFlow)
.Validate(
user => user is not null,
_ => new NotFoundException($"{userId}"))
.Chain(user =>
user.IsVip switch {
true => Flow.Succeed(Templates.VipWelcomeEmailFor(user)),
false => Flow.Succeed(Templates.StandardWelcomeEmailFor(user))
})
.Chain(Emails.SendWelcomeEmailFlow)
.DoOnSuccess(_ =>
_metrics.Increment("emails.sent"))
.DoOnFailure(ex =>
_logger.LogError(ex, "Send failed"));
await FlowEngine.ExecuteAsync(onboardingFlow);
This Flow is made possible by a small set of composable building blocks. Here are the core components used above:
// --- 1. Starting a Flow ---
var a = Flow.Succeed(42);
var b = Flow.Create(() => GetValueFromDatabase());
// --- 2. Composing a Flow ---
var transformed = initialFlow.Select(i => i.ToString()); // T -> U
var sequenced = initialFlow.Chain(i => GetNextFlow(i)); // T -> IFlow<U>
var validated = initialFlow.Validate(i => i > 0, _ => new Exception("..."));
var logged = initialFlow.DoOnSuccess(i => Log(i));
// --- 3. Executing the Flow ---
Outcome<string> outcome = await FlowEngine.ExecuteAsync(sequenced);
Now that you’ve seen a basic Flow, let’s look at more advanced composition techniques.