A bit over a year ago we started a rewrite of one of the core functionalities of our system. I was really tempted to use F# for that, but the other team members were not so sure. We've agreed upon sticking with C# but use more functional and railway-oriented programming inspired approach. This forced us to come up with a way to do it. We could stick with some of the existing libraries available (like language-ext, which one of our teams was already using) or try to implement it by ourselves. As you may guess, we have taken the latter path and it led us to the successful delivery of multiple projects using this approach.
As the code we shared between the projects was pretty simple yet very useful, we wanted to share it with other developers outside of our organization. It wasn't so easy as it seems to be, unfortunately, but finally, after many hours spent on recreating things from scratch, I made it available publicly on GitHub.
What is Monacs?
It's intended to be a simple and lightweight way to introduce some bits of functional and railway-oriented programming to the C# projects. Currently, you'll find two core monads inside the library:
Result. Both of the types are complimented by a set of extension methods, including constructors,
Map. It allows you to write code in more railway-oriented style, as in this example:
public async Task<Result<Cart>> GetCart(CartRequest request) => await Validator.Validate(request) .Map(RequestMapper.ToDomain) .BindAsync(_getCartContext.Create) .BindAsync(BusinessValidator.Validate) .MapAsync(_operation.Execute) .BindAsync(cart => _storage.Persist(cart)) .DoWhenErrorAsync(_logger.Error);
I've done a few presentations about this approach (here is recording in Polish) and also wrote about it earlier. It basically allows you to reduce the noise and helps to flatten the structure of class dependencies, leading to easier reasoning about the code and its goal. Head to the docs for some more details.
What's the status?
The current library version is 0.1, which means it's still in development and APIs are subject to change. The core functionality shouldn't change much though and I expect to only add functionalities in the upcoming releases, so the risk of using it shouldn't be that high ;). It's also covered by quite a few unit tests so hopefully, the quality shouldn't disappoint. Documentation is in progress, I hope to get nice documentation of the API for next release with the help of contributors.
How can I use it?
The plans for the future development include:
Unittype and related methods to make your code more consistent;
- documentation updates mentioned earlier;
- sample project to demonstrate the capabilities;
- more extension methods, e.g. to integrate nicely with
- possibly some other monads (
Either?) - I'm open for proposals here.
How can I help?
Start using it and give me some feedback! I also accept contributions like pull requests, documentation updates, bug reports and so on. GitHub page of the Monacs library will be always happy to see you :).
If you have any questions or comments, feel free to ask here, on Twitter or using GitHub issues. I hope this library will help some of the developers create better software. Thanks for coming in, and enjoy!