Build a real-time Twitter clone with LiveView and Phoenix 1.5
phoenixframework.org
phoenixframework.org
Elixir is one of those languages where everything has been done perfectly as of the time of this comment. When I say perfect, I mean, there has been never once in my career where I hit a roadblock due to the language's limitation or complexity or flawed assumption. I faced this with other languages, but not Elixir.
I'm currently a full time consultant writing, teaching and deploying production apps for clients in Elixir. Most of my apps have served my clients well beyond my contractual agreement. It's almost deploy and forget because of Phoenix. It also scales amazingly well. It's extremely performant.
I just re-wrote the entire crappy mess Wordpress core in Elixir and enjoyed the process. In any other language, I wouldn't be saying the same. It's really an enjoyable language that forces you to rethink the way you write code. Don't be put off by this statement, I mean that in a really good way. And once you start thinking interms of functions, you just won't touch any of those terrible OO programming paradigms (Eg. writing for loops, nesting conditionals, etc.). You will start writing maintainable, beautiful code.
You will appreciate Elixir a lot especially if you have a background in horrible programming languages like Javascript. You will literally start finding ways to use Elixir in your entire stack like I am. It's that good.
Enough said. Give it a shot.
That sounds useful. Do you plan to make a product out of that?
Edit: Saw the link to your blog below https://medium.com/build-ideas/
They hit a sweet spot. Enough rigor, enough limitation, at the language level, to force you to do things "the right way" for a broad swath of problems (there are certain problems they're poorly suited for), but enough simplicity and freedom to keep a minimal learning curve, and minimal runtime complexity to figure out issues.
The focus on fault tolerance also means once you learn to use the app structure, with supervisors, you mostly have just one concern for reliability ("how do I start this into a known, good, consistent state?"), rather than hundreds ("what happens if -this- fails? Or that? Or that other thing?").
Haskell and Scala both have a huge surface area to learn before you're productive, let alone anything approaching fault tolerant, and even after years of use, there's still a lot of hidden gotchas with them. I've seen teams take Erlang, and their very first project just...worked. None of their lessons learned caused production issues, and no weirdness; the three issues that made it to prod I can even think of were, variously, one that wasn't user facing (just a log entry indicating something wasn't handled right; supervisor took care of it), one where performance started to slow (and it was due to having written an O(N^2) algorithm accidentally, and not testing at higher loads than production), and one where a low level C driver made an unnecessary reverse DNS lookup that, when the caches flushed, caused things to hang, which became an issue when load increased, and which should have been circuit broken (but which instead caused a failover to another node).
I've never had that experience with another language. The ramp up time to productivity was longer, the production issues caused by us missing something about the language were more frequent, the production issues caused by us failing to expect or handle a failure condition were more frequent, etc.
That said, Elixir and Phoenix do raise the bar a little. Elixir has a larger surface than Erlang (only a few concepts, but a lot of ramifications when it comes to macros if you haven't used them in other languages), and Phoenix is reliant on a fair bit of magic so you need to read the docs and it may take a little bit of work to feel happy with things. But even when I knew nothing about it, picking it was easy because of the experience I had with Erlang.
Thank you for this comment. I have used Elixir for a couple of years and is a concept I have always understood but have never been able to explain coherently and succinctly.
In contrast, Elixir is super simple. I can describe the language in a single HN comment. Everything is just a function and they're inside modules. That's pretty much it. When I was picking up Elixir, I started off writing an E-Commerce platform from scratch with Elixir. When I was about to finish it, I was thrown into a 8 month long PHP project. When I was finally done with it and returned back to work on my E-Commerce project, I was able to just open up the code in a text editor and immediately understand what was happening - without having to re-learn the language. That is a the "Joy" part for me.
One more "Joy" of writing in Elixir is you don't need to worry about memory usage or performance that much. It's pretty efficient unlike Ruby or PHP even. So, I can just throw this entire application in a $5 Digital Ocean droplet and watch it handle insane amounts of traffic. And this is without optimizing anything. You will probably able to squeeze more with caching, optimizations, etc.
As for re-thinking the way you write code, it's mostly to do with pipe operations. Piping was a new concept for me jumping from Ruby. It's absolutely powerful, concise and productive. In Elixir, if you don't write good code, the compiler will warn you AND show you examples of how (and sometimes why) it should be re-written. Eg. If you write a nested case statement which many people subconsciously may do coming from OOP backgrounds, the compiler will ask you to re-think your code. And stuff like this really challenges you, but actually doesn't do anything destructive to your code - your code will still compile and function, but you will feel that tingling inside - "Hmm, maybe I should consider re-writing that?"
THAT is the balance. Before Elixir, I also used Scala. Took me 3 months to fully learn the language from the 700+ pages book on Scala. I absolutely love Scala and the JVM. It's powerful, but there's just too many ways to do the same thing in Scala to keep track of. So, it goes back to my first point on looking at the language after 6 months without the need to re-learn it. I would still try Scala at some point because JVM is very powerful. But, will it replace Elixir? Absolutely not.
I'm not affiliated with them in any way. I'm just a happy customer.
https://elixir-lang.org/learning.html - Start here. It starts off kind of abstract, and then works its way into the concrete (from my experience) -- but is very easy to pick up.
> What major sites?
Last I heard, Discord was serving ~5 million concurrent users, and that was well before compelled isolation.
Bleacher Report is also using Elixir, and serving something like 100k requests per minute just to mobile clients.
Bet365 handles as much as 100k monetary transactions during a big sporting event like a Champions League final.
On a smaller scale Feedback Panda very successfully bootstrapped to a 55k MRR SaaS and was aquired in under 2 years: https://youtu.be/vaXp81OxxK0
Edit: Not to be too self-promotional, but AFIK I've created more free Elixir-learning screencasts than anyone on YouTube. I cover a pretty broad range of topics from total beginner to some fairly niche things: https://youtu.be/z1nKbzZiRtY
Besides what was listed already, if you're looking for info on people running Elixir / Phoenix in production there's this podcast: https://runninginproduction.com/tags/phoenix
One guy was pumping over 7 billion log events a month through it.
Another one (remote.com episode) serves 100k+ daily requests.
Each podcast episode goes through how the app was built and how it's deployed at a high level, but still has enough details to apply those things back to your own projects.
With that said, if anyone is running Elixir or Phoenix in production and sees this and wants to be on the show, just head over to the above link and click "become a guest" on the top right. I'd love to have you on, both big and small sites are welcome.
Here are a few pain points I've ran into: 1. Typespecs leave something to be desired compared to other type systems 2. Maps vs structs and easily using one in place of the other
Things that my team would like to see: 1. Components in addition to templates as a first-class citizen in Phoenix. My team loves React because of the component model even though we hardly use an insane amount of interactivity.
Surface is a server-side rendering component library that allows developers to build rich interactive user-interfaces, writing minimal custom Javascript.
Features: * An HTML-centric templating language with built-in directives (:for, :if, ...) and syntactic sugar for attributes (inspired by Vue.js). * Components as modules - they can be stateless, stateful, renderless or compile-time. * Declarative properties - explicitly declare the inputs (properties and events) of each component. * Slots - placeholders declared by a component that you can fill up with custom content. * Contexts - allows a parent component to share data with its children without passing them as properties.. * Compile-time checking of components and their properties. * Integration with editor/tools for warnings/errors, syntax highlighting, jump-to-definition, auto-completion (soon!) and more.
And in general Erlang and Elixir have very little automatic type conversions, if any.
But maps and structs are interchangeable, I don't get why using one or the other would make your GenServer code any different. A struct is just a map with an additional field called "__struct__".
Thank you.
This is pretty amazing praise! Are many of the other languages you've used strongly typed? That's the thing that gives me pause - I feel like I rely on the compiler a lot in languages where it can do a lot for me, and that I'd be really frustrated managing a large project without it.
I'm not sure what other languages you have a lot of experience with, but does anything in Elixir stand out to you as the reason dynamic typing works well there? I think dynamic typing is the main reason I nod along with "horrible programming languages like Javascript", for instance.
There are trade-offs.
In my case I left Java for Ruby for web programming in 2006 because working with Rails was infinitely easier than working with Structs. I didn't even know that Ruby was a programming language before Rails.
As someone who has been writing Elixir professionally for 4-ish years, and who is otherwise about as big of a proponent of static types as is possible, this is simultaneously my biggest critique of Elixir, and also a critique that has ended up being more theoretical than not. I wish that it were statically typed, but in practice that hasn't been slowing me down.
Part of the reason for that is that while Elixir is dynamically typed, I've found that it's possible to pretend it is a statically typed language if you squint just right. By that, I mean making judicious use of typespecs [0], dialyzer [1], Norm [2], and just generally constraining the way you write code to mirror the sorts of code that you'd write in a language that offers algebraic data-types, like Haskell. I've been meaning to put together a blog post on what I mean by this, because I often hear people talking about how unusable Dialyzer is, so I feel like my team is a rare example of a large production app that requires that Dialyzer typechecks on every build. This makes large-scale refactoring of our app almost (but not quite) as easy as it would be in Haskell.
The macro system in Elixir also means that it's possible to write libraries like typeclass [3], that offer compile-time guarantees (using compile-time property tests!) that your implementations correctly implement a given interface. I think that as the language evolves, we'll be seeing a lot more examples of macros that move runtime logic into the compilation step, to offer compile-time guarantees and safety. For example, a few weeks ago, I prototyped an experimental library in a few hours that added support for compile-time OCaml style parameterized-modules. [4]
Obviously, all of these techniques don't get you quite as far as proper static typing would (though the Whatsapp team is working on static types for Erlang! [5]), but the rest of the language and the ecosystem is just so well thought out, that I've been okay with that!
[0] https://hexdocs.pm/elixir/typespecs.html
[1] https://github.com/jeremyjh/dialyxir
[2] https://github.com/keathley/norm/
[3] https://github.com/witchcrafters/type_class
And I totally agree with you here:
> I've found that it's possible to pretend it is a statically typed language if you squint just right.
My Elixir code tends to use a lot of pattern matching on structs. It's not real static typing, but it gets me a lot of mileage!
[0] https://gleam.run/index.html
[1] https://gleam.run/faqs.html#how-is-message-passing-typed
Type checking unrestricted message passing would be difficult, but I can imagine a subset that's typeable.
> Type checking unrestricted message passing would be difficult, but I can imagine a subset that's typeable.
I'd love to see a discussion on this somewhere. I can totally imagine a world where it's true that "yes, you can't send messages of type X because the receiver can't pattern match on them in the way you expect, but what you're really trying to do is Y, and you _can_ send messages of type Z that accomplish Y."
We have fully type safe message passing, we just don't have any special syntax for it. I'll update the documentation to make this clearer.
> I'll update the documentation to make this clearer.
Thanks! Much appreciated.
In practice this is enough for the vast majority of applicatinos, and messages with runtime checks (like in regular Erlang) can be used for the other situations if required.
Not disagreeing with you, I guess. It was just surprising/interesting to read.
Sadly I can't find the quote...
What you've said matches my findings. Messages can be typed, however hot code upgrades cannot be. For Gleam we've sacrified hot code loading in exchange for types, which I think is a good trade for most use cases.
Erlang/OTP was designed for systems where the amount of acceptable downtime is 0, you don't want phone calls failing because you have to fix a bug, the solution is a system where you can replace parts of it running live, if you replace a module all processes currently running it will still work normally but any new call to the module will use the updated version of it.
https://blog.appsignal.com/2018/10/16/elixir-alchemy-hot-cod...
We could probably do hot loading in development using type assertions fairly happily.
Quite an interesting set of constraints!
There’s a lot of problems introduced by that.
That being said, with the tools I described, you still have type annotations and automated type checking, so the documentation benefits of static types are still present.
My other huge gripe about Elixir when I worked on it last year was lack of IDE autocompletion. This to me is a the #1 dealbreaker in working with dynamically typed languages. Im a horrible speller and having to run my program every time just to find out that I missed a capital letter somewhere in my code is infuriating.
Has Dialyzer and IDEs (VSCode I assume) gotten good enough yet to have decent autocomplete support? When I was using Elixir with WebStorm the experience was less than optimal.
That said, I'm head-over-heels for Elixir. As for autocomplete and such, there's a pretty good project for vscode called something like "Elixir LSP (fork)". Be sure to use the fork version, it's a continuation of the old stale original extension.
In more general terms, the `elixir-lsp` project is pretty solid (and lies underneath the VSCode extension, FWIW), and I've had good luck with it so far in neovim with CoC + coc-elixir.
https://elixirforum.com/t/introducing-elixirls-the-elixir-la... The fork will probably be deprecated soon
I remember thinking, "This feels messy..." but not really knowing why. And I was brand new and barely a developer!
But I think you nailed it. It's because of the Erlang continuity.
Also worth noting (because Elixir was strange and new for everyone at some point) that a lot of what used to be mind-boggling to me in earlier versions of Elixir/Phoenix have become relatively commonplace when dealing with things like React or modern Javascript.
If you've ever handled a JS promise for something as simple as a `fetch()` query and processed results, you _already understand_ how to build code in functional components.
There's much less difference between
fetch(url)
.then(results => doSomething())
.then(results => doSomethingElse())
and doSomething()
|> doSomethingElse()
than it looks like at first blush.It's good to know that there exists a way to do this natively now though.
This sort of absolutism does nobody any favours. Functional zealotry is every bit as bad as OO zealotry.
Including GenServers? I find writing GenServers to be needlessly painful. Their syntax is one of my least favorite things about Elixir.
You can add your own abstractions with macros on top of that if you like.
That is interesting.
I've gone from Geocities pages to ASP Classic, PHP, WP, Rails, Flask and have been dabbling with Elixir and Phoenix for a bit.
So far LiveView (and some bits of Elixir in general) has been the only time in my career where I felt like I'm seriously struggling hard to understand how things come together and how to solve real but fairly common web dev problems without asking for help (mainly with LV). I've had to ask for help on IRC / the forums an embarrassing amount of times. Where as with Rails and Flask almost everything except the most crazy problems were solvable with a little bit of Googling and self exploration.
Now, I'm not saying Elixir and Phoenix is bad at all. I'm still happily using it to build my next big project (for all of the reasons that everyone else uses it for), and the Programming Phoenix book is a great learning resource for building regular web apps with Phoenix, but there's nothing like that for LiveView.
But on the bright side, Chris (the author of Phoenix) and Jose (the author of Elixir) are remarkably responsive to help the community. Lots of other folks are super helpful too. That and once things start to click, you can write some really pleasant looking code and actually understand what it does a few months later.
The struggle is mainly around the nuisances of how certain things work with LV and what the implications are of using X vs Y with practical examples. I wrote a forum post asking for help about this the other day at https://elixirforum.com/t/concrete-examples-of-when-to-use-l....
Then there's other things like wanting to do authentication. I know in theory you'll need to create a controller action to create / delete the session and there's phx-trigger-action to submit a LV form to a controller but there's no code examples anywhere on how to pull this off and get a "current_user" like you normally would with a non-LV set up. But authentication is one of the most important things in any app.
And also, it's easy to find help for Flask and Rails by googling because... It's been around longer. LiveView has been GA for less than a year, and even some major shifts have come around (like mount/2 suddenly becoming mount/3 in one of the last releases).
But then I look at the Live View equiv. in other frameworks. All of which came well after Live View since they are modeled after it.
For example: https://laravel-livewire.com/docs/quickstart in Laravel. I'm not a Laravel developer but their documentation is next level amazing and the author of the library even has a screencast series going that is fully up to date where he builds a real app using Live Wire to demo how it works in practice.
I don't even know Laravel at all, but I can skim their docs and get a feel for how to solve real problems like validation, authorization, pagination, and everything else is focused on practical examples and explaining things very well in the process.
But with Live View, the docs are not anything like this. It reads more like a low level guide on the API itself, not how things work in practice and when you should use certain things or how to write common web dev features. After reading the docs, you're left wondering "ok, but how do I get started using Live View in practice?", IMO at least.
There's also the Rails equiv. which is https://expo.stimulusreflex.com/. Besides the docs there's a bunch of real practical examples, with a live demo of how they all work without having to install anything. With Live View, we have an example repo but it's very out dated at the moment to the point where you can't even follow it with the docs and it seems to not be based on best practices anymore since new things were released with LV.
Erlang does it too.
If you want to have state you do recursion and call itself with the updated value.
fn me(iter) -> me(iter+1) end
a = [foo: "bar", foo: "baz"]
Keyword.get(a, :foo) #==> gives you "bar"
a[:foo] #==> gives you "bar"
my_struct = struct(SomeStructWithFoo, a)
my_struct.foo #==> gives you "baz"
But really, this minor, minor inconsistency is near the top of my list of complaints, so... Take that into consideration.Also, if you start coding in Elixir a lot, you will write better Javascript by importing good practices in from Elixir.
They are similar but they are not the same thing and are not to be used in the same places.
Is it as performant as technologies like Django / Ruby?
That said, there are some ways in which Phoenix/LiveView is extremely "scalable".
For example, pushing messages to 2 million simultaneous websocket connections: https://www.phoenixframework.org/blog/the-road-to-2-million-...
... and running on the BEAM gives all sorts of exciting horizontal scaling possibilities on top of that.
I've heard only good things about Elixir/Phoenix, so I'm thinking about picking it up for my next project. One thing about JS/TS is that the ecosystem is well developed, especially on the deployment side. For side projects especially, I like to minimize my dev ops configs and utilize "serverless" type stuff (i.e. Zeit/Vercel, FaaS, etc). I haven't seen much of this in Elixir-land, but hey, maybe that's an area I can help innovate in.
I used liveview in https://readastorytome.com. I posted it here last week and it stayed on the front page for a good few hours. I was concerned about load, so before I posted it I upgraded my $5 DO box to a 4 core box which turned out to be completely unnecessary. The CPU load stayed in the 2-3% range the entire time it was on the front page, which is pretty amazing considering how much traffic was coming in. Funnily enough I came across the livedashboard repo just before I posted it, so I set it up and I was using it to monitor my app live while it was on the frontpage of HN.
The dev experience is pretty amazing - I don't think I would have been able to write this app as quickly and to add new features at the pace I have been in any other language.
So thank you Chris, Jose and the Phoenix/Elixir team.
If anyone has questions about my experience with liveview free free to ask - either here or by email - ben@readastorytome.com
We use liveview + hooks(where necessary) for all of the interactive parts on the site, switching pages, changing books etc...
I also appreciated the twitter analogy. I just couldn't help but think "Wait, Twitter doesn't have 'Update/Edit Post'!" :)
I've heard that Blazor in the .net world has similar goals to LiveView, but I haven't gotten into it much. Can anyone confirm?
I worry that all these other platforms rushing to emulate liveview are missing that extremely critical component of this model. If you aren't certain about what I mean, I suggest watching Sasa juric's "the soul of erlang and Elixir" video where forward progress of the system is unimpeded by a panic or a process that attempts to hog processing via an infinite loop, both are detectable in the running system, and able to be easily identified (down to the malfunctioning function name) in the in-prod system.
Re-rendering templates every time on things that require high interaction also seems very expensive and an easy way to slow down your server when you have multiple users correct? or what I'm missing?
LiveView also uses a long-running WebSocket connection and that reduces the amount of data sent over the wire compared to regular requests/responses, as you don't need to encode headers, cookies, etc.
Finally, if you are worried about latency, you can call "liveView.enableLatencySim(200)" in your browser console, and you will be able to emulate how your application behaves over high latencies.
DHH was right about this stuff long ago in 2012 (mixing server side rendering with interactive JS frontends) even as the software wasn't quite there yet: https://signalvnoise.com/posts/3112-how-basecamp-next-got-to...
The other approach is SSR with React/Vue that hydrates on pageload with something like Next.js/Nuxt.js. https://nextjs.org/
But the Phoenix approach seems better for a more Railsy single framework approach (assuming you don't like writing the entire server side code in JS, which I do not). It's more cohesive and quicker to roll something out.
I currently do mostly Vue with Rails backends professionally but if it was from scratch or rearchitected with Elixir I'd seriously reconsider using full blown Liveview.
My only concern would be missing out on some UI libraries and pure size of community support. But I wouldn't miss getting rid of the super complicated JS tooling set ups I currently use (in addition to rails or trying to jam it through the asset pipeline via webpacker), in exchange for a more centralized approach. I've gotten a bit too used to maintaining the frontend almost separately from the server app and sometimes miss the simple days of being pure Rails.
One additional concern may be portability for mobile with React native. But that only applies to a subset of apps where reuse/cross platform makes sense. Still it was a big reason why these SPA style frameworks flourished like they did.
Here's some information: https://www.evanmiller.org/elixir-ram-and-the-template-of-do...
On the extreme end I have a few pages that plot IoT data where it can take ~3 seconds to do a drop down in LV... Granted the server is serving a dozen SVG plots with a total of ~80,000 data points and performs the server template diff in that time. That’s on a RPi3 "server", which are also processing data, running similar pages on 4-10 browser tabs and running its own web browser. Haven't gotten close to using up the ram. Much of the slowness in that case is due to Chrome choking on that much SVG. I haven’t bothered optimizing the server side by dropping already rendered graphs.
Hope that helps give some insights. It'd be interesting to hear from people running high traffic sites.
People who don't enjoy videos for various reasons would probably like a text version too.
Yes this. I went to the video eagerly looking for a repo link and was disappointed not to find one.
https://pastebin.com/raw/WxH0uAsf
If Pastebin doesn't work for you, let me know and I can get it hosted at a different location.
My apologies if there are any mistakes in this. I'm not familiar with Phoenix, but found this video very interesting, so wanted to make sure it could be shared.
Just out of curiosity (please don't consider this as a feature request, more like a thought exercise), in case you wanted the application to have offline editing functionality, could the framework provide it in a similar manner? having a generic JS handler that manages pushing state when an internet connection is available again and exposing hooks that you can implement to handle data consistency? Of course in this case the data payload passed through sockets would be bigger as you would need some identifiers to make sure for example increments don't get duplicated, and there could potentially be different strategies for solving data conflicts (CRDTs for example). But would it need extra back-end support for this or would it be enough to have engineers manage state through the current handlers?
The funny thing is last I tried to use Google Docs offline, it locked the page in read-only mode, so offline mode even in the SPA space isn't just a given – you're definitely opting in to some necessary complexity.
How does reconnection work? lets say someone is using the site, and you do a deployment, rolling the nodes over. Does live view simply reconnect to another node without any interruption from the user's perspective?
I'm especially invested in this since I've just rolled out an alpha of a project that may incorporate it in the future: https://phoenixigniter.com
One thing I didn't understand from the video is how the :post_updated callback worked. It prepends the updated post to the list of posts. How come that doesn't lead to the same post being double in the list?
The same happens on the client. If the server emits the same DOM ID, the client just updates it in place too.
Writing UI code, in a language/environment that has first class support of pattern matching is like a dream for me. Seriously, pattern matching is sooo good when you don't have fucking classes and objects and bullshit "abstractions" in the way of your data.
Also, if you took a stab at it before 1.5, try it again. This release has all the goodies to make it nice and documentation to go with it... I'm stoked to delete the phx.live generators I copy-pasta'd into my repo from phx master a couple weeks ago trying to get my bearings.
Truly awesome work on this! Thank you so much.
Also, pro-tip, use the generators at least once, even if you have already used live view without 'em, because now there's more or less an official pattern for how to organize yer live code and it really helps.
What about LiveView/Phoenix made the process more enjoyable - let's call it 'less painful'?
1. Tooling, yeah, you gotta have node installed, but that's pretty much the last time you have to touch it. I'm not anti-node or anti-js by any means, but the tooling around them often turns me off. Getting to do front-end work without _having_ to think about 'em is a breath of fresh air.
2. Less duplication of effort. I don't need to define schemas twice... once in the "backend" and once in the "frontend" application. You don't think this is bad until you spend two hours adding a adding, removing, or changing a simple property to your application because you have to update the backend, the backend's api docs, its tests. Then on the frontend, adjust the schema, adjust the frontend tests, and finally see if it's working.
3. Faster iteration. I prepare a new context, and can immediately consume it in a view. Views are reloaded instantly when changes are made during development reducing the time it takes to get feedback and increasing how fast I get shit done. Also less duplication of effort REALLY helps here...
4. We (at least me) got S(F)PA idea totally fucking backwards. The idea isn't to make you're entire web site a Single Fucking Page Application, but to make individual (single) pages which NEED TO function like applications do so... Quintessential examples that do _NOT_ need an SPA: a fucking FAQ, about, or contact pages. In fact, having an "application" on top of them is more burden than not.
5. CSS is really powerful these days and provides a lot of what the 2008-2012 JS movement was trying to do. If I combine that, with being able to re-render only part of the page, I've got almost the entire flexibility of what SPAs offer with almost none of the complexity.
6. Going to a new page, and causing a page refresh, but totally knowing the next page isn't going to be broken because of the previous page's state. Page refreshes are awesome. Growing up on 28.8k that wasn't the case, but ever since I got above 10Mbps its really not something I ever even notice (though I do notice when pages are broken that shouldn't be because they're SPAs and not just fucking content).
I could probably keep rambling but I'll stop here...
I built a few things in Phoenix in the past, and while the core framework is very simple and elegant to use, I recall having to write my own file uploading library because the one that existed had almost no documentation. This made me really hesitant to adopt Elixir / Phoenix stack for any projects I'm serious about.
I was hoping there was a world where most of the old rails community moved onto phoenix, but in the time this project has been around, it seems the backend web stack has really fragmented into a multitude of Node, Go, python, etc, while Phoenix hasn't really grown its mindshare.
For former Rails / Django devs who has made the switch: what are your thoughts on this?
The lack of magic is nice too. For example, it's easy to add a new custom Plug (that you wrote yourself) to your pipeline without resorting to third-party libraries to help you navigate all the magic and boilerplate you'd otherwise have to deal in other frameworks.
you could do the same potentially for any rails or laravel package you wanted for phoenix, obviously language constraints would be different and programming paradigm. It'd take a little bit but you could port things over, if you package it up - even contribute to the community growth.
I think choosing a framework solely because of available packages isn't a good thing. I mean nodejs probably has the most packages in it's ecosystem but a lot of them are pure shit.
As someone else already pointed out, many of the solutions in Elixir are significantly more simple to just "roll your own" rather than have to worry about pulling 50 gems.
Yes and no. The larger the number of dependencies you have, and the larger number of maintainers that are behind them, the more chances you have of one of them containing malicious code.
I think you're pretty safe from Phoenix or Rails or NodeJS getting owned because so many people work on them. But one of the thousand small packages you use may belong to someone careless or malicious.
Didn't really have any issues. There were maybe one or two gotchas but they were explained clearly by the docs (appending vs updating elements) and I was able to get it sorted easily. That whole app took a couple days, but more than half the time was wasted on iOS not supporting mp4 and webm formats for the animated shots in the chat messages. Unfortunately, liveview does not fix Apple's stupid walled garden.
Overall it was a great way to minimize the javascript involved. It doesn't make sense for certain types of apps, but it really adds a ton of value and saves a lot of time when the use case is right. And it performs really well. Loading and rendering a chatroom full of messages (with animated gifs in each message) makes a couple requests and happens in less than a second.
And combined with phoenix presence it was like...5 lines of code to add realtime online/offline statuses for users. Super cool.
What are some of these use cases?
basically if you got an application which wants to connect everyone to each other in real time, thats a perfect usecase for the BEAM. so chat rooms, live-feeds, comments, video/audio conferencing, etc.
and thats also exactly where phoenix excels in my opinion as a occasional user. (never professionally though) quick and seamless communication between silly amounts of people with almost negligible amount of resources while being error tolerant to an extreme (functional, so almost no state)
just try it out on a weekend. its definitely worth it just to see how web-development couldve been. you'll probably go back to the old way, because thats just how you earn your money and where you already have your expertise... but its definitely amazing to see how easy it can be
However, 1) you can add custom JS using LiveView's hooks, which might be enough for very simple offline behavior and 2) many SPAs don't work offline either.
If offline support is a major part of your app's design, LiveView isn't a good fit. But you could still use Phoenix Channels (the building block underneath LiveView) to provide fast push updates to your client. See the channels docs for an idea of how they work - https://hexdocs.pm/phoenix/channels.html
I'm a big fan, Elixir + Phoenix is excellent enough, and LiveView is what really sealed the deal for me as the perfect web development stack. It's simple, it's fast, it works. Sure, it has a few rough spots that have to be worked around when you start to push its limits, but as this blog post showed it's perfect to quickly have a working web application by completely skipping having to write client-side code. I developed a couple of prototypes and single-use applications in hours that with any other stack would have taken me days. Hell, I'd argue that in some cases it took me less time to complete my app with LiveView than it would have taken me to setup Webpack with Frontend Framework.
I don't believe it to be a silver bullet for sure, and it has to prove its worth at scale, but it gives excellent results with little effort, and honestly the reduced tedium is worth it on its own.
Also, protip: try LiveView with Tailwind CSS.
https://shankardevy.com/phoenix-inside-out-mpf/#mastering-ph...
I found it more approachable than the PragProg book. Helps if you've dabbled in Rails a little bit.
I wrote out a quick analysis of the details there along with some looking into the backing code in text format here: https://github.com/SaturnFramework/Saturn/issues/228#issueco...
We mostly see threads fawn over Elixir and Phoenix, have you experienced any downsides to switching? Anything you miss from Rails?
I'm convinced to give it a try after that demo!
To someone who uses Rails/Django with React, I'd describe LiveView as something that offers pretty much everything you're used to, but with the React part consolidated with the server-side of things.
I've been playing around with LiveView since it came out, and have been using it for 'serious' work for the past year or so, and I still regularly discover ways in which this setup simplifies things, makes development faster and more fun, and saves me from various potential security flaws or 'busiwork'.
Imagine that your store (Redux, whatever) and view (React) ran in the same place as your backend.
Direct access to the database and the rest of the backend, no need to carefully consider whether it's really worth it to increase your js payload with library x, no constant context switching, no building and maintaining of, essentially, two completely separate applications, no need to make sure your API endpoints are properly versioned, or that they don't expose data that shouldn't be exposed, or that they send only the data you need. Little to no need for rube-goldberg js pipelines, and significant less time spent dealing with synchronizing state between server and client.
I'm probably forgetting some other advantages.
There are some things where LiveView doesn't seem ideal, but I've found that even in those cases I prefer using LiveView wherever I can anyways, and then I do the specific javascripty bits wherever I need them.
Some other things to consider are that Go's concurrency model is quite bloated when compared to Elixir's, Go uses public memory for its goroutines vs. Elixir's private memory that protects processes, Go uses cooperative multitasking vs. Elixir's preemptive model, and Go's dependency handling is absolute rubbish. Elixir's process supervision is amazing and Elixir's pattern-matching allows you to write easier-to-read and more maintainable code, in my opinion.
While both are good languages, I've personally found Elixir > Go.
I'm currently planning a SaaS project and had settled on go, but this discussion is making me wonder if perhaps Elixir is the better choice.
OPT, which is how you build supervision trees and other more complex Elixery things, is tricky at first but reading through Designing Elixir Systems with OTP, by James Edward Gray & Bruce A. Tate, and The Little Elixir & OTP Guidebook, by Benjamin Tan Wei Hao should clear it up fairly well.
This is highly subjective, of course, but I've written code in C, C++, Pascal, Basic, Python, Perl, Ruby, JavaScript, Go, PHP, Java, C#, Clojure, Scheme, Cobol, and Pick Basic (of all things). Elixir has been my most favorite language so far.
My anecdotal view of the marketplace is that Elixir recruitment emails tend to come from startups looking for their 2nd or 3rd dev, usually full stack, and the salaries are nothing special. Go recruitment emails tend to come from bigger companies looking for backend devs, often hoping for kubernetes experience too, and the pay is higher.
I built an internal service with LiveView at work and I loved it. I gave a presentation about how it all works and was hoping it would catch on. It didn’t. The front end team would probably mutiny if we told them to give up React and level up their LiveView skills.
If I were running a web business as a solo founder I would 100% want to use LiveView. As a dev on a larger team that already has specialization it’s a tougher sell.
You shouldn't really compare it to React, you should compare it to your whole stack, and see how a lot of the code and the worries just kind of go away.
This is much like how it used to be with classic server-side rendered Rails/PHP/Phoenix... except with LiveView you can update part of the page running on the client, in response to events coming from the client without a page refresh.
HOW do you manage to broadcast only the minuscule change of a number to all of the connected clients with server side rendering? I'm trying to wrap my brain around it.
Looks to me hours of work and learning got abstracted as under the hood "magic".
It's like saying: Oh, so I've been weight training for the last 17 years and I should tell you Olympic silver is not too hard, see?
Am I right in my thinking? or is learning to be this proficient with the framework not as time taking for a novice developer as I think it to be?
Is it encompassing a lot of magic? Yes. But the quick growth in mindshare that Ruby on Rails attained back in 2005-2010 (part of which it still retains) was due to how easy it was for a novice developer to pick it up and build something useful. Pick it up and understand all the pieces, no. Phoenix is less Express/Martini in nature, more Spring/Rails (but more pleasant than either of those to work with, I would contend, but again, that's opinion).
When you combine a couple of those bits together, you end up with this.
The only modern web problem that Elixir isn't ideally suited for is heavy number crunching. Otherwise it gives this amazing balance of efficiency, scalability, reliability, maintainability and capability that can't be replicated in any language that has a shared memory model.
A lot of people find Elixir more approachable than Erlang. But I wouldn't be surprised if Erlang is technically simpler and as such potentially easier to learn. The syntax is quite foreign to most people coming from more conventional languages while Elixir reads and writes fairly conventionally.
Now Phoenix LiveView does a lot for you, so I wouldn't dismiss the claim of having some magic in there. But once someone starts to get familiar with the stateful approach the model is fairly simple and the "magic" is less mystical. A lot of the things you don't need to pay attention to would be optimizations in markup and templates and how the JS does its job. That's where a bit of magic happens.
Most of the things you mention sound like things about the language. Which I found to be very approachable and the onboarding documentation to be great.
I would caveat that in a couple of ways.
First, suppose you have a web app where some requests involve heavy number crunching and others don't. In web frameworks where 1 request ties up 1 OS thread, a burst of heavy requests could gobble up all your available connections. Phoenix would use one cheap BEAM process per request, and the BEAM's preemptive scheduler would ensure that other requests are answered in a timely way and that all the heavy ones continue to make steady progress. So although the heavy requests might be completed more slowly than in another language, the overall system would remain more responsive.
Second, if you have need for heavy computation or data structures that work better with mutability, it's possible to (eg) use Rustler (https://github.com/rusterlium/rustler) to implement that part in Rust. See https://github.com/rusterlium/rustler for a story about doing this.
Phoenix has a sprinkling of magic or syntactic sugar through macros and stuff but the step between Phoenix and LiveView is not that mystical to me.
I have taught a novice developer, not yet out of 2-year school for web dev, to use Elixir and the Phoenix Framework. I really should interview him about that. Write something up.
I would say that Django does more stuff under the hood than Phoenix. But they are fairly different vehicles.
and it uses uPlot [1][2] in the metrics panel :D
However, does it have a mature ecosystem now ? What about deployments and tools around it ? Does it work with generic web servers like Nginx or does it run its own http server ?
The deployment topic is wide, so the answer will depend on your favorite ways to deploy. If you are using Heroku or another PaaS, it has been very straight-forward since ever. If you want to ship a self-contained executable or a Docker image, the language has standardized on the tooling for assembling those in the last year or so (they are called releases). It was always possible before, just not standardized at the language level.
It runs its own http server but you can easily put it behind nginx, websockets included, by using the reverse-proxy settings. Here is an example article: https://dennisreimann.de/articles/phoenix-nginx-config.html
The tooling and developer experience in Elixir is first class and the ecosystem is highly mature.
I've done plenty of Django and Flask and I'd rather work with Phoenix. I still like Django plenty but only time I'd pick it is if I think the admin might save me copious time or if there is something else tying the project to Python, such as machine learning.
I agree that it's fun to witness that level of passion and it makes me happy that Chris is so amped about this.
Phoenix -> Elixir
Rails -> Ruby
<div
phx-hook="MyChart"
data-days="<%= Jason.encode!(days(@balances)) %>"
data-amounts="<%= Jason.encode!(amounts(@balances)) %>"
>
<div phx-update="ignore">
</div>
</div>I might be too greedy, but if there could be a solid JavaSript support Elixir/Phoenix just like ClojureScript that would be perfect. Phoenix and Liveview are great, but I really hope it can extend its reach to React Native and Electron so that we don't have to write too many extra things for those platforms.
Implementing runtime for Elixir in JavaScript is quite challenging IMO. Kudos for Dockyard trying to tackle this.
https://dashbit.co/blog/a-new-authentication-solution-for-ph...
ueberauth is one of the most fully featured with support for a ton of different authentication schemes (https://github.com/ueberauth/ueberauth)
But there are lots of other things that integrate with Phoenix / Plug (https://github.com/h4cc/awesome-elixir#authentication)
Thank you Chris and Jose and all those who were and are involve with Phoenix.
It runs on the same Erlang VM that Whatsapp used to scale to hundreds of millions of users on under 30 machines and very few employees.
For rails people who are unaware there is already a lib that has copied this approach.
That being said why would I pick this over go or scala for example ?
I’m having a hard time finding a decent argument in the thread bedside syntax.
Can someone elaborate?
Can you rebuild this demo in Go or Scala in 15 mins or in 1 hour, correctly push any updates to the client while maintaining the robustness and sharding across the cluster? Writing stateful services correctly is very hard using an average web framework.
I need at least 1 day to implement the same in Go or Scala, only the functionality but neither the clustering nor the optimization. And I'm considering I myself a functional programmer that is very familiar with Scala.
In a nutshell, temporary state in the client (URLs, forms) are resubmitted on reconnect. The server state is typically backed by a database.