I'm a hobbyist high-availability dork, so the idea that I could update my program without interrupting any user of the program was very, very attractive to me. I'm also quite sick in the head and have a life-long torrid love affair with Bash's switch statements, so Erlang's "pattern match to make most decisions" syntax was a huge attracter.
Having said that, I didn't really get Erlang until I had a project for which it and the OTP were a good fit. I needed to build a server for an unfamiliar-to-me protocol, so I expected to regularly have protocol handlers fail due to incorrect implementation. This server would be long-running, so VM startup time was not a problem. This server would perform next-to-no number crunching. This server could be very effectively modeled as a swarm of message-passing processes. The core functionality of the server was best modeled as an FSM.
Erlang's "share nothing, use message passing" design, along with OTP's supervisor and friends kept my server up and running while my protocol handlers exploded because of incorrect or absent handler code, or too-pessimistic assertions about the valid bounds of input data. Hot code reloading let me fix broken code paths (or experiment with non-broken ones) without affecting users of other code paths in the server. [0] The built-in FSM library made it trivial to express the parts of my program that were an FSM as an FSM. Not only did Erlang's syntax satisfy my sick fascination with Bash's switch statements, it permitted me to write nearly all of my server as simple, sequential code and let Erlang/OTP handle the nasty problems of concurrency for me.
Oh yeah, and the extremely high quality of Erlang's documentation was really helpful. In the reference manual for the standard library, the documentation for every single function provided in Erlang/OTP told you the valid types and acceptable ranges/values for both function arguments and return values. They told you which functions would throw, what would be thrown, and under what conditions. They also described what the function did, and -when needed- why it did it. I could be confident that if I programmed according to the docs, then my program would behave as the docs said it would... unlike where documentation for most Web Development stuff leaves you. [1] There's also official documentation about the design of Erlang/OTP and the reasons behind that design. Those docs (along with Learn You Some Erlang) definitely helped me understand Erlang and OTP.
Like I said... if your project isn't a good fit for what Erlang provides, I think you're not going to get what makes Erlang/OTP special. But if it is, there's a very good chance that you will.
[0] Supervisors + hot code reloading made it emotionally really easy to build my server incrementally. Knowing that I didn't have to get the entire protocol right to have a server that would never die was calming. As was knowing that implementation failures (or deliberately unhandled parts of the protocol) would provide me with usually-good diagnostic information, rather than a core dump (or nothing at all(!)).
[1] This was prior to the big redesign of Erlang's docs to ape the style used by HexDocs. Whoever did that redesign very, very clearly did not understand what made Erlang's documentation so good. Switching from EBNF-ish to raw Erlang spec format not only takes up far more vertical space, but adds yet another new thing someone new to Erlang needs to learn. But far, far, far worse is that some of the documentation about the valid ranges of input to functions has been lost.
I'm a hobbyist high-availability dork, so the idea that I could update my program without interrupting any user of the program was very, very attractive to me. I'm also quite sick in the head and have a life-long torrid love affair with Bash's switch statements, so Erlang's "pattern match to make most decisions" syntax was a huge attracter.
Having said that, I didn't really get Erlang until I had a project for which it and the OTP were a good fit. I needed to build a server for an unfamiliar-to-me protocol, so I expected to regularly have protocol handlers fail due to incorrect implementation. This server would be long-running, so VM startup time was not a problem. This server would perform next-to-no number crunching. This server could be very effectively modeled as a swarm of message-passing processes. The core functionality of the server was best modeled as an FSM.
Erlang's "share nothing, use message passing" design, along with OTP's supervisor and friends kept my server up and running while my protocol handlers exploded because of incorrect or absent handler code, or too-pessimistic assertions about the valid bounds of input data. Hot code reloading let me fix broken code paths (or experiment with non-broken ones) without affecting users of other code paths in the server. [0] The built-in FSM library made it trivial to express the parts of my program that were an FSM as an FSM. Not only did Erlang's syntax satisfy my sick fascination with Bash's switch statements, it permitted me to write nearly all of my server as simple, sequential code and let Erlang/OTP handle the nasty problems of concurrency for me.
Oh yeah, and the extremely high quality of Erlang's documentation was really helpful. In the reference manual for the standard library, the documentation for every single function provided in Erlang/OTP told you the valid types and acceptable ranges/values for both function arguments and return values. They told you which functions would throw, what would be thrown, and under what conditions. They also described what the function did, and -when needed- why it did it. I could be confident that if I programmed according to the docs, then my program would behave as the docs said it would... unlike where documentation for most Web Development stuff leaves you. [1] There's also official documentation about the design of Erlang/OTP and the reasons behind that design. Those docs (along with Learn You Some Erlang) definitely helped me understand Erlang and OTP.
Like I said... if your project isn't a good fit for what Erlang provides, I think you're not going to get what makes Erlang/OTP special. But if it is, there's a very good chance that you will.
[0] Supervisors + hot code reloading made it emotionally really easy to build my server incrementally. Knowing that I didn't have to get the entire protocol right to have a server that would never die was calming. As was knowing that implementation failures (or deliberately unhandled parts of the protocol) would provide me with usually-good diagnostic information, rather than a core dump (or nothing at all(!)).
[1] This was prior to the big redesign of Erlang's docs to ape the style used by HexDocs. Whoever did that redesign very, very clearly did not understand what made Erlang's documentation so good. Switching from EBNF-ish to raw Erlang spec format not only takes up far more vertical space, but adds yet another new thing someone new to Erlang needs to learn. But far, far, far worse is that some of the documentation about the valid ranges of input to functions has been lost.