8 ms·
Elixir and Phoenix after two years
- davidw 6y agoWhat are people finding as the real sweet spots for Phoenix? I have used Erlang very successfully in a semi-embedded context, but that's quite different from a web server that can usually be scaled horizontally pretty easily. One obvious one is if you have to hold open a lot of concurrent connections like web sockets. It'd be great for that. Others?
- ch4s3 6y agoIt's pretty great anywhere that you might use Rails or Django, but if you expect spike in traffic that are hard to predict you get nice stable worst case latency. I think it's also really good if you need to hold state server side for any reason.
- davidw 6y agoRails has a ton of high quality code available for it. It looks to me like Phoenix is certainly 'good enough' for a lot of tasks, but it just hasn't been around as long. I'm looking for those use cases where someone picked Phoenix and it was just clearly a better tool than, say, Rails because of X, Y, and Z, despite maybe being inferior for one or two other things.
- ch4s3 6y agoHaving done both, I think Rails has a ton of baggage around ActiveSupport and ActiveRecord that are full of gotchas. Ecto prevents N+1 queries by default, which I think is clearly better. I also think that the lack of lifecycle hooks in Ecto is a better decision than the pile of foot guns in ActiveRecord hooks. I would also argue that Plug is a large improvement over Rack, and the idea of explicitly passing a single context map all the way through the request is just a better way to build http responses. I also think that the Fallback controller is obviously a better way to handle common errors. Anything related to web sockets will be leagues better in Elixir, because the BEAM is built to do a thing like that. SSR html as a compiled linked list is a better idea than runtime string interpolation. Sure, Rails has libraries for everything, but some of the core parts just aren't a nice. So if you don't need all of that breadth of ecosystem then Phoenix is a better choice IMHO having worked professionally with both for a number of years.
- aantix 6y ago>Ecto prevents N+1 queries by default, which I think is clearly better How does it know what associations to eagerly load without knowing about the views? It can't eagerly load all of the data on complex objects.
- AlchemistCamp 6y agoIt doesn't eagerly load anything. It preloads exactly what you tell it to. Ecto Repo vs Active Record: https://youtu.be/IFKG4Hgt-zM https://youtu.be/IFKG4Hgt-zM
- aantix 6y agoSo you have to be explicit in what to "preload"? How does that differ from specifying an includes on associations for eager loading? It's not saving you any mental energy; you still have to discern what should and shouldn't be loaded up front.
- dmpk2k 6y agoThe question was regarding N+1. If you're not careful with ActiveRecord, you get that. With Ecto, it's impossible. Ecto has its own drawbacks, but its strong suit is predictability.
- aantix 6y agoN+1 is because lazy loading is by default in ActiveRecord. Because it doesn't know anything about your object graph and what associations are needed, so it just loads data as it's encountered. That's a reasonable default. You add includes as you know more about your data and what associations are needed in specific contexts. Eager loading is an optimization, not a prerequisite.
- nickjj 6y ago> Ecto prevents N+1 queries by default, which I think is clearly better. To be fair... If you want to protect yourself from these with Rails you can install Bullet[0] and get protection through in your face notifications, and you have the option to let it slide because you're taking advantage of caching with Rails and in this case you know what you're getting into and the N+1 query with caching ends up being better because you understand your domain. Rails also has the strong migrations[1] gem which is a huge help for not shooting yourself in the foot for running migrations in production by helping you avoid table locks and other issues / errors. But AFAIK there's no Ecto equivalent, but strong migrations is really really useful. Rails also has the data-migrate[2] gem which is a nice little abstraction for splitting out your schema changes and backfilling data in an automated way. There's nothing like this with Ecto. This one isn't as useful as strong migrations IMO but it's still very handy to have this problem taken care of for you without having to re-invent a new strategy in every project or copy code over. Basically all 3 of these things are something I'd use in every Rails project but with Phoenix I wouldn't have these things except for N+1 query protection. I'm pretty sure you could technically create strong migrations and data-migrate for Ecto but the reality of the situation is today neither of them are available and there's no sign of them coming anytime soon. Meanwhile strong migrations has had ~6 years worth of real world testing at this point. [0]: https://github.com/flyerhzm/bullet https://github.com/flyerhzm/bullet [1]: https://github.com/ankane/strong_migrations https://github.com/ankane/strong_migrations [2]: https://github.com/ilyakatz/data-migrate https://github.com/ilyakatz/data-migrate
- cancan 6y agoI can add a bit of my experience. I used Rails here and there since 2.3 and have followed Elixir since its inception. - Channels in Phoenix are just a joy to use compared to ActionCable. This is partly due to the language (pattern matching, especially) but not having to deal with a Redis instance (and/or AnyCable) is also appealing. It just works out of the box and is ridiculously performant. - I find the Repository pattern much easier to wrap my head around than ActiveRecord. I feel like with Rails, I always have to know the state of an object whereas w/ Ecto, things are more explicit. I know some people prefer AR here, but I prefer not making an accidental query. - I feel like I am lost every time I'm in a Rails project with so many abstractions now. Maybe this is me being a curmudgeon, but I remember being able to trace request all the way from where it hits the machine (say, Nginx) to the HTML rendering even with Rack. Now, if I had to do something similar, there are so many layers to peel. This is again partly due to the language, and partly to Rails' age.
- news_to_me 6y agoIn terms of language, Phoenix is a complete replacement for Rails for me. I feel more comfortable growing a functional codebase, and the BEAM means I don't have to worry about scaling as soon as I would with Rails. I think it's a good fit for when you want to do more with a small, experienced team. I would reach for Rails when I'm concerned about finding developers (Elixir devs are fewer and more expensive, generally), or if there are Ruby libraries I want that aren't available in Elixir.
- blunte 6y agoI fear it would be difficult to hire Elixir people as well, but now I realize it's actually also hard to hire decent Ruby/Rails people. Honestly I think we should just accept anyone who can demonstrate thinking and programming skills of any language and then plan for 2-3 months of ramp-up time to get them into our language of choice.
- news_to_me 6y agoI agree, and to be clear I've never really been in a position to worry about hiring anyway. But I would imagine building a medium/large team with varying experience levels (including juniors) would be easier with a more established framework like Rails.
- danjac 6y agoI'd be happy (if I were job-hunting) to be able to try out a different language/platform every so often. Now and again I'll play with, say, Ruby or Elixir or whatever. But I know that I'll never get a job working with these languages because I don't have the n years experience with them. The tech hiring process is gruelling enough with languages and frameworks we are familiar with, your resume won't even get a glance if you apply for jobs where you don't have that experience. But I think that narrow thinking is to everyone's detriment.
- mercer 5y agoI've seen at least a few Elixir jobs where they explicitly specify that you don't need to have experience specifically with Elixir. Don't know how common it is though, and it's true that finding Elixir work can be difficult to begin with.
- toolz 6y agoI find elixir and supporting libraries to be the best general web-dev experience of any language. Optional typing, first class documentation, ecto as a library for validations is far more successful at encouraging separation of concerns than I've seen in other CRUD webdev ecosystems. The performance for typical stateless webapps is great, but honestly the thing I love is the amazing tooling and libraries. Elixir libraries are often very high quality.
- news_to_me 6y ago+1 for Ecto, really a game-changing library.
- nickjj 6y ago> ecto as a library for validations is far more successful at encouraging separation of concerns than I've seen in other CRUD webdev ecosystems. Which other ecosystems have you tried? Just asking because with Python and WTForms they've kept validations separate from your model for the last ~10 years. You could for example create "sign up", "sign in" and "profile" forms based off a single user model and each form has its own fields that you can define with their own validations. Very similar to how you can create separate changesets with Ecto and use a single user schema.
- blunte 6y agoLooking purely at webapps, Liveview is the killer feature of Phoenix. Other than that, I would say that any place with a complex service oriented environment where you could leverage the Erlang VM would be an obvious place to use Phoenix for doing your webapps.
- dnautics 6y ago> I have used Erlang very successfully in a semi-embedded context Elixir is really quite good in the semi-embedded space with several successful companies having their IOT bread and butter in Elixir Nerves platform. The deployment story is getting really mature in Elixir. The article has some really salient points: Testing and Documentation and really amazing in Elixir. Concurrent tests are amazing. So for example normally a "database" would be a global resource and running concurrent tests against the database is really tricky. It's basically turnkey in Elixir (need to set up two settings). With a bit of work, it's not terribly hard to write concurrent tests that exit the VM and come back into the vm and use a test-shard of a global resource. So, for example, you write a test that issues an HTTP request to itself, and the request is instrumented with parameters to connect it back to the test process and use the correct "temporary shard" of the database. (In the case of the database it's a transaction, I use the phrase "temporary shard" because the same mechanism can extended to other concepts too, like module mocks, ets tables, process registries, etc, which all use the same mechanism, you only have to set it up once).
- davidw 6y ago> Elixir is really quite good in the semi-embedded space Yeah, I don't need any convincing there. Erlang was a perfect fit for the device I worked on. High level enough to get things done quickly, but with a really solid, predictable runtime.
- lostcolony 6y ago>> but that's quite different from a web server that can usually be scaled horizontally pretty easily So a lot of the other responses are comparing it against Rails and the like, but it sounds like you may be asking specifically around scaling. Erlang (and by extension, Elixir), is nice even when scaling because the actor model will scale to I/O or CPU bound workers simply, without having to tweak threadpools or worry about thread starvation or etc. Other languages that provide n:m concurrency here have the same benefit though (i.e., Golang). Where it shines in comparison to those is in its fault tolerance and memory model. Immutable non-shared data + supervisor hierarchy gives you tools to tackle state that are less error prone than most other languages. And the fact it has a Rails like environment in Phoenix (and Plug, and Ecto, and the whole ecosystem) means you get the same quick-to-build app functionality, without giving up the performance and state management. It's basically having all of these that make it desirable on this front; you can write code as quickly and simply as in Rails, getting the braindead simple scaling behavior of any actor/CSP based model, with the state management of an immutable language, and the fault tolerance of Erlang.
- davidw 6y agoNot that concerned about scaling - I think it's going to beat Rails there, but for a larger web app growing quickly, the difference between going to N web servers from 1 might not be that many months.
- lostcolony 6y agoOh, sure, Erlang isn't going to save you from going multi-node...in fact, it shouldn't; just basic resiliency should mean you're starting multi-node. But the actual number of concurrents per instance, and the effect on latency, is quite another thing. And it also provides you a better story around shared state within the instance, and better controls around its access.
- te_chris 6y agoFast templates are a superpower for our CMS. Combine it with LiveView to eliminate react and we deliver a really good site quickly.
- bluesnowmonkey 6y agoWe used Elixir to implement a columnar database and Phoenix for the web front end, which was about 20% of the code. It’s very convenient having all the tests run together, including end to end integration tests. Elixir (with NIFs) has the necessary performance for the database layer, and Phoenix has the necessary productivity for the web layer, and we don’t have to switch languages to work on both.
- jfim 6y agoPretty curious about this, are there more details that are publicly available? The only thing I can find about this is some meetup from 2018 with a speaker from Pinterest.
- ipnon 6y agoElixir with Phoenix feels like programming with simple and straightforward abstractions around HTTP server, HTML generation and DB querying. Ruby on Rails feels like some sort of divine incantation. Rails has a lot of magic and hand waving, and there are recipes for doing everything that you would ignore at your own peril. I don't get the "hold on to your butts" feeling with Elixir.
- blunte 6y agoTo add to the author's experience, I spent 18 months of production time with Elixir and Phoenix. As he says, the templates are compiled and are blindingly fast compared to Rails. Pattern matching is really really nice when used in the right places (and you'll miss it if you go back to Ruby); but it can be overused. There's a faction of Elixir folks who attempt to avoid all conditionals and instead seem to prefer multiple dispatch/multi-methods to handle different cases. That's nice and very concise, because then you can simply call a function and let the pattern matching resolve which of the various implementations you've defined handle it. The big downside here is, as a reader of the code, you have to basically mentally imagine what all cases are covered and what they mean. Sometimes simply reading a switch statement or if/else/then is much clearer. The super special magic is in the Erlang VM. If you put more energy into learning it and its capabilities, and using it where appropriate, it can shape the structure of your greater system beyond just one webapp; and it can provide a lot of features without you having to cobble together many other (good but independent) solutions. Lastly, single thread performance is basically a dog. In my anecdotal experience, the same external service written with Elixir+Ecto was 25-50% as performant as a Python+SQLAlchemy program. So the lesson there is, find ways to parallelize or otherwise scale your process if it is batch oriented and handling a large volume of data. If you asked me today if I would prefer to use Elixir (and Phoenix) over Ruby and Rails, I would say yes... but honestly mostly just because it's a new fascination with different tradeoffs and a better functional story. Function is the past and the future, and it makes your life easier and simpler. Elixir as a language... borrowed too much from Ruby and has too much syntax. It is noisy in a Perl-like way, and perhaps there could be a more concise enhancement of Erlang which would get the job done and not have you spending time visually parsing code.
- toolz 6y agosqlalchemy is an ORM - I'm not sure it can be compared against a web framework, but my experience with phoenix vs python web frameworks is that phoenix is easily faster even for single-threaded web requests (which of course will utilize many threads for things like DB thread pooling etc.)
- TylerE 6y ago
- waynesonfire 6y agoi'm not a web developer but enjoy paying attention to this space from the sidelines. elixir and phoenix are wonderful. the phoenix liveview is a fantastic piece of technology; it moves the processing to the backend and allows the web application to be developed in the same language (mostly). i just recently discovered microsoft blazor and it seems like it's an even better improvement. compared to liveview, the computation is moved back to the client while the development experience is still a single language. there is no more javascript (at least that's the claim) and the platform takes advantage of webassembly to deliver a high performance UX. really compelling stack. I hope it continues to drive the innovation in web development. I'm so excited to see the javascript eat dust. Maybe light at the end of the tunnel to a horrible 10+ year period of web development.
- devoutsalsa 6y agoI'm an Elixir developer, and I love the language, but I'm not sold on Phoenix LiveView. It sounds really cool, but it seems like there are too many edge cases. How do you scale it horizontally? What happens to user state when a connection is dropped? What do you do when you get a business requirement that hits one of LiveView's pain points? What if you have to swap out your backend for business reasons, and now you have to rewrite your frontend, too? I'm not trying to talk anyone out of LiveView; these are just the thoughts that prevent me from getting excited about it.
- dnautics 6y ago> How do you scale it horizontally If you're using Phoenix PubSub for your message queue, then it scales out automatically over PG2 clusters.
- ashton314 6y agoThere is now good support for keeping the data cashed client side, so that if your connection does drop, it can be restored once the connection is reestablished. That used to be a pain point, but as far as I have seen, it has been pretty well fleshed out now. This all happens mostly automatically, so you don’t have to worry about it. I think it’s just a parameter that you set to “true“.
- joelbluminator 6y agoOh no same crap of mixing hash symbol and string keys as in ruby? You didnt have to borrow that Elixir! Does Elixir also have HashWithIndifferentAccess?
- ironmagma 6y agoHonest question, why is this a problem?
- joelbluminator 6y agoJust google HashWithIndifferentAccess...
- e_proxus 6y agoI get a feeling that it is just a band aid because of unsanitized data and sloppy coding practices. If you subscribe to the philosophy of sanitizing and validating user data on the edge as soon as you receive it and then stick to using whatever data type you decided on, this is much less of a problem (any mismatch in runtime would then be considered a bug).
- praveenperera 6y agoElixir does not have HashWithIndifferentAccess
- bglusman 6y agoNot built in, and not remotely suggesting anyone use this, but as an experiment I did build this a few years ago as a toy/to play with a few ways it might look if we ever wanted something similar.... https://hex.pm/packages/indifferent_access https://hex.pm/packages/indifferent_access https://github.com/bglusman/indifferent_access https://github.com/bglusman/indifferent_access (see also https://github.com/vic/indifferent https://github.com/vic/indifferent )
- regulation_d 6y agoTypically string key maps should exist only at the edges of your system, but they are still often necessary when you're interacting with the outside world. Params in Phoenix come in as a string key map because the atom table does not get garbage collected, so where you don't know what keys may be passed in, string keys are necessary to avoid the risk of running OOM. That said, once I know the shape of the data I'm dealing with, I pretty much always convert to an atom key map as quickly as possible. If I see a string key outside of the context of a controller or worker, I am immediately suspicious.
- mstipetic 6y agoI have a dream that one day most of our software will be built with something like elixir and most of the saas products we're using now (octa, zapier, newrelic...) will be just installable modules with a simple api
- nichochar 6y agoI wrote elixir for a couple years in a high scale environment, and I agree with OP on most of what he described. My favorite aspects, ranked: 1) immutable data / actor model paradigm 2) mix (super modern build tool that does it all) 3) pattern matching
- JediPig 6y agolast hype train i joined, was scala... this language reminds me of scala... a HORRIBLE developer experience, yet we zerglings are happy to be lemmings to someone's "best idea evah" This brings up the pain of scala... only this time im not going to join the fan club.
- nesarkvechnep 6y agoI wish more Node.js people shake off their Stockholm syndrome and check out Elixir and Phoenix.
- heipei 6y agoLet me tell you the single reason I haven't switched to Elixir yet: I develop backend and frontend (SPA) so I'd rather just stick with a single language and library catalog. It helps that there's plenty of libraries in JS land too. I would love to just write elixir code but at the end of the day I feel sticking with node+browser js is the more pragmatic choice right now.
- void_mint 6y agoIsn't phoenix meant to remove the JS dependency on FE dev? (Not arguing with any of your points btw, JS is matter-of-factly more popular and pragmatic).
- dnautics 6y agoI just implemented a thing for work in very bare Phoenix Liveview. It integrates with Plaid. I definitely needed hooks and about 200 lines of JS to get it working. You can't completely kill JS, yet, unfortunately.
- innocentoldguy 6y agoWas it your integration with Plaid that required the 200 lines of JavaScript? I've spent the last year building out a web application for service providers to use to manage disaster recovery software for multiple clients using Elixir, Phoenix, LiveView, and TailwindCSS. We haven't used a single line of JavaScript code, including for the Tailwind components that typically rely on JavaScript to function. LiveView has been able to handle it all.
- dnautics 6y ago
- datavirtue 6y ago"Elixir is not an object-oriented language. We practically only write modules and functions. This helps tremendously in understanding code..." Sign me up. I hold hope that Elixer is the thing that starts pushing the knife into OOP. Microsoft has added a ton of features to make functional style a thing in C#, and nearly everyone hates Java...so maybe the stars are aligning.
- innocentoldguy 6y agoAgreed. OOP is obnoxiously convoluted at times and—I feel anyway—never fully delivered on its promises of reuse. I've been using Elixir for about five years now and I never want to write another line of OOP code. I don't care what language it is in.
- connorlay 5y agoThis has been my experience as well. I left Elixir for a brief stint with Kotlin, a modern OOP language, and it was jarring how many abstractions and incidental complexity I had to wrangle with to be productive and ship well-tested features.
- sbaildon 6y agoBig fan of Elixir. First and third party libraries are typically very high quality; community support is great; and documentation is best in class. Right now, I’m trying to find a way to speed up builds in CI because they’re the biggest bottle neck to deploying. Building an umbrella with 5 apps, 3 of which are phoenix, leveraging parallelised docker buildkit, will still take 8~ minutes.
- emerongi 6y agoInteresting. Elixir builds are the fastest builds in my CI pipelines. I make sure to cache the builds/ folder; usually only a small amount of files need to be re-compiled, which is very fast. This was actually improved even further in Elixir 1.11 [0]. Compared to TypeScript + React and Java, Elixir build times are significantly better. [0] https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md#compilation-time-improvements https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.m...
- AlchemistCamp 6y agoIt's always interesting to read these and I completely agree with the author's comments on productivity (both on Phoenix and Rails). It's a major reason why I learn and teach Elixir, even though it's niche. I genuinely want the skills! One thing to that stood out was how the author found deployment easy, the same as I first did 5 years ago: > "The deployment of Phoenix can be as easy as copying the Mix release I already mentioned to the remote server. You can then start it as a systemd service" I was using Distillery to make the release, but the workflow was virtually identic. Back then, the command to make a Distillery release was even "mix release", just as this author types for Elixir 1.9+ mix releases now. > "Of course, you can make a light way Docker container too, but maybe you don’t even need to. Mix releases are entirely self-contained (even better than a Java’s JAR)!" Also true!
- iudqnolq 6y agoI've found the release story to be lacking. For example, the suggestions I've seen for automatically running migrations after launch can blow up if you have traffic between the deployment start and the migration end. Even if I accept downtime, I've found mix annoyingly low level.
- AlchemistCamp 6y agoHow do you run database migrations on Rails, Laravel or whatever your framework of choice is?
- mrtweetyhack 6y agoWhat about Crystal?
- connorlay 5y agoAt work I am building a new internal project in Phoenix Live View and the developer experience so far is sublime. The entire Elixir ecosystem is an absolute joy to use. In the early life of an application, you get the incredible productivity of Ruby on Rails, while building on the battle-tested OTP platform that can scale with your business. The language itself combines the best of Erlang, Clojure, and Ruby all under one roof.