Adding key / entityId interfaces to discriminated unions in F# for use with @AkkaDotNET routing constructs like Cluster.Sharding is such a succinct way to implement a protocol docs.microsoft.com/en-us/dotnet/f…
@AkkaDotNET I'm almost done with my first set of domain state machines with my F# prototype and it's just a breeze compared to the same one I implemented in C# - I'm | | close to recommending it to some customers who have greenfield projects
Benefits of this approach, once I forced myself to learn it over the course of 4-5 2hr Twitch stream sessions:
1. Not having to worry about mutability - cuts out 80% of boilerplate code alone 2. Can make it nearly impossible to express illegal states via the type system
3. Very little third party library dependencies - validation et al is handled pretty concisely via "wrapped types" for primitives (i.e. @ScottWlaschin 's String50 and so on) 4. Decoupling functions from type declarations actually makes both more modular and re-usable
There's a lot more subtleties and nuances to learn still (i.e. active patterns) but it's amazing how easy it is to express something so robustly
Here's my implementation of that protocol in F# - I actually can't express this idea in C# very easily: "here's all of the possible commands you can receive in this protocol and by the way here's an identifier for the unique identity they should be sent to"
I could go a step further with this and try to define what possible _responses_ you can receive but I haven't gotten that far with my implementation or F# experience yet
• • •
Missing some Tweet in this thread? You can try to
force a refresh
For all of the #fsharp bits I tweeted, this is the key takeaway. I can point a new developer on my team at this block of code and say "this is the protocol" and in a separate code file we have a concise FSM that processes all of these
Difficult idea to express because many of these weaknesses are strengths taken to an extreme.
i.e. Frameworkism, building frameworks for building apps rather than just building apps, occurs when DRY gets taken to an extreme and the developer misses the point.
In other cases though, it's failure on the part of the developer to anticipate future changes to the project when they're inexpensive to implement, i.e. building an event-sourcing abstraction when you don't have customer data to preserve, which becomes a giant project later
If I have the history of state changes for my business entities preserved it creates options for the following:
1. Replaying old data with new code (simulation) 2. Creating novel features and experiences from old data (projections) 3. Reverting objects back to previous states
4. Introducing new ways of modifying business entities that can easily be reconciled along with prior ones
These are all extremely valuable and powerful future-facing tools that you will regret not having once you, inevitably, encounter a customer request that necessitates them