This post is part of the F# Advent Calendar 2022 hosted by Sergey Tihon. The goal of this post is to provide a glimpse into the journey of two C# developers (myself and Sean G. Wright) who are learning F# together and to provide some insight into the motivations and resources that helped them along the way. We hope this post will be helpful to other developers who are interested in learning F#. All answers are opinions from the perspective of our individual experiences thus far in our F# learning journey. Please excuse our ignorance as we continue to learn!
What’s your background as a software developer?
I’ve been a .NET developer for nearly a decade building mostly cloud-native solutions with extensive experience working in Azure. I’ve helped develop and maintain a wide range of legacy and greenfield projects from ETL pipelines in VB.NET, scalable microservices with Azure Function’s Durable Orchestrations, and quite a few modern ASP.NET applications in .NET 6. I’ve spent time working with TypeScript using frameworks like Angular and Vue and continue to dabble in those ecosystems occasionally. Nowadays I am a part of a great team at a small consulting company called NimblePros, where I am a proponent of clean architecture, domain-driven design, and test-driven development. My day-to-day programming is primarily done in C#, often while pairing programming whenever possible. I still consider myself to be a novice F# enthusiast with an understanding of the basics like syntax but lacking an understanding of more advanced language features.
What interested you about F#?
I was briefly exposed to functional programming while in college studying computer science but the paradigm didn’t catch my interest until I started building event-driven systems in .NET with patterns like asynchronous messaging and CQRS. Throughout the same period, C# began adding functional features to the language under the guidance of Mads Torgersen so I decided to read Functional Programming in C# by Enrico Buonanno. This opened my eyes to the possibility of functional programming in C# and I was intrigued to explore this topic further.
In early 2020, Sean and I began collaborating on a side project of mine called Payroll-Processor which became a playground (or smorgasbord as we eventually called it) for us to try out any patterns or frameworks we were interested in at the time. Sean embraced using LanguageExt to create railway-oriented APIEndpoints which I found to be really enjoyable to work with. There were times when C# felt difficult to work with and we felt like making the jump to F# but never committed to it due to us both exploring other patterns and frameworks at that time.
Then in 2021, F# began to appear more and more on my radar as a language I should try learning. The primary reason F# was of particular interest to me over other languages with functional features like Clojure or TypeScript is because of the .NET ecosystem. I was already familiar with .NET and wanted to continue working with it as opposed to learning a new framework and a new language at the same time. The F# snippets I had seen on Twitter and blogs also looked very clean and readable, which was a big plus for me. It seemed to have a lot of different patterns that would force a change in my mindset and I was hoping this would improve not just my F# skills, but also my C# understanding as well. As I am learning F# now, it feels like a natural progression for me as my journey with C# and .NET has matured and I should continue to explore F# as a complementary tool in my .NET toolkit.
As a novice software developer, using C# and learning object-oriented concepts, I had the impression that F# was for “math stuff” and must be similar to MATLAB or Scheme (which I used while in school). No one I knew used F# and most of my peers didn’t even know of or talk about functional programming.
Over the past several years I started looking more at F#, watching DevOwl and Scott Wlaschin videos on YouTube, and trying to understand why F# might be a more ergonomic fit with the functional patterns I’d been exploring. I eventually realized its type system and functional-first (but still multi-paradigm) design had lots of things to teach me and decided to try to learn it in earnest.
What kinds of resources did you use as an F# beginner to help you learn the language?
I have mostly been consuming books and watching a few PluralSight courses. I think my first dedicated F# resource that I watched was A Functional Architecture in F# by Mark Seemann on Pluralsight a few years ago. This course is a great demonstration of building a web application with real-time messaging in F#. Next, I was curious to read Domain Modeling Made Functional by Scott Wlaschin. As someone who regularly practices domain-driven design, this book was a great introduction to how F# could be used alongside these principles to create a rich, expressive, and maintainable domain model.
Currently, I am reading Get Programming With F# while patiently waiting on the MEAP version of F# In Action by Isaac Abraham. One thing I might have done differently looking back was to read Get Programming With F# before Domain Modeling Made Functional, as it would have given me a better understanding of the language and its syntax before diving into the more advanced concepts like higher-order functions, monads, and function composition. Domain Modeling Made Functional was a great resource and since F# is fairly readable most of the time, I was able to get a decent understanding of the concepts and examples in the book. However, I think it would have been easier to understand the concepts if I had a better understanding of the language and its syntax beforehand.
Initially, I focused on functional concepts, like the aforementioned monads and higher order functions, because I could learn these and use them in F#, C#, and TypeScript. I picked up a lot of these concepts from F# for Fun and Profit, one of the definitive sources on the web for F#.
But concepts only got me so far when my goal was to write real programs in F#. I felt I needed to learn the syntax and some of the development workflow (like F# interactive and how to debug in F#) since I relied on that kind of stuff heavily with C#. I purchased the first edition of Get Programming with F# by Isaac Abraham and started coding along with it while on flights to conferences. It’s a great book, starts at the ground level, and ramps up rather quickly with exercises and problem-solving.
What I ended up realizing though is that there wasn’t a single resource that helped me begin to learn F# and my focus on “this one tool will teach me everything” wasn’t tangible. I kept getting stuck and feeling like I wasn’t learning in an environment that I connected with - web development.
The key that really helped me feel more confident and learn faster was starting the FShopOnWeb project with Kyle. This project had an existing reference implementation in C# (so we could verify functionality) and was a web application, which felt more familiar to me than console apps.
I started reading F# source code on GitHub, reading the Microsoft F# docs, and working in a “solve the next problem” development cycle where I’d figure out how to do one thing to solve my current blocker, and then solve the next thing and the next. Often the problems were completely unrelated in syntax or patterns and this helped me explore F# more naturally.
What did you not use that you typically do?
I’ve watched less youtube content and followed fewer blogs than I typically have for C#. Part of that is my own growth and accumulation of those resources over time, but I’ve noticed there isn’t a go-to personality like Nick Chapsas or CSharpFritz in the F# community. Nick’s content is great because it appeals to junior and senior developers alike. Most of the content I’ve consumed on F# is primarily focused on established developers learning a new language. I immediately noticed a gap in new programmer resources for F# compared to the immense amount of resources available to new programmers learning C#.
In the past, I used a lot of PluralSight for both quickly learning a new programming topic and diving into a niche, but I didn’t find much F# content there.
What’s most difficult about F# coming from C#?
I’ve hit the usual hurdles one would expect when learning new tooling and a new language. The C# ecosystem benefits from a top-tier development experience inside Visual Studio. While I’ve been using Ionide inside Visual Studio Code for F# development and it’s worked out well, the two don’t have the same level of maturity and support so learning a new development workflow has been difficult. From a language perspective, F# is pretty elegant in terms of readability and it isn’t until the syntax gets verbose that I found it to be difficult to read. Although, writing it is a whole different matter! I’ve found the large number of operators available in F# (such as |> and >> vs <| and <<) to be a bit tricky to reason about and I’m still working on internalizing the composability of functions in what would be considered idiomatic F# style.
Another thing I’ve struggled with is how to structure my application and group functions in F# which is something that I rarely even think about when using C#. In C#, every method belongs to a class and if you practice SOLID or clean architecture then those decisions usually feel trivial. While in F#, I still don’t have a good feel for how to structure a large F# web application yet.
I think the most difficult thing was being very experienced with .NET and very inexperienced with F#. This created an uncanny valley in many places where I knew how to do something in C# with the .NET Base Class Library (BCL), and was able to do that thing in F# in a similar way, but didn’t know if that was the F# way to do things, or if I was going to run into issues I didn’t even know about.
One standout example was when trying to get C# and F# collection types to play well together or async in F# working with Task in C#.
C# developers don’t have this problem since calling F# libraries from C# is very rare and the BCL has always been more aligned with C# (having been written in C#).
What’s easiest about F# coming from C#?
F# syntax has great readability, can be very expressive, and lacks a lot of boilerplate like classes, brackets, and parenthesis which makes F# code easier to read and write. The ability to define custom types so that you can trust the compiler more and spend less time debugging feels very efficient from a workflow perspective. Nested functions are another language feature I’ve found rewarding when using F#. While C# has comparable features with local functions or private methods, the syntax makes a world of a difference in readability in my opinion.
While the uncanny valley of .NET made things confusing at times, it also allowed me to skip learning a lot of things I’d need to learn with a completely different language like Go or Rust. F# project files use the same MSBuild XML as C# projects, they consume libraries with project references and NuGet packages (I didn’t try to adopt Paket because that seemed like added complexity for little gain - am I missing something?), and the BCL is the same in both languages.
What is FShopOnWeb?
Kyle & Sean
FShopOnWeb is meant to be an F# implementation of the eShopOnWeb ASP.NET Core reference application. Previously, there was no community extension to F# of this project and it felt like a great place to apply the knowledge we were gaining of F#. One of its primary goals is to fill the lack of robust sample projects in the F# ecosystem and hopefully aid others in taking their F# projects from “Hello World” level applications to a production-ready state. Since it is meant to be comparable to eShopOnWeb, this is great for C# developers looking to learn F# because they can directly compare the two projects and run them side by side. We are always looking for feedback from the F# community and would be happy to accept submissions from other contributors.
Name one Wow moment while working with F#
Early on in the development of FShopOnWeb, we were discussing how to structure our code. When trying to reason about grouping functions, we were trying to reference how we typically organize code in C# but it became problematic because C# code is often organized by the purpose of the class. An example of this might be organizing entities by their aggregate root in a C# application’s domain layer. In F#, that style of organization felt out of place because “Everything is functions!”. There isn’t a direct need to apply the same principles to F# projects. I found the responses to this tweet to be really illuminating on how few issues the community has had overall with structuring projects. With FShopOnWeb, I’ve felt the organization of the project has come much more organically rather than following explicit conventions even if the outcomes have been similar.
I had heard the saying from the functional programming community that while object-oriented languages use many different language constructs and design patterns to solve problems, functional languages try to focus on functions as the primary tool. That definitely played out in my experience with F# and was a very noticeable shift from the comparably large toolset that C# offers (or requires).
Being able to use one tool to create so many features of an application was really amazing and exciting.
The nuanced outcome of this reliance on functions is that I needed to become much more skilled in how I authored and composed them. This skill doesn’t come for free - it needs to be developed over time and is very important to using F# effectively, and it is something I’m still working on and struggling with (in a good way).
What do you think of the F# developer community?
What do you think of the F# Open-Source Software (OSS) options?
I’m not sure I have a strong opinion yet on many of the open-source software options available in F# to give preference to certain projects over others. I’ve really enjoyed using Falco since it is based on ASP.NET Core for creating FShopOnWeb. I agree with Sean that it feels like the number of contributors to F# OSS is much smaller and the projects remain relatively immature compared to many of the mainstream C# projects.
At the same time, some of the projects I encountered seemed either abandoned, inactive, or unfinished. I think I’m biased having worked with C# for so long that I look for the “all-in-one” solution that has the standard features I’ll need for production scenarios, but I found many libraries had key features missing and I either couldn’t get some basic functionality to work (and the incomplete docs didn’t help) or I had to write a handful of functions on top of the library to “finish it up”. Maybe I don’t know what the key libraries are, I shouldn’t bring my C# mindset to F#, or I would have the same issues in C# but I’m much more comfortable there and don’t notice them as much.
Where do you think F# could be useful in the types of projects you work on?
I would enjoy applying what I learned in Domain Modeling Made Functional for documenting business requirements through the process of event storming utilizing F#. I am intrigued by how that book described that easily readable F# code can be useful for domain experts and developers. The idea of creating business specifications through DSLs in F# feels incredibly powerful to me.
Although it may be treasonous to say on the F# Advent Calendar, C# will likely remain my primary language for most applications that I work on for the foreseeable future. That being said, there is immense value both personally and professionally to expanding my toolkit of .NET skills and that’s something I’ve really enjoyed having the support of from NimblePros, friends like Sean, and the F# community.
I’m not exactly sure where I’d use F# in the projects I work on for my day job. My team has been writing C# for years, our clients projects are all C# for backend functionality, and there aren’t any plans to change this.
Today, I view F# as a language that expands my brain and I think that’s an important exercise for me as a software developer. Whether or not I introduce it to teams, use it in a production environment, or switch over from C# to F# full time is less important to me at the moment.
Writing in F# helps me think about problems in different ways, with new perspectives, and avoid the pitfalls of comfortable assumptions that come with working in the same language (or two) year after year.
For me, the question of using a programming language “for work” is important, but even if I don’t, it doesn’t lessen the value of learning and exploring F#.
That said, learning F# could very well help me feel much more comfortable adopting an F# library that solves a key problem in the C# applications I work on, even if my team doesn’t write our code in F#.
What is your experience working on F# Advent of Code?
Advent of Code has been a great training exercise for me to reinforce my F# knowledge and learn new tactics along the way. I’ve tried to focus on a particular language feature each day to force myself to try something I haven’t used before or am inexperienced with. When I compare my solutions to others on Sergey Tihon’s private leaderboard I feel like my submissions are C# solutions written in F# so I have a ways to go before I am truly writing F# in all its greatness. Overall, it’s been really fun and I hope to participate more next year!
I’ve never done Advent of Code before, but working with Kyle on one of the month’s problems was really interesting.
I felt as though the solution would write itself if I was using C# and in comparison F# felt slow and kind of painful, but that says more about my skills than F# as a language. When I looked online and saw solutions to the challenge in F# from folks, who were well-versed in it, I realized how awesome F# can be in knowledgeable hands - the code was extremely readable and terse, which I find can be very difficult to accomplish in other languages.
What kind of project are you excited to try next with F#?
As I mentioned before, I would really enjoy applying F# to domain-driven design and explore how patterns like aggregates and commands translate to the language. I can also see value in using F# in the event storming process while using F# as a sort of specification and ultimately implementation of that results of gathering business requirements.
For the foreseeable future, FShopOnWeb will likely be my main source for developing my F# skills and continuing to improve on my knowledge of functional principles.
I’d like to continue to explore F# in FShopOnWeb. I feel the practical nature of building a full stack web application really helps me stay motivated in working with F# and also helps me, like I mentioned earlier, organically learn the language which I’ve discovered is a good fit for me.
It’s big enough to feel real, but small enough to not get lost in. Simple enough to not require advanced techniques and also has some areas that don’t translate from C# to F# easily, which means learning more of “the F# way”.
What feature of the F# language do you really want to learn more about?
Overall, I’d like to continue to improve my overall competency in F# as a whole. I think there are functional principles like higher-order functions that I still need to develop a deeper understanding of and improve my ability to recall how those are implemented in F#. Some specifics about F# that stand out to me are operators for composing functions and becoming more familiar with F#’s built-in List operations (I see you List.Fold 😜).
I’ve dipped my toes into computation expressions with Falco, which uses them in several places, and async or Task-based F# code. So, I’d like to learn more about them as they seem to be pretty versatile and are especially useful for cross-cutting concerns (like logging).
I’m a huge fan of pattern matching in F# (and C#, more recently). It’s an amazing language feature that I notice when it’s missing in other languages. I think learning active patterns would help me grow my skills here. I’ve watched some videos about them but nothing has clicked for me yet.
Finally, I think I’d like to become more intuitive with function composition. While I’ve become accustomed to the “|>” operator and love writing function pipelines with it, I’m not at all familiar with the other function operators. I want to understand these tools better so I’m well-equipped to use the right solution for a given problem.
We want to thank Sergey Tihon for giving us the opportunity to participate in the F# advent blog event. Diving into learning and working with F# over the past several months has been challenging, exciting, and rewarding. We’ve enjoyed learning about the F# OSS ecosystem and engaging with the F# community on Twitter.
We hope this post gives new developers (especially those well versed in C#) some perspective on what F#, the language and the people behind it, can offer. We also hope the F# community finds our perspectives - a couple of C# developers trying to bridge the language gap and shed some ignorance - enlightening.
Please provide us feedback if you see things we missed, or have some thoughts or tips that other developers might find valuable. We hope this post leads to more opportunities for discussion, exploration, and self-education.