I fell in love with Erlang. I always prefer languages where the syntax is very simple because you don't need to know that much when reading the code.
In fact, Erlang was so simple I was able to read it before I even knew what it was. I learned it by digging into the RabbitMQ source code.
Pattern matching with function branching and case really changed the way I develop in every language. Just have a linear instruction flow, no more multiple returns, no more if/else, just read the code and when you're at the end of the function, you know what it returns.
Then, I fell in love with Elixir. The only language where macros aren't just C's #define to replace text. You're working directly with the AST, and that's just obvious to me now it should be done like that. Mix is also a game changer for the Erlang/Elixir ecosystem, it's so easy to build/release/deploy with Mix. I remember having some difficulties getting erlang.mk or rebar to work correctly, but with Mix it was instantly working. Also config/runtime.exs, I love you.
The OTP framework let's you structure your code the same way you conceptualize it in your head: "I have this part that talks to this part, and they need to know what this part is doing" translates to "I have a module that send messages to this GenServer, and they both monitor this process".
I can't understand why those languages aren't more known/hyped/adopted/... It's a shame.
> The only language where macros aren't just C's #define to replace text. You're working directly with the AST
It's hardly the only such language. In my experience, Haskell, Rust, Common Lisp, and Scheme all have macros that operate by syntax trees rather than text substitution, and I have no doubt that there are several more that I'm not aware of.
It's mostly based on manipulating lists. Scoping is a bit odd, but if you squint, the fact that unevaluated lists are passed into functions where they can be manipulated (by normal tcl list functions) and then evaluated in the caller's scope (or in other scopes), coupled with the fact that built in syntax (if, proc, for, etc) is the same as user-defined function call syntax, gives you more metaprogramming power than you might expect.
True, mostly. As the other commenter noted, function calls can be squeezed through some rather macro-looking holes if you just push hard enough.
Don't get me wrong, Tcl metaprogramming is awful and gross and I don't recommend it, I was just being the stereotypical nitpick HN commenter for that moment since it CAN be done.
I will give you an answer. The average system won't encounter the drawbacks of not using this model until they have the good problems of too much success and too many users. At that point you can throw warm bodies into cold chairs and mostly solve the problem. To conclude, Node and Python are good enough, and VC bucks will iron out the kinks.
That being said, having learned Elixir, I struggle to imagine using anything else for a greenfield web application. However, I have some curiosity about programming languages and was willing to take a leap of faith based on a few enthusiastic HN posts. Not everyone is like this.
Let me add that you, yes you reading this post, should read Elixir or Erlang if you haven't yet!
> In fact, Erlang was so simple I was able to read it before I even knew what it was. I learned it by digging into the RabbitMQ source code.
No matter what language I'm programming (including elixir), my pseudocode in design documents is always written in a pidgin erlang. It's simple, direct, discourages side-effects and encourages composability. Its building blocks (and syntax) also make it easy to describe abstract data types and schemas.
Elixir was a joy to write applications in. OTP provides the most seamless graduation from single-threaded to concurrent to distributed application that I've seen in any language. The abstractions are built the way they are because they facilitate this process. Additionally using apps as building blocks matches exactly how I think about systems.
The only things I didn't like:
* Message queues are fundamental to the abstractions. If you need to avoid queuing for whatever reason then you need to think harder
* Leaving the Erlang ecosystem (e.g. shelling out) always felt painful. Integrating with Kubernetes was painful. OTP has its own ways of doing everything and they are often counter to general best practices (e.g. doing hot releases instead of rolling new containers)
* I never figured out how to do multi-node systems correctly. One of the neat things about OTP is that you can migrate processes between nodes that are connected in a mesh network. The documentation is really light on how to do this. Along those lines, more advanced multi-node setups exist but feel like they are at the fringes of what has been done with OTP so you need to invest a lot of time if your application can't handle a mesh setup
The only language that comes close to Elixir for me is Rust. I haven't done much with Rust however the out-of-the-box tooling is really great for it. I'm doubtful that distributed applications are as easy to write in Rust as they are in Elixir though
I tried to sell a company I was working at (they were doing real-time bidding) on Elixir. It's a shame they didn't go with it (they went with Java instead). It's really easy to build those types of apps in Elixir. Likewise I'm somewhat surprised Elixir hasn't taken off with teams who want microservices.
> OTP has its own ways of doing everything and they are often counter to general best practices (e.g. doing hot releases instead of rolling new containers)
Now this is opinionated. Hot releases are used mostly if you want to upgrade your drone's software while it's flying. Surely you don't want it to crash?
Or if you're a telecom company (like the creator of Erlang), you don't want an upgrade to kill the on-going communications. Same for a MMO, you don't want an upgrade to disconnect your players.
Docker/Kubernetes is not "general best practices". It's only one way out of many. And if you don't need the use cases above, you can put your application in a Docker container and restart it for upgrades, this is how 90% of Elixir/Phoenix webapps are deployed.
> One of the neat things about OTP is that you can migrate processes between nodes that are connected in a mesh network. The documentation is really light on how to do this.
My time with Elixir is pretty stale at this point (5-6 years ago; haven't touched it much in the past 4) so I'm glad to see there are better solutions today
> How? They solve completely different problems. Could you explain?
I don't disagree. The main crossover for me has been in productivity/expressiveness/safety. Can I easily write the programs I want to write with it or am I fighting the language and tooling constantly? Do I have high confidence in the correctness of my solution? Does the solution feel easy to maintain and extend? I haven't done enough with Rust to comment on how it fairs for larger projects, but my experiences with it for smaller problems has been very positive
It is. I'm working on a distributed IOT project (think 40 raspberries talking to each other).
From my superficial understanding, this would be an ideal use case for Erlang. I guess an Erlang environment would naturally lead to a much more elegant solution.
The problem is, that nobody really speaks it here or has any experience with it. That's why we chickened out and used Go and C++ instead.
I guess a lot of developers have the same problem. Erlang is intriguing, but other languages are the safe choice.
This sounds like a great fit for the Nerves project. It focuses on Elixir, which runs the same as Erlang.
It builds firmware for Pis and other IoT on top of a thin Buildroot Linux layer, starts the Erlang VM and then that's practically your OS for building your device. Plenty of escape hatches for special needs.
I've done a bunch of streams recently with clustering Pi devices using Nerves, especially fun on local network with mDNS. They are on my blog: https://underjord.io/blog.html
Feel free to reach out if you have questions about Nerves. I'm an enthusiast of it, contributing mostly by using it for fun in public. Also write the newsletter so I'm fairly up to date :)
A lot of devs find Elixir more approachable/familiar than Erlang so it might help in your case there as well.
Sounds good. I'll take a look. I'm actually still waiting for the GRISP 2 board, if that ever gets done.
The problem is that I think that I need to spend time on Erlang/Exlir full time, otherwise I keep forgetting what I've learned. I guess I'm getting old :(
I work on GRiSP. It’s really close to being done. We’re wrapping up the software (e.g. updating drivers for the new platform) and are doing a lot of testing at the moment.
We are using the first boards from the final batch for this, and I really hope we can start shipping soon.
in a previous job, back around 2007, we had a rather crappy homegrown distributed system with python nodes talking over rabbitmq. gave us constant headaches, partly because no one in the company had any distributed computing experience at all and we had just sort of hacked something together.
four of us decided to see if erlang would suit us better, and within three months we had learnt enough of the language to set up an mvp that was both outperforming and out-uptiming the python cluster, with significantly less code, and all in basically 10-15% of our time, since we had to do our actual work.
sadly management decided that erlang was too risky to bet on, but my takeaway from that experience is that it is a remarkably easy language to learn/train even junior developers on, and that if your problem fits its sweet spot the language/platform will practically guide you towards a nice clean solution for it, and more than pay for the time taken to learn it in reduced maintenance complexity.
I think the point is that it's simpler to write a functional distributed system in Erlang/Elixir that have this all baked in than to do it in the others. But the others are simpler to round up some coders and out something out with even though there are a lot of traps for the unwary and no guide rails like the ones Actor models give you.
Basically enterprise IT sometimes mistakes something being easier to finish with it actually being simpler to run long term. Hence people who write themselves into corners with Python websites etc
I did like my time with erlang but it just didn’t gel with my current line of work. The distributed nature and pattern matching does make stitching together little http servers in go feel like a step backwards, but it’s just a bit too arcane for my team.
Should probably check in with elixir again. Although we’re plenty happy with golang at the moment…
Don't bother if you value your sanity. If you check in with Elixir you will likely increasingly grow irritated with golang. I recommend waiting until you don't depend on golang for a paycheck anymore.
The Erlang world is obviously full of bright people with cool ideas, but difficult string handling is a deal breaker for me if I intend to use a language in production grade projects. Is Elixir better at it?
Significantly better, yes, I've never felt like String methods were missing while using Elixir, they've also got some goodies like Jaro distance right in the stdlib. Docs on Elixir strings are here, plenty of methods: https://hexdocs.pm/elixir/1.12/String.html
> The Erlang world is obviously full of bright people with cool ideas, but difficult string handling is a deal breaker for me if I intend to use a language in production grade projects. Is Elixir better at it?
Yes, the Elixir stdlib uses only binary strings, never charlists. But to be fair Erlang largely got its shit together with binary strings a decade ago.
It's still uncomfortable to deal with binary strings in erlang, starting with the very awkward syntax, but also there are also quite a few non-core stdlib functions that refuse anything but charlists, like options for tls (ssl) module, x509 settings, ssh module, etc.
In fact, Erlang was so simple I was able to read it before I even knew what it was. I learned it by digging into the RabbitMQ source code.
Pattern matching with function branching and case really changed the way I develop in every language. Just have a linear instruction flow, no more multiple returns, no more if/else, just read the code and when you're at the end of the function, you know what it returns.
Then, I fell in love with Elixir. The only language where macros aren't just C's #define to replace text. You're working directly with the AST, and that's just obvious to me now it should be done like that. Mix is also a game changer for the Erlang/Elixir ecosystem, it's so easy to build/release/deploy with Mix. I remember having some difficulties getting erlang.mk or rebar to work correctly, but with Mix it was instantly working. Also config/runtime.exs, I love you.
The OTP framework let's you structure your code the same way you conceptualize it in your head: "I have this part that talks to this part, and they need to know what this part is doing" translates to "I have a module that send messages to this GenServer, and they both monitor this process".
I can't understand why those languages aren't more known/hyped/adopted/... It's a shame.