Writing clean Facades with Fluent API in C#

Photo by Paweł Czerwiński on Unsplash
A day in the life of Randy
Infant routine
teenage routine
  • The Facade’s job has been greatly simplified, it’s only responsible for defining the execution sequence and to then trigger the execution.
  • The ControlFlowScheduler has taken on the responsibility of executing each step and abstracts away the complexity of serial/concurrent execution. The instantiation of these collection of the steps is handled by Autofac and injected into the ControlFlowScheduler. Having this centralized execution block also presents code-reuse opportunities such as standardized exception handling, state management, tracing and logging for this kind of control flow.
  • Along with being implemented behind an interface, each step is defined in its own class, making them very specific (Single Responsibility) and decoupled from each other.
  1. IControlFlowStep
  2. IControlFlowScheduler<>
  3. IControlFlowDoer<>
  4. IControlFlowThenDoer<>
  1. IControlFlowStep is the base interface for any Step that will be executed within the facade (e.g. TheSchool). The two methods it declares, .Execute() and .ExecuteAsync() are meant to provide sync and async ways to run a step for sequential or concurrent executions respectively.
IControlFlowStep
IControlFlowScheduler
IControlFlowDoer
IControlFlowThenDoer
  • Compile time safety: Since the interfaces IControlFlowScheduler<>, IControlFlowThenDoer<> and IControlFlowDoer<> are all generic, defining an IControlFlowScheduler<IDailyTask> prevents something like a MathClass : ISchoolTask from being scheduled directly in the daily routine schedule at compile time. The compiler prevents having a Math class outside of the school schedule, strengthening the scheduler API
Compile time safety
  • Container config: It helps the DI container resolve correct types of steps needed for Daily tasks at run time. As we’ll see in a later example, we will be breaking down TheSchool : IDailyTask task into a sub-facade that masks ISchoolTask , with its own set of steps that implement the ISchoolTask interface. For e.g., TheMathClass : ISchoolTask.

Additional use cases

  • One common example is nesting: let’s consider the case of TheSchool task. Schools have their own set schedule. The TheSchool task, which is part of the daily routine, likely has multiple thing going on within it and will benefit by having its own set of sub-tasks to ensure the Single Responsibility Principle. This means that it can act as a facade itself, masking the orchestration of the various underlying school-level tasks. Let’s look at the following screenshot:
TheSchool as a sub-facade
  • Another enhancement to the scheduler may be something that addresses more complex use cases such as the one below. There may be use cases where a step needs to run in the background and the execution of a subsequent step further down the sequence needs to be blocked until that background step has completed successfully, for e.g., consider the following:
Conditional control

Grains of salt

  • This ControlFlowScheduler abstracts away the actual control flow, which means that stepping thru code in debug may involve a few extra hops or breakpoints
  • It brings simplicity and readability to the control flow, but needs to be implemented before it can be used. An ROI analysis might help if you only have one facade or if the application won’t increase in complexity, etc.. The readability this approach brings is still an advantage.
  • Needless to say, if you have one of those unusual opportunities where you literally need to save micro-seconds in run time and must write micro-optimized code, you should consider the trade-off between performance and readability.
  • This article presents an idea that can be molded to make sense for specific use cases. For example, the scheduler’s final .Execute() method can be made a part of the .Then() and .Do<>() method chain if it makes sense to put it there. Having it separate, as in this example, provides the separation/flexibility of defining once and executing later or multiple times. Smaller things like the method names .Then() and .Do<> made some sense for readability in this daily routine example, but they should be renamed to whatever makes the code more fluent and readable.

Bigger picture

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Summer Internship-Online Transport Management System

Symfony without Request

Image représentant du code source

On Operationalizing Privacy Engineering into Development Process (featuring Michelle…

WHAT IS GIT

Five Dex Alternatives for Kubernetes Authentication

CS 373 Fall 2020: Sameer Haniyur

My Tech Story From Genesis to Genesys

Rebus Vault Overview

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Saharsh Sinha

Saharsh Sinha

More from Medium

Clean Variables: Volume I

How to Add WPF UI Controls to Your Desktop Application

.NET Type Internals from a Microsoft CLR Perspective — Part 1

Unit Test Best Practices