7 ms·
I learned Elixir a few weeks ago as a quarantine self-improvement project and pretty much loved it. There are some warts, as in any language. As someone who's p
by biggestlou 6y ago
I learned Elixir a few weeks ago as a quarantine self-improvement project and pretty much loved it. There are some warts, as in any language. As someone who's primarily worked in Go and Java in the past and has also been learning Rust I don't super love the optional typing thing, and I end up missing higher-level data constructs like interfaces and traits.
But there are some great language features, like guards and pattern matching, that are hard to give up when you go back to other languages.
Plus it's great to have OTP goodies like GenServer at your fingertips if you run into performance bottlenecks (which you may not!). The OTP APIs are a bit weird coming from other languages but not too bad.
Other things I've liked:
1. Ecto is simply the best DB library I've encountered in any language. I'd almost recommend learning Elixir just to be able to use Ecto.
2. Plug provides great HTTP ergonomics highly reminiscent of Go's context-based middleware approach. Having direct access to the full request/response lifecycle is a win.
3. Phoenix is nice because it's essentially just Plug with some convenient helpers on top. Strikes a really nice balance between configuration and convention by letting you use only what you need. Haven't tried LiveView as I'd prefer to handcraft my own JS but probably worth a shot.
4. Absinthe is the best GraphQL framework I've encountered after many others in other languages left me completely cold.
- izelnakri 6y agoYou’ve just summarized my thoughts on Elixir after using it(and still loving it) for years. Thanks :)
- lindgrenj6 6y agoCheck out the Elixir "protocol" feature, it's similar to interfaces: https://elixir-lang.org/getting-started/protocols.html https://elixir-lang.org/getting-started/protocols.html
- Grimm1 6y agoI was just about to say, protocols fill the interface slot pretty well
- QuinnWilton 6y agoProtocols + the Typeclass library [0] makes for some of the most extensible Elixir code I've worked with. [0] https://github.com/witchcrafters/type_class https://github.com/witchcrafters/type_class
- sb8244 6y agoHi Elixir friend! Have you done a blog post on this by chance? I'd be really interested in reading one.
- QuinnWilton 6y agoI haven't, but the creator of the library (Brooklyn Zelenka / @expede) has given a few excellent talks that reference her libraries. This is a personal favourite: https://www.youtube.com/watch?v=JD0FJTmuV_Q https://www.youtube.com/watch?v=JD0FJTmuV_Q
- biggestlou 6y agoI've used protocols, and they are useful as a kind of bare minimum interface/implementation abstraction. But they're nowhere even close to something like Rust traits. Which is totally fine given Elixir's goals.
- AlchemistCamp 6y agoI'm pretty deep into Elixir and have been learning a bit of Rust on the side this year, so this is interesting. Could you elaborate a bit?
- ch4s3 6y ago> 1. Ecto is simply the best DB library I've encountered in any language. I'd almost recommend learning Elixir just to be able to use Ecto. It's interesting, people always talk about Phoenix, which is nice, but Ecto is really special. I often recommend it to anyone who is feeling burned by Active Record implementations.
- dpeck 6y agoChangesets are beautiful. And they're great for general structure validation outside of databases as well.
- ch4s3 6y agoOh yeah, absolutely. They're great for building API clients.
- i_s 6y agoI thought so too, at first, but now I'm really down on it. Ecto Changesets work fine for flat data, but when you have to deal with nested data, it becomes a nightmare, because you have to use these special functions to read and update the data. Doing that in a nested context just gets really clunky, especially coming from Clojure, where I would just do something trivial, like (assoc-in changeset [:children 1 :title] "New title")
- sooheon 6y agoClojure sets an unfairly high bar for data manipulation with core, transducers, libraries like supdate and specter.
- ch4s3 6y agoThat is indeed a bit of a pain point. From what I understand, it's a bit intentional and the library authors want you to prefer flatter data structures. Now of course not all structures CAN be flat so you can hit a bit of an impedance mismatch. However, I think Ecto is amazing for more common (for me at least) cases.
- 6y ago
- derefr 6y ago> I don't super love the optional typing thing It might not be a plus if you're writing a web-app, or some other kind of easily-restarted "shared-nothing business layer" system. But get deep-enough into absorbing the Zen of Erlang (i.e. by trying to write a big-deal telecom system; or by working on a distributable Erlang DBMS like CouchDB), and you'll come to appreciate it. Specifically, you'll realize that it'd actually be impossible for the Erlang runtime system to support hot-code-reload plus automatic distribution plus static typing, all at once. One of them has to give. (I think this is one of those universal "choose only two properties" triangles, like CAP, though I don't think this one has a name.) If you have a "living" distributed system—one that you don't bring down entirely for each upgrade—then inevitably you'll hit a situation where a node with the fresh new version of a module (V3, let's say), tries to use that module to send a V3 message to a node that is still only running V2 of the module. In a distributed system with static typing, that'll inevitably crash the V2 node—unless you did a whole extra "V2.5" rollout step to first teach V2 about the wire-format of V3 and how to handle it. Much of the point of Erlang/Elixir's user-facing "data architecture" design—e.g. using partial destructuring pattern-matching (unwrapping tuples one layer at a time) instead of uniquely tagging messages with message-type UUIDs like COM/CORBA—is to "automatically" cope with this, allowing your "living" distributed system to interoperate in the face of cross-node module-version heterogeneity, without having to write explicitly backcompat "also recognize the previous/next version of the message" code during the rollout period. Every Erlang term sent in a message is, in some sense, like a little extensible file-format; and the tools you're given to "parse" the term—when you use them idiomatically—give you forward-compatible "parsing." As long as you don't validate that a term has a specific "deep" structure corresponding to some static type, then it doesn't matter if your module-V2 actor has actually received—and is now holding onto—a module-V3 parameter in its state. It won't know what to do with it, but nor will that cause any problems as long as it doesn't poke too hard at it. It can even keep hold of it, storing it away for later in its state generically, without understanding exactly what it's received. It'll be there in the state for when the module upgrades to V3, and suddenly cares about that property. (OTP's supervision system also comes into play here, ensuring that any unhandled edge-cases of this term "parsing" just become temporary restarts of the leaf-actors that receive them, without affecting the stability of the node as a whole. The network upgrade completes; the affected actors come back up running the new module version; the system continues.)
- deleted 6y ago[deleted]
- 52-6F-62 6y agoI've been meaning to do this for so long and I've started at least twice but other work or life have gotten in the way. And I haven't gotten any "quarantine-time" as my industry has been busy! It's good to hear this, though. I might have to try and re-prioritize learning it again. Do you have any good resources on hand that you used and would recommend?
- dnautics 6y agoActually I think the one place where elixir community is relatively lacking is online long form tutorials. There is some fantastic content on YouTube. I quite like plangora for intro stuff and knowthen for more advanced content.
- skeletal88 6y agoInteresting. I really like Python and SqlAlchemy. Changing objects in the database via changesets and applying them on top of eachother feels kinda alien, when I can't do object.property = something. The thing that confuses me most about Phoenix and Elixir is how do I actually deploy the application to production? I have my own server where I can run whatever I want (running Ubuntu), so what do I have to do to get my Phoenix application working there? How do I get my code running as a systemd service?
- dnautics 6y agoDoing object.property = something is, I think a mental anti-pattern because it engenders uncertainty about which source of information holds the truth (local object or database), and now you have a needless (mental) distributed state problem. At least in a system with bare structs and changesets, especially in an immutable language, there's no ambiguity about the fact that your data are stale the minute you drive it off the dealership lot and your data synchronization events must pass through a single explicit point of entry. Explicit is better than implicit, after all. To answer your second question, that's not entirely easy to answer, but I personally use mix release command, ship it to s3 as a tar.gz, then pull it down into the server, unzip, put the command line entry point "start" (there are instructions when you do mix release) into a systemd service, and it's good to go. Couldn't be easier. It takes us several ansible scripts, and annoying wrangling with virtualenvs if something goes wrong for us to create a new Ubuntu Django server from scratch and literally two commands (one is a 5 line shell script) to get Elixir up and running.
- ch4s3 6y ago1. It's a functional thing, it's quite nice after you use it for a bit, and really powerful because you can use it for any data, and not just when working with a DB. 2. There are several ways. You can use releases [1]; copy the code to the box, run mix release, then ./app start, and point whatever you want to that process. If you're running phoenix you could always compile it on the box and just run mix phx.server. I wouldn't do that though. You could also use a tool like distillery[2] which is kind of like releases. There is another more esoteric option where you build locally without the runtime, but I wouldn't recommend that. [1] https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html https://elixir-lang.org/getting-started/mix-otp/config-and-r... [2] https://hexdocs.pm/distillery/tooling/cli.html https://hexdocs.pm/distillery/tooling/cli.html