We're an F#-first company and I'd like to share our experience here.
All our new code is in F#, we started off from a C# codebase, so that made the transition somewhat manageable, as new F# code can be directly called from C#, and vice versa (still took over 2 years). All new frontend apps are also being written in F# (using Fable), as of 6 months back, migrating away from TypeScript, this forces everyone into a "design your model first, and well" paradigm. We've written quite a bit of code to blur the lines between traditional backend and frontend development roles, so what we have now are:
- product engineers (who write application logic on both frontend and backend to serve business needs)
Platform/framework engineers try to encapsulate as much magic as possible into computation expressions (F#'s monads), so product engineers can focus simply on writing out business intent, with readability given very high priority. We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).
Our code written in F# has an order of magnitude fewer bugs when it makes it to production, given the amount of thought we pour in modelling the problem domain accurately, and thanks to functional programming itself. They're also more amenable to business requirements changing, simply because they've been modelled well to start with. Nothing that can't be achieved in other languages, but with F#, this happens more naturally.
Almost everyone in our team has learnt F# on the job, and overall, everyone's experience has been extremely positive. There's a bit of difficulty in the first 2-3 months, as junior devs get introduced to functional thinking, but if you've generally being doing functional programming, this is just about learning new syntax, tooling and F#'s choice of operator naming (map/bind/pick/collect/choose/..). Typically, based on prior experience, we ask newcomers to spend two weeks to a month, solving the first 100 problems on Project Euler in F#, without using the mutable keyword, and we assign a mentor to point out best practices and review their code.
The hiring pool for F# devs is much smaller than the regular applicant pool, but if a candidate shows genuine interest in F#, they are usually 10x more likely get through our interview process. If they've discovered F#, it means they find something lacking with mainstream languages, so they're likely to have many years of experience under their belt, and they've found a way to grow. That said, we don't restrict our hiring to simply F# devs.
For more info about us, see chaldal.tech (YC/S15).
Amazing! I’d be interested- the problem I have in the FP space is not getting the F# or Haskell experience so you have to “keep up in your spare time” and with other commitments I have to choose what to keep up with and the rarity of FP jobs means it makes more sense to say learn Redux, Sagas, that kind of stuff etc. So I think it’s good if companies like yours would take pure enthusiasm with proven knowledge of other programming languages and desire to learn F#. But I guess it depends as you may have a queue of people wanting a FP job so you can be choosy!
I find the same thing. Getting the experience can only happen in time I direct. I have scope to use F# at work but still fear that choice is not the best for the company I work for. Yes I will love the tooling and right now I'm there but it won't always be that way. They won't be able to find contractors to make changes in the future. I have to give them solutions they can run with in the future or they will be forever regretting me once I'm gone.
If you're on a .NET stack, F# is a secret sauce; its just not many have bothered to look :) Maybe discuss with your CTO and make a collective decision to invest in it by understanding what it brings to the table, and don't worry too much about the future, like having to hire F# devs. As I described above, guiding existing devs to learn F# is the equivalent of training them to think better (as PG/Eric Raymond quote, it will "make you a better programmer for the rest of your days"). If a small handful of you within the company develop expertise, you can guide others. And what's more; if you do pick up F#, many skills are transferable to other FP jobs (like Scala). There's a leap-of-faith element involved, but it has been paying us dividends.
> We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).
Here's is a simplistic example of a state machine:
let transition (state: State) (action: Action) : State option =
match (state, action) with
| (StateA, ActionA) -> Some StateB
| (StateA, ActionB) -> Some StateC
| (StateB, ActionA) -> Some StateB
| _ -> None
If you get the quoted representation of the transition function, it can be visualized as a tree data structure (like code-as-data in LISP). You can analyze that tree to understand that if current state is StateB, only ActionA can be applied on it.
Couple this with another realization: "Any sufficiently complicated model class contains an ad hoc, informally specified, bug-ridden, slow implementation of half of a state machine." (not sure where I read this quote).
This means all the entity framework/ORM crap work that we do can actually be neatly represented as transforms on a F# state machine, which suddenly makes the application more powerful if you give it this structure.
We use this technique to auto-generate admin panels.
> "Any sufficiently complicated model class contains an ad hoc, informally specified, bug-ridden, slow implementation of half of a state machine." (not sure where I read this quote).
Can’t tell you where you read it, of course, but believe it originates from Braithwaite/raganwald:
You can do similar things with other Ocaml or Lispy Langs, depending on how you want to do it. All you need is a function that returns possibleTypeTransitions for givenType(type, enclosedLexeme, type.validTransitions). A gradually typed lang sitting in top of a prototype-based blob also makes this easy to do (see typescript) in-codo.
Maybe it's my unsophisticated mind talking here, but programming in F# is pure joy.Among the languages I use only Ruby gets close to provide that feeling.
Yes :) That moment when it simply clicks, it's not something that goes away. It has certainly made my day-to-day programming work a lot sweeter, hence I can't shut up talking about it. And it's not like I write some esoteric ML or data science code, a lot of these are boring line-of-business applications, yet it is so satisfying designing those in F#.
Interop is janky. It works, but there are some gotchas that need to be worked around. It works in 95% of the cases without much mucking around, but it's not pretty, so you're better off tucking that away in some dark corner.
Can you explain the interop a bit more? I’ve been looking into an F# job. Having a functional background, the language looks nice, but I’m wondering about the ecosystem. Can you not use .Net libraries as easily as you can from C#?
Yes. Typically interop is very straightforward. You look in the api docs and copy paste.
Example here is the String doc[1]. Way down you see all the methods. Some of the methods have overloads (multiple variants). Pretty straightforward here. (E.g. `"mystring".Contains("ring")`)
Where it gets more verbose and finicky is when the API takes a C# callback. Even more complex is if it’s asynchronous so it takes a C# callback as a Task.
An example being the `.Use` method for defining server middleware.[2]
To see how it’s done, here’s a gist I found.[3] Notice how the function for requestHandler is verbosely annotated with Func<> and RequestDelegate, etc.
Luckily this isn’t the norm, most APIs are less complicated. Even so, you write a wrapper (abstraction) around that complexity and only look at your wrapper. Which is why someone in this thread said to leave them in a dark corner.
All our new code is in F#, we started off from a C# codebase, so that made the transition somewhat manageable, as new F# code can be directly called from C#, and vice versa (still took over 2 years). All new frontend apps are also being written in F# (using Fable), as of 6 months back, migrating away from TypeScript, this forces everyone into a "design your model first, and well" paradigm. We've written quite a bit of code to blur the lines between traditional backend and frontend development roles, so what we have now are:
- product engineers (who write application logic on both frontend and backend to serve business needs)
- platform & framework engineers (who write the underlying persistence/serialization/versioning/frontend-backend-sync websocket/load balancing/IDE extensions/deployment etc)
- component designers who focus on visuals
Platform/framework engineers try to encapsulate as much magic as possible into computation expressions (F#'s monads), so product engineers can focus simply on writing out business intent, with readability given very high priority. We also make ample use of quotations to do some cool tricks (like predict the future states some type can take, based on current state + available transitions).
Our code written in F# has an order of magnitude fewer bugs when it makes it to production, given the amount of thought we pour in modelling the problem domain accurately, and thanks to functional programming itself. They're also more amenable to business requirements changing, simply because they've been modelled well to start with. Nothing that can't be achieved in other languages, but with F#, this happens more naturally.
Almost everyone in our team has learnt F# on the job, and overall, everyone's experience has been extremely positive. There's a bit of difficulty in the first 2-3 months, as junior devs get introduced to functional thinking, but if you've generally being doing functional programming, this is just about learning new syntax, tooling and F#'s choice of operator naming (map/bind/pick/collect/choose/..). Typically, based on prior experience, we ask newcomers to spend two weeks to a month, solving the first 100 problems on Project Euler in F#, without using the mutable keyword, and we assign a mentor to point out best practices and review their code.
The hiring pool for F# devs is much smaller than the regular applicant pool, but if a candidate shows genuine interest in F#, they are usually 10x more likely get through our interview process. If they've discovered F#, it means they find something lacking with mainstream languages, so they're likely to have many years of experience under their belt, and they've found a way to grow. That said, we don't restrict our hiring to simply F# devs.
For more info about us, see chaldal.tech (YC/S15).