Hacker News new | ask | show | jobs
by nickjj 2556 days ago
If anyone is on the fence on learning Elixir / Phoenix (Elixir's most popular web framework library) please do yourself a favor and give it a shot. If you're on a time crunch and want the best bang for your buck on "why bother learning yet another language to write web apps in?" then watch this talk called "The Soul of Erlang and Elixir": https://www.youtube.com/watch?v=JvBT4XBdoUE

I'm not affiliated with the language but I just want to throw out that I've been around since the Geocities era as a web developer and I haven't seen a tech stack or platform this well thought out and so in tune with what makes developing (and testing!) modern web applications an absolute joy. There's really something special here. I see myself sticking with it for 10+ years with 0 regrets.

The best part about it is everything is ready today (and was before 1.9 too btw).

8 comments

The Authn/Authz story of Phoenix is a joke though compared to Rails/Devise or Django. The framework authors refuse to ship a first party implementation and instead leave it to the community. Problem is, the ones available are mostly extremely low level (ueberauth, guardian etc.) and you have to spend ages customizing it. On Rails it's literally two commands to set up user registration, email confirmation, password reset. Despite its supposed Rails roots, Phoenix has a long way to go (the greater irony is that the company behind Devise, Platformatec, is also the company behind Elixir).

If you only need basic functionality and absolutely have to use Phoenix, Pow is a good choice:

https://github.com/danschultzer/pow

I can't speak for the Phoenix dev team but the fact that some of the Devise authors are now heavily invested in Elixir / Phoenix and they didn't port Devise to Phoenix by now makes you wonder if they still think the idea of Devise is a good one.

Personally I haven't found auth to be a problem in Phoenix and I have lots of experience with Rails (and using Devise).

You can put together an iron clad user registration + auth system in about 150 lines of app-level code (not including lines of code for the template forms, but with Devise you would end up customizing your own forms anyways). This includes registering new users, authenticating by email + encrypted password, logging in, logging out, session management and having the idea of a current_user in your system, along with a way to restrict routes, controllers or actions to only logged in users. The essentials basically.

I would much rather manage ~150 lines of code in my own project that I fully know and can easily customize than pull in something like Devise which is 6,000+ lines of Ruby and have to configure / override a number of things.

Everyone has their own opinions but I would much rather spend my time developing features for my app than trying to figure out how to customize a massive third party dependency.

Personally I'm rolling with a magic link authentication system in my Phoenix app and it was also around 200 lines of code to implement everything, including configuring and sending the emails out. There's no external libs beyond Phoenix to get it all working (except for sending the emails out, in which case I use Bamboo which is a lib dedicated to sending emails).

As someone who used Devise multiple times and always ended up regretting said choice in the long term, I am actually glad there is no Devise for Phoenix.

In one day I can quickly get something up and running with Guardian and have full control over how my app does authentication. Password reset and confirmation are easily done with Phoenix.Token without a need to touch the database.

Also, authorisation is a breeze on Phoenix. Take a look at Canada: https://github.com/jarednorman/canada - and it is only 10 LOC.

> The Authn/Authz story of Phoenix is a joke though compared to Rails/Devise or Django. The framework authors refuse to ship a first party implementation and instead leave it to the community.

I agree, but it's not unique to Phoenix. In the PHP world the otherwise excellent Symfony framework is only starting to add generation of authentication/authorization, and email confirmation and password reset remains the developer's responsibility.

I see two reasons for this.

1. Frameworks see themselves as building blocks, not RAD systems. When the core framework developers are (mostly) working on APIs they don't see the need for approval/password reset. After all "you'll issue the user with a JWT so who cares about the rest (shrug)"

2. Flexibility to auth with anything. Apparently not bundling a system makes it more "flexible".

I believe (1) to (a) be shortsighted and (b) we need RAD frameworks, of higher-level flexible components that can be bolted together.

I believe (2) is wrong, and bundling standard auth flows does not reduce flexibility: you implement your own if you need something else.

That's partially true because you have FosUserBundle as kind of defacto standard for user facing auth (but yes it's a community package) and many built-in things for APi auth.
FosUserBundle is no longer recommended, and is superseded by Guard. Guard is considerably nicer to work with, and doesn't take long to build the extra bits (password reset etc) but (a) it's not built-in, and (b) if done as a bundle, it doesn't get the same level of support.
>> The framework authors refuse to ship a first party implementation and instead leave it to the community

Maybe for AuthN, but AuthZ is pretty far from the business of a web framework. The framework authors seem, for the most part, to be avoiding first-party endorsement of secondary tooling that doesn't deeply benefit from being first-party. I find it super refreshing coming from Rails where it is either the golden path or good luck.

A lot of the early AuthN libraries seem to target the controller layer, but I've found, having worked on a couple of sizeable Phoenix production codebases, that AuthN at the app domain layer works better. Regular use of channels as an alternate entrypoint to web request controllers means that controller based helper libraries are less valuable. Once you push this logic inside the app domain, it really isn't the business of Phoenix to know or care about it, since you're just working in plain Elixir, probably with some sort of Ecto struct to represent identity.

I would like to point out that it is not only the company but the person behind Devise (ie José Valim). It may means, possibly, that they are not really a fan of what was created with Devise and think the experiment should not be replicated. You know.
My preferred way of learning a new language/framework is watching someone walk through creating a real app in that language/framework so I can see all the folders/files I need to touch and the thought process moving step-by-step. Unfortunately I haven't found much in the way of that for Phoenix, the stuff on Udemy is pretty outdated last time I checked. Any recommendations?
The way I've learned so far was building my own app while skimming the docs and looking at successful open source projects like https://github.com/thechangelog/changelog.com for inspiration and guidance. Basically error driven development and looking up things as needed. Of course also taking advantage of IRC / Slack / Forums when I get really stuck.

But recently I read the Programming Phoenix 1.4 book (written by the authors of Elixir and Phoenix) and it really filled in a ton of gaps and made so many things click together. I can't speak highly enough about it. In fact, finishing that book today is what provoked me to write my comment here. The book might be exactly what you're looking for as like 5% of the book focuses on the super basics and a toy example, but 95% of the book focuses on building up a pretty real app and layering on features as you go. It's also up to date and feature complete even though the book is labeled as a beta release.

By the time you finish the book, you exercise a ton of interesting things along the way (including how to take advantage of Erlang's VM to build features that would be 100x more effort and probably 10x worse in other tech stacks). You definitely don't just build a simple todo app. I don't even want to say what we build in the end because it feels like a spoiler. I only say that because when I hit the last section of the book I had no idea what was coming and was blown away by what it covers. It literally made me smile for hours just thinking about how badass everything is when it all comes together.

Glowing recommendation, I'll have to check it out!
I concur. Programming Phoenix (I read the old version, 1.2 or 1.3, don't remember) and it is simply so well thought and helps you understand why Phoenix is not as magic as its appears in the start.

I also recommend you to try to play with Plug. Things make much more sense in Phoenix after you understand how Plug works.

That's exactly what I do at https://alchemist.camp. Most the videos and all the intro-level ones are free.

I've also put up about a hundred screencasts at http://youtube.com/alchemistcamp.

Looks like a cool site. I'll check it out. My Elixir is Good. My Phoenix is not.
I’m building a side project in Phoenix right now. For me the learning curve is wondering whether Phoenix has a built-in or “everybody does it this way” solution to the problem I’m facing or whether it’s something I should implement myself.

In Rails the answer is always “use this popular gem” and in Go the answer is always “roll your own”. Phoenix is somewhere in the middle.

The good thing about Phoenix is you are not forced to go in any particular convention for everything, you can craft them yourselves from scratch. The bright side of this is you will only every little thing in the implementation and you'll know how to optimize it.
The one time I really want to override something in a Phoenix app was deleting a response header bolted on by Cowboy (I think it was the server header). I couldn't find a work around, so I did something lame like intercept the formatted response and modify it. Some flexibility in that area would have been nice, but it was a pretty niche corner case on a not too important app, so a time crunch hack was my best option.
I'd say you're in good shape, then. Phoenix is really well-designed and doesn't have a lot of "magic" in it.
https://pragmaticstudio.com/elixir

https://pragmaticstudio.com/courses/unpacked-full-stack-grap...

These have been my go-to that seem to fit what you're describing. I hope this helps.

For event sourcing in Elixir this is a very good walk-through: https://blog.nootch.net/post/event-sourcing-with-elixir/

Another example is: https://github.com/AltTracker/alttracker

It's an implementation of fully functional site. The beauty of Elixir is that the code is very readable.

The thing is, nowadays, statically typed languages became so ergonomic, there is really no reason to go with dynamic languages.
I partially agree, but none have the preemptive green threads of the BEAM VM and its amazing tooling around supervisors and worker hierarchies.

Trust me, if somebody puts that in Go, Rust or OCaml -- I'd ditch Elixir tomorrow.

The BEAM VM is just too good. You can have thousands of smaller tasks running in parallel and nothing lags until you hit the physical limits of the hardware -- which 99% of the apps never do.

I think this is right on point. The BEAM is finely tuned for a specific problem and it solves it beautifully in a way that is extremely hard to replicate unless you actually are willing to invest in some kind of run time (which instantly makes you ineligible for consideration in a lot of peoples' minds). Every language that has tried, as far as I know, has done so as an afterthought and obviously does not end up replicating the important parts.

Knowing that, it's perhaps more pertinent to talk about what you can actually bring to that VM. Alpaca [0] could potentially be the solution. Interoperation with the rest of the VM languages and static typing on top of that. I have no doubt that most of the community would simply not use it, because they don't care about static typing, but I have zero reservations about saying it would be a better way to write code for the BEAM in the future.

Without something like that, it's unlikely that I will actually put any code that does more than something like routing messages to other services or the like on the BEAM in the future. Beyond a fairly low number of lines I simply don't trust anyone to write code that does exactly what they think it will do and no more in a dynamically typed language.

[0] - https://github.com/alpaca-lang/alpaca

> The BEAM is finely tuned for a specific problem and it solves it beautifully...

Not disagreeing with you per se but that was true 10 or 20 years ago. Nowadays the BEAM is very solid general-purpose runtime with the best parallelism on the planet attached.

> Knowing that, it's perhaps more pertinent to talk about what you can actually bring to that VM. Alpaca [0] could potentially be the solution.

Realistically, I'd say that ship has sailed. Elixir has a lot of inertia for that to happen at this point. People focus really hard on improvements over Dialyzer (like Dialyxir + improving warning messages), linting, standard formatting, higher-level code generators and what-have-you.

At this point I'd think an OCaml-to-Elixir transpiler that enforces the compile-time guarantees of OCaml and translates them to Elixir code is the much likelier road to strong static typing on the BEAM. I might be wrong though, it's just a speculation.

Most people who point to Elixir's lack of static typing as a weakness, or believe their productivity would be adversely affected by it, do so because they haven't actually used the language.

Anyways, this subject occasionally comes up for discussion in the community. This post sums up my thoughts fairly well: https://elixirforum.com/t/static-vs-dynamic-typing/9824/3

It's a near certainty that I've written an order of magnitude more elixir code than you have and I can say without a shadow of a doubt that elixir's lack of static typing definitely makes it less useful.

Even if you disregard the modeling power that you can get from this there is an upper bound on any elixir project after which any work on it becomes less and less easy to do, as with all languages that lack a static type system. We write assertive elixir code as much as we can, but that doesn't mean that you can actually guarantee anything about a code path that is less traveled.

dialyzer is also not the answer. Oftentimes we'll find ourselves in a situation where dialyzer complains because someone who made a major library simply doesn't use dialyzer. You might wonder why they don't in that case, because it would pick this particular issue up very easily, but the next time you run into some garbage error that dialyzer spat out that you are instantly reminded that you can neither trust it to be correct or safe, so people turn it off.

Elixir has upsides: I think it's solidly the best language for creating servers of different kinds, but it's near useless after you pass a fairly short distance with it. I would absolutely never, in my personal endeavors (as opposed to my working contract) write an elixir server that actually tries to do anything meaningful itself other than just route messages to other servers.

What language would you use to write a server "that actually tries to do anything meaningful"?
Any language with the possibility to express variant types that all can have different structure and have that structure be checked at compile time, properly, will be a better choice for describing simple, medium and complex domains.

Whether or not this is based on nominal or structural typing is less important, because the feature itself only depends on differentiating between what is essentially different cases and having that be done safely and properly at compile time.

Elixir has no satisfying solution to this problem and it likely will never be able to. It is a huge penalty in domain modeling, which is why I personally don't want to use it for anything that actually has to deal with the flow of things.

To some extent I expected and wanted the VM to feel like it makes up for this by being so great that what it does, but there's no band-aid you can use to fix lack of modeling power.

> It's a near certainty that I've written an order of magnitude more elixir code than you have and I can say without a shadow of a doubt that elixir's lack of static typing definitely makes it less useful.

You should really read that post I linked, and do a bit more research on this topic. The consensus in the Elixir community (where many members have written an order of magnitude more Elixir than you) is that static typing would be "nice to have", but is not critical by any means. Your post seems to be an attempt to spread FUD.

I've done all the research I need to, thank you very much, and I was there when this thread was started and much earlier than that. The consensus in the elixir community is hardly relevant when most of the users aren't experienced enough with type systems to know what they're talking about.

If you asked a community of people who primarily have never used languages that don't have garbage collection, they'll likely not understand at all why it could be a bad thing.

Someone who has used a language without garbage collection and is comfortable with basic allocation strategies is very likely to remark that having control of memory allocation and deallocation is very often something that you end up wanting instead of having to re-architect your solution in indirect ways to influence the garbage collector. This comes from having a wider perspective and the elixir community at large does not have this.

Given that the elixir community is also very cultlike it's hardly a productive thing to take what they say as the objective truth.

(I'm not saying this is an outsider at all, I've been a part of the elixir community since 2016. It's not really despite that I am saying these things, it's because of that.)

Friend, you're making a lot of assumptions and claims about people you don't know (including me), and have a certain streak of arrogance that is difficult to get past. This makes it impossible to have a productive conversation, if having a productive conversation is your goal.

I advise some humility, as well as some effort to recognize that your opinions sound very dogmatic. You are of course free to like or dislike any language you want, but it is important to understand that going from one's own preferences to grandiose claims about a language's merits and usefulness is a rather big leap.

I agree. I've sincerely asked for explanations what is missing when pattern matching is so similar to type inference. Combined with guard clauses and "let it fail" philosophy, what is the problem other than boilerplate? Is it lack of mechanical refactoring? Totally honest question for type enthusiasts, my other posts have been met with silence.
Erlang’s Dialyzer (and the related Elixir project Dialyxer) provide compile-time type safety analysis. It’s optional and only at compile time, but immensely helpful in verifying correctness.
Worth noting that Elixir Language Server will also hook into your text editor/IDE and provide warnings every time you save a file (it compiles the code behind the scenes).

https://github.com/JakeBecker/elixir-ls

I also highly recommend the dialyzex [0] project as well. While it's not going to match every feature of some type systems, it does a much better job than one might expect.

It's always a little frustrating that folks pass on Erlang or Elixir as entirely dynamic. It's a lot closer to what you find in gradually typed languages if you take advantage of the tools available.

[0]: I know there are a few of these elixir projects, though I am not familiar with the parent's. Perhaps it's a typo?

dialyzer is terrible and doesn't actually work in practice, as is evidenced by the many dialyzer errors that slip through to current releases on hex of libraries even the size of Phoenix, StreamData, etc.... Even the major community members don't use it. It's not a substitute for a type system and especially not one that allows you to properly model things in it.
have you used it with elixir_ls? I find that in practice it catches about 80% of my errors before I send them to test.
Yeah, I managed to get our team members to use ElixirLS for this very reason, but in the end I found that it doesn't work when it matters. The good thing about ElixirLS is that at least you have to configure something to disable dialyzer, so by default to at least get some coverage…

In the end you need to some kind of compiler that does proper, rigorous and unapologetic type checking. If Alpaca could reach critical mass I could convince our project leader to use it, which would solve the problem entirely.

Sure, the ecosystem would likely remain the same in that the majority of people simply don't actually have any familiarity with strong, static typing, but at the very least you can now set up these guards yourself and you can have code that is much more likely to be safe and good.

Imagine typechecking a cluster of nodes all sending messages to each other.
Statically typed languages deal with data un/marshaling all the time. Maybe I’m missing something, but how would this be an issue?
One thing I love about Elixir is I had read the Erlang book from Joe Armstrong ages back, and a lot of ideas and concepts still apply. I just didn't get into Phoenix cause PGSQL is a PITA on Windows, so I have to go back and try with MySQL instead.
Use Vagrant! Then you don't have to install/run PostgreSQL natively at all, and can run it inside a Linux VM.

https://www.vagrantup.com/

You could run PG in either WSL or a Docker container.

I currently use Windows (where I spend 99% of my time in WSL) and everything runs great.

Maybe somebody else knows where to wave the dead chicken to make postgres under WSL work well, but my last two tries (Feb 2018, Nov 2018) suggested that trying to do so invites lots of yak-shaving, pain, and poor performance. And that's just using the package manager to install, if you want to build from source, it may not work at all.

Stories to the contrary and hints how to make it work are welcome.

Might be worth retesting, we did some changes to PG to handle the unsupported syscalls more gracefully (warn once, and then not anymore) in a recent set of minor releases.
What issues are you having getting Postgres setup in Windows?

I've used the Windows installer[1] and have had no issues.

[1]: https://www.postgresql.org/download/windows/

I was unable to figure out how to setup accounts, and I am not used to PostgreSQL, I couldnt figure out my root password, which I swear was just "developer" but that didn't seem to work. I'm used to other database engines, despite my love of the idea of using PGSQL.
That’s not a windows issue, it’s an unfamiliar software issue. Take a weekend to learn how Postgres handles accounts. It takes a little getting used to but it is very much worth it.
Ah ok. Maybe it's because my install was basic without additional accounts. I just have my phoenix apps setup to use the default postgres/postgres login.
For some reason I remember having this PGSQL issue a couple of times on Windows, so I may either go with MySQL or what others suggested with WSL / Vagrant. Also I always forget database passwords after a week if it's not saved somewhere.
Screw windows and move to Linux! Opens up a ton of possibilities including docker
I gave it a try, but for me after years of programming in C like languages the syntax is really hard.

I know it is very similar to Ruby.

I wish there was a ElixirC syntax that would also compile to Earlang.

After years of programming with C-like langauges, I actually came to really appreciate the syntax of Erlang. It's actually fairly simple and straightforward. I think the biggest issues people have with it are:

* Capitalized variables names

* use of comma, semi-colon, and period as clause delimiters

It's interesting, but I think that Prolog-style syntax is probably the easiest to read if you don't have syntax highlighting available (though I don't think there is as much of a difference with syntax highlighting).

IMO, the use of header files is a bit baroque and I find it makes it harder to reason about your code. Erlang structs are also no fun at all.
It seems similar to Ruby, but in the end it's more like Prolog
I think you might find one that suits your needs in this list

https://github.com/llaisdy/beam_languages

Fantastic talk. I have been meaning to learn more about Elixr for a while now, and this video was perfect. Thank you!
I sometimes joke that microservices are half of Erlang, badly implemented (I guess Greenspun’s Curse is broken?).

Elixir has been second or third on my todo list for a long time. With the scary news from Vue, it might have just jumped the queue.

See also, Stigler's Law.

Or Poe's law, thus named in 2005, but based on a phenomenon that was well known by the time of Godwin's law.

> Scary news from Vue

Do you have a link?

He's most likely referring to: https://news.ycombinator.com/item?id=20237568

Which is a bunch of FUD (see top comment by EvanYou).

Thanks
That was exactly my thought when I went thru release notes.