8 ms·
Thank you so much for sharing this. I've not yet finished a decade in the industry, nor ever laid an eye on Elixir before, and this made sense pretty quickly. G
by ammanley 5y ago
Thank you so much for sharing this. I've not yet finished a decade in the industry, nor ever laid an eye on Elixir before, and this made sense pretty quickly. Great job explaining it all!
On a side note, its pretty amazing to see the impact on readability and understanding that native language features have on something like async. I've worked with similar systems to the example in the past in JS/Go/etc, and while you can definitely do the same stuff presented here, it tends to be a far messier callback-hell ime. For lack of better explanation, this Elixir code just "flows" better to my eye, which I know is a completely subjective and non-helpful unsolicited piece of info. Thanks again.
- dnautics 5y agoOh that's so funny, because I'm an elixir user and we all claim that genserver (internal) organization is terrible. But yes, it is way better than callback hell... It just could be better still.
- HH_GU 5y agonot genserver, what will you use?
- deleted 5y ago[deleted]
- dnautics 5y agoThere isn't anything. Dave thomas proposed a better way of organizing genservers, but I can't get behind it because his implementation is too magical and clever, but his idea for what the api should look like in the big picture is reasonable... I'm also generally in favor having everyone speak the same idioms, so it would take a very good implementation to get me off of genserver. That said you shouldn't write genservers if you can help it. Using the frameworks genservers Is the best choice, Task is a better choice for most cases.
- lostcolony 5y agoIt flows better because it is writing synchronous code. The code inside of every process in Erlang is synchronous. You achieve concurrency by spinning up processes (spawning functions). This isn't that different to firing an async function in Javascript, or starting a goroutine, etc. And you communicate between the processes by sending async messages. Those are the primitives. Asynchronously send messages between processes that are synchronously doing stuff. Go is actually not -that- different, except sending messages is synchronous, too, unless you set a buffer on the channel (and then you have to size it). Though I agree, because Erlang/Elixir keep it simpler than that, and are dynamically typed, it's a lot cleaner to write.
- fn1 5y agoThe formal framework for this is called CSP ("Communicating sequential processes"). I discovered this 15 years ago, and once you understand it, you will never have problems in multithreading again. https://arild.github.io/csp-presentation/#3 https://arild.github.io/csp-presentation/#3
- lostcolony 5y agoNot exactly. CSP is more what Golang adheres to (synchronous communication). The Actor Model predates CSP. And understanding it you'll still have problems...they're just different problems. You either won't be able to use a language with message passing as a concurrency primitive (i.e., almost all popular languages other than Go at this point), or you will, and now you'll have the time to spend on new types of problems (i.e., you can still create race conditions and deadlocks, and, in Erlang at least, now you get to start asking yourself what happens when things go wrong to a level you never would have with any other language).
- OkayPhysicist 5y agoThe nice thing about the cleanly independent processes is that by and large, "let that part crash, and keep going" is a perfectly adequate answer to most process states outside the pretty path, which is a real saving grace when working with wildly concurrent systems.
- pandemic_region 5y agoI completely relate to the "code that just flows" statement. Cognitive overhead when dealing with code is a thing. I've been trying to explain this to a bunch of junior devs at every opportunity i get but all I get is a blank stare. Seems that the more senior and especially bittervet developers are a lot more sensitive to this. Thanks for sharing!