Hacker Newsnew | past | comments | ask | show | jobs | submit | danyx's commentslogin

I also like F# a lot and have used it professionally for 3 years now. I wrote down my own take on learning F# in a post "What I wish I knew when I learned F#" http://danielbachler.de/2020/12/23/what-i-wish-i-knew-when-l.... Maybe this is a helpful additional perspective for some.


This is an excellent blog post! Thanks for writing it.


Would you have if it weren’t supported by Microsoft?


Sure, we used Elm as well. But it sometimes helps in getting buy-in that MS is behind F# to some degree.


In an F# project file (and thus also in all editor support), the referenced F# source files have an order. Files can only see types, values etc defined in files above them (and the same within files, with some caveats). This sounds really weird and annoying but turns out to have some surprising benefits (because it limits the mental/real search space for definitions as well). In practice it's just something that is surprising at first, then totally fine.


This guarantees that there are no cycles, but there are more ergonomic ways to do that. And the change would be backwards compatible.

I wish languages didn't insist on preserving quirks like this one.


That is pretty nice for testing, since it removes the need for depency injection, or am i mistaken?


Not really. There are various DI patterns you can use in F# [1], but the combination of no cyclic dependencies + type inference does mean you can just do the simplest thing - pass dependencies manually as specific arguments - and it will stay manageable for much longer than in java/c#.

Evil dangerous code using global variables:

   let mail = // .. create email service
   let db = // .. create database service

   let receiveThing thing = async {
      let query = // .. compose update query
      do! saveToDb db query
      let emailText = // .. compose email
      do! sendMail mail emailText
   }

   while readInput() do receiveThing (getThing())
Beautiful pure code using dependency injection:

   let mail = // .. create email service
   let db = // .. create database service

   let receiveThing db mail thing = async {
      let query = // .. compose update query
      do! saveToDb db query
      let emailText = // .. compose email
      do! sendMail mail emailText
   }

   while readInput() do receiveThing db mail (getThing())

[1] https://fsharpforfunandprofit.com/posts/dependencies/


All DI libraries can be ripped out and replaced with a bog standard main method, and it doesn't even require much skill. Most of what it's doing for you is stuff like "foo = new Foo(); bar = new Bar(foo, 33);" So there's no strict "need" for them, they help with (and enable) complexity.

What F#'s aversion to cyclic dependencies does forces you to break cycles of types referring to types referring to types. The way you do that is by writing a generic function that avoids referring to a concrete type. Because it's generic, such a function is inherently easier to test by means of a simple stub value.


For sharing large training data have a look at https://zenodo.org which is run by the CERN people. Up to 50GB is no problem and after that they say just talk to us :).


Douglas Connect GmbH | Functional programming generalist | Basel, Switzerland | ONSITE w partly remote | Full time or part time

We are a small company based in Basel, Switzerland working on solutions and research in the field of health sciences with a focus on toxicology. It's an exciting time to be in Toxicology as the whole field is moving towards minimizing animal testing by using machine learning to predict toxicity of new compounds.

We are looking for an experienced software engineer who is comfortable with functional programming languages (any of Elm, Elixir, F#, Haskell, OCaml, ...) and has experience both on the backend and in frontend development. Our existing solutions are built mostly with Elm, Python, R and a bit of Scala. You are a resident of Switzerland and while remote work is also possible, you are able to work from our office in Basel at least some of the time.

https://douglasconnect.com/join-us


Douglas Connect GmbH | Functional programming generalist | Basel, Switzerland | ONSITE w partly remote | Full time or part time

We are a small company based in Basel, Switzerland working on solutions and research in the field of health sciences with a focus on toxicology. It's an exciting time to be in Toxicology as the whole field is moving towards minimizing animal testing by using machine learning to predict toxicity of new compounds.

We are looking for an experienced software engineer who is comfortable with functional programming languages (any of Elm, Elixir, F#, Haskell, OCaml, ...) and has experience both on the backend and in frontend development. Our existing solutions are built mostly with Elm, Python, R and a bit of Scala. You are a resident of Switzerland and while remote work is also possible, you are able to work from our office in Basel at least some of the time.

Find a more extensive job description here: https://douglasconnect.com/join-us . We are looking forward to your application!


I'm actually surprised that so many teams have this view. We are a very small dev team working on scientific apps and I feel that the time it took us all to get comfortable with Elm was easily recouped by the constant development speed we had even as the app got bigger. In Javascript, projects just become harder and harder to refactor and so they accumulate cruft and development speed drops as the project ages. In Elm, with the help of a really decent type system and a helpful compile, we were able to keep going and just add features at a constant pace. I think it's worth taking a close look at Elm for this reason alone (or Purescript for that matter but there it is possible to get lost in rabbit holes of type complexity :) ).


> We are a very small dev team

That's the secret though, right? When you have teams of dozens of developers in a company of thousands the cost of adoption and the resistance you encounter increases exponentially. At least I can evangelize React/Redux/Typescript and get a sane development experience that's still just JavaScript.


That's an interesting claim. Can you elaborate on the superlinear factors of the cost increase?


In part, it's probably because ever since the os360 project we've known that communications overhead in programming projects does increase more-than-linearly with the number of collaborators.


I'm not entirely sure that the cost is exponential as the parent stated, but it certainly is superlinear above a certain threshold in my experience.

There are a few issues you have to deal with. The first is how adoption happens. This is generally based on power structures and reputation. If you are in a position to mandate a change, the cost is potentially lower (see below, though), but if you are not then you have to influence enough people to make a change.

There are many ways to do this, but I will split it into 2 for simplicity. First, you can try to influence the rest of the group directly. As the group size grows, this becomes progressively more difficult because your message is lost in the noise of other people pressing their own agendas. Once you get above certain point (say about 8-10 people), your odds of success drops to near zero.

The other main way is to pilot a project and use its success to influence others. Setting up the pilot requires influencing a smaller group and therefore you have higher chances of success. The problem is that when you pilot a new way of doing things, you are intentionally breaking consensus. You now have a small group of individuals who have experience that nobody else in the group has. Whether the adoption of the new technique is successful or not, this leads to increased cost as attitudes change.

The bigger the group, growing out a pilot into a larger project becomes more expensive. This is essentially the same problem as before -- you may be in a position now to mandate a way of working, but if you are not, then you have to create another round of pilots to move the idea around the group. But now you have another problem -- the implementors of the new pilots are different than the implementors of the original pilot. So you will now have more than one message coming out. You now have to harmonise that message in order to drive adoption.

At every step, there is a chance of failure (sometimes quite high). The chance of failure grows as size of the group increases, because the external pressures to not change are higher. Again, there are several possible outcomes, but I will pick 2 for simplicity. You may find that your idea is rejected. You have now spent resources on your pilot that you will have to reimplement in another way. Another outcome is that your adoption is simply stalled -- you split your group permanently. This has cost implications ranging from staffing, to training, to tooling, to management, etc.

Now, assuming you don't fail, you may have organically grown the adoption in your group (which is ideal), but as your group size grows, the possibility of that decreases (because the risk of failure increases based on the size of the group). More likely is that you have gotten enough reputation to be able to mandate a change.

Mandating changes has costs as well. The first is that some people will be uncomfortable with the change and will quit. You now have to replace those individuals - which costs you both lost productivity, referral fees, and training costs. This is more likely as the group size increases because you are more likely to have diverse, strongly held opinions.

The next biggest cost would appear to be training, retooling, etc. However, there is a hidden cost -- compliance. Very good people who dislike the change will leave. Very poor people will not leave -- they will simply refuse to follow the new strategy competently. This may be because they are depressed over the change, scared of how the change affects their influence, and many other things. These people can often end up sabotaging your projects (mostly unintentionally, but as they are usually quite upset they also don't care if they do). As the size of the group increases, the chances of building an unshiftable group of discontents grows.

If you want to make a lot of money, become a consultant introducing new development techniques into large organisations like banks. It's a bit like siphoning all their operating capital into your pocket because you have no hope of success and can blame all your failure on other people.


Sounds about right. Tons of work and can be very draining.


Elm seems like an excellent choice for a small or large dev team. There's only one way to structure your app - the Elm way. As your app grows, it must still follow the Elm way and the same circle of events. For developers transitioning on to the app or different parts of it, business logic is the major hurdle and not the app structure itself. The app structure is more or less the same be it a small or large app.


Take a look at Traefik (http://traefik.io/), it's a reverse proxy you use as an edge service behind the cloud providers L4/L7 LB. It is designed to change dynamically and can listen to K8s ingress changes and reconfigure itself automatically and it has let's encrypt support (although at the moment not so streamlined in k8s but that is supposed to change soon).


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: