I want desperately to start moving a legacy C# codebase to F#. The problem is that I'm currently the only one that understands the C# codebase, other developers on the project struggle to understand the JS front-end, and flail on contact with the back-end. I'm at severe risk of making myself an Expert Beginner indispensable piece, but I don't know how to move forward with what I have to work with.
Based on what you’re saying, adding greater understanding to the current codebase is problem #1, which you’ll need to solve before going to F#. Language migrations require two things, at minimum:
[1] A really firm understanding of the business logic the code is performing (which can really be simplified to, do you have a deep understanding of “the business”)
[2] An understanding of the edge cases.
#2 is often only captured in the code, and these regressions end up being the thing that cause lots of bumps along the way with business teams. Knowledge gets lost so easily, or silo’d in distant parts of the business, that the code really becomes the “living history” of the business.
I don’t have a lot of good solutions for you. Migrating languages is tough business, but I’d potentially think about starting a “lunch and learn” with some colleagues to do high level code walkthroughs. This could help to distribute knowledge, and build a better understanding of what you already have. The process of prepping can help you to also document what it might take to do the migration, so you can better make the case to any superiors you need to get buy in from.
My own migration of a 7+ years C# codebase to F# (in 2013) began when I decided, belatedly, that I'm just not smart enough to pair a deep OO hierarchy with multicore parallelism without having my vacations spoiled with troubleshooting. The first thing I did was take a tiny part of the code, read the C# data into F# records and used F#'s Array.Parallel.map for the multicore crunching. Like magic, the intermittent threading bugs I had with that small part disappeared, so I kept going. I hadn't planned to rewrite everything in F#, but I had so much fun with it, and grew to love the language so much, that 18 months later, that's what had happened.
I'd recommend starting by nibbling around the edges: find small pain points where F#'s union types, immutability, pattern-matching, option types, active patterns, etc, make some small part of the software easier to understand and maintain. And then if you like how that goes, don't stop.
In the spirit of leveraging the type system, you could try doing some type-first development. If possible, carve a logical module or sub-system out of your existing code base and then attempt to represent the data and functions for that module in F# types. Don't implement any of the functions, just see if you can describe the data and operations using the type system. Tomas Petricek describes this approach really nicely in his post "Why type first development matters".
This has a the following benefits:
- It helps you review and clarify what the existing code does.
- It will force you to name the data and operations explicitly.
- You won't be distracted by actually implementing the operations.
- You have a succinct description of the module that you can discuss with other developers.
- It divides the migration into manageable chunks.
You could challenge yourself to educate team members, through the type system.
You may also find some of the techniques from the book "Working Effectively with Legacy Code" useful.
Updated: Removed links as comment was not posting.