August 16, 2024
Read Time: ~8 minutes
<aside> 📎 The boundaries between Object-Oriented Programming (OOP) and Functional Programming (FP) are increasingly blurring, creating exciting opportunities for developers. Languages traditionally rooted in functional paradigms are incorporating OOP patterns, while OOP languages like C# are embracing functional features. As a result, developers can leverage the strengths of both paradigms to write more efficient and maintainable code. This post delves into four functional concepts that have transformed the author's C# coding practices, highlighting how immutability, state management, and LINQ can simplify complex logic and reduce bugs in your codebase.
</aside>
The lines between OOP and Functional programming are becoming blurry— and that is a great thing for developers! Functional programming languages are adopting object oriented patterns, and object oriented languages like C# are embracing concepts that have made functional programming so powerful.
A significant amount of complexity has been abstracted away in languages like Scala and F# as they have matured, which has empowered their developer communities to distil wisdom and principles that have found their way into more object oriented languages such as C#. This has yielded enormous benefit in particular to OO developers. For example, here’s an excellent UC Davis study quantifying the reduction of bugs by using functional programming.
In this post, I’m going to share with you 4 ways functional concepts have changed my C# coding patterns for the better.
When I think of immutability, there are two categories that come to mind: Immutable Types, and Immutable Variable Assignment. The C# documentation covers Immutable Types very well, so I’ll leave those out of the scope of this blog. But if you’re keen, these include records, get-only properties, and immutable collections — I highly recommend reading up on and adopting these!
Lets focus on Immutable Variable Assignment.
Many languages provide at least one type of keyword that specifies that an assigned value can not be changed once it is set. In other words, once the variable is assigned - it becomes immutable. For example, in JS you can define const
and let
variables. const
is immutable - you cannot reassign its value. In Scala you have val
and var
.
In C#, we simply have var
. And although you can define const
assignments, these assignments must be compile-time constant - and that's not what we’re after here. We’re really talking about variables whose value cannot be changed after assignment at runtime.
At Empower, we’re doing our best to bring fair credit to everyone. This means we run a lot of experiments to see what works best for our customers. Recently we ran an experiment to determine which of our Thrive eligible customers who are also eligible for our Cash Advance product, would be most likely to actually sign up for the Cash Advance product.
Below is how I would have written the code for this before incorporating the concept of immutability daily design practice:
var showCashAdvanceBeforeThrive = false;
var cards = new List<Card>();
if (_featureFlagService.IsFeatureEnabled("ShowCashAdvanceFirst"))
{
showCashAdvanceBeforeThrive = true;
cards = dto.Cards
.OrderByDescending(x => x.CardType == CardType.CashAdvance ? 0 : 1)
.ThenBy(x=> x.CardType == CardType.Thrive ? 0 : 1)
.ToList();
} else {
cards = dto.Cards;
}
_eventService.Fire(new MarketingUserEvent(
userPublicKey,
"OnboardingOffersReturned",
new Dictionary<string, string>
{
{ nameof(showCashAdvanceBeforeThrive), showCashAdvanceBeforeThrive }
}
));
return cards;
In the above code, consider the cognitive load we’re adding to the person who comes next by reassignment of showCashAdvanceBeforeThrive
so we can fire the correct marketing Event as well as cards
based on the feature flag / ordering.