[HN Gopher] Elixir for cynical curmudgeons ___________________________________________________________________ Elixir for cynical curmudgeons Author : todsacerdoti Score : 337 points Date : 2023-08-03 14:51 UTC (8 hours ago) (HTM) web link (wiki.alopex.li) (TXT) w3m dump (wiki.alopex.li) | golemotron wrote: | Disappointed. I thought it was going to describe a way for | cynical curmudgeons to get out of their rut. | simmanian wrote: | If I volunteer at a nonprofit and I'm trying to run a team of | volunteers who would... 1) probably not stick | around for long 2) need to be trained from scratch 3) | not have a solid development background | | Would Phoenix be a good choice, given that you can do so much | with it without needing to learn many other tools, or would it be | better to start with something like Supabase + a javascript front | end framework and hope we'll never have to deal with monsters | like kubernetes? | biorach wrote: | phoenix does not sound like a good fit | impulser_ wrote: | I would probably go with Javascript and Supabase, this would | require you to only really worry about the frontend. Javascript | is also probably easier to train people because of how many | resources there are out there about training people to write | Javascript. Supabase is also has a great free tier which will | help your nonprofit. Hell, you might even want to try to | contact them and they might give you a better tier for free | they are really friendly there. | | Elixir is great, and developers love it but training new people | without a solid development background might be hard. | Dowwie wrote: | Things I like about Elixir: | | - concurrency is intuitive! | | - Elixir is a two-for-one language. You can reach into Erlang std | library as easily as you can that of Elixir. So, depending on | your work, you get a chance to discover a wide range of goodies | that come for "free". Examples include gen_tcp, gb_tree, etc. | | - You can remote into a running virtual machine in production, | pod or whatever, and have access to a repl that let's you inspect | state, manage "processes", and manually invoke commands to | troubleshoot issues. The observer, and tui counterpart, are quite | useful too. | | - everyone in the community writing libraries uses the standard | approach to emitting telemetry, saving time and effort for users | to take what is available | | - fast compile times | | - hardest working BDFL (although this presents risks, too), who | also has a pleasant, respectful disposition | | - the community is respectful | | Things I don't like: | | - dynamic language leads to pattern matching or type mismatch | errors at runtime that could have been caught at compile time | | - Elixir Phoenix doesn't have a large community, nor much up to | date reference material, or literature. If you're not experienced | with Front-end dev, it's easier to onboard with a modern SPA | framework like React. | | - supply of Elixir talent exceeds demand, although this isn't | unique to Elixir (e.g Rust) | | - slowly growing ecosystem, relatively speaking | melvinroest wrote: | The changing code in production with a REPL reminds me of | Pharo. Though, with Pharo you get a whole IDE :D | | I also feel that Pharo has too small if a community. The ESUG | conference is coming up soon though. It's good to see they're | coming together | | Why is concurrency intuitive? | Dowwie wrote: | There's no function color. The concurrency patterns are well | defined, documented and discussed. You don't need to sit in a | chat room asking for help from a benevolent core team of | maintainers. | | Granted, I did learn the hard way about introducing cycles | but the error messaging lead me to the root of the problem | quickly. | jpbastyr wrote: | If you're a fan of the ecosystem, but not of dynamic types, | there are statically typed languages on BEAM, eg Gleam | (https://gleam.run/) | beeburrt wrote: | > supply of Elixir talent exceeds demand, although this isn't | unique to Elixir (e.g Rust) | | Is this true? | sarchertech wrote: | At my current company we've many times had to hire and train | people who had no elixir experience. If anything I'd say the | demand for experienced people exceeds supply. | esclerofilo wrote: | Talent and experience are not the same thing, and I would | say experience is a lot more correlated to demand of talent | than to supply of it. More demand means more opportunities | to get experience. | Dowwie wrote: | No, I am lying. The most jobs out there are for elixir | engineers and managers are struggling to fill vacancies. | RadiozRadioz wrote: | Why be so unnecessarily subversive? | OkayPhysicist wrote: | What the documentation for Elixir and its big libraries (Ecto | and Phoenix) lack in quantity of documentation, they | exceedingly make up for in quality of documentation. Who needs | a bunch of garbage blog posts about how to do xyz, when the | official docs painstakingly lay out not only what you need to | know, but also present it in a readable and discoverable way? | bhaney wrote: | > `if` is a macro. | | > `def` is a macro. | | > `defmodule` is a macro. | | > It's all macros. It's ALL MACROS! ALL THE WAY DOWN! AAAAAAAAAA | AHAHAHAHAHHAHAAAA! | | Also see the definition for `defmacro`, the macro for defining | macros, which is defined using... defmacro | | https://github.com/elixir-lang/elixir/blob/v1.15/lib/elixir/... | plainOldText wrote: | The syntactic sugar for the list of tuples (aka the _Keyword | list_ ), such as: _[one: 1, two: 2]_ instead of _[{:one, 1}, | {:two, 2}]_ and the other _... do:_ macros drove me crazy when I | first learned Elixir. But as soon as I familiarized myself with | it and a few other gotchas, Elixir managed to become my favorite | and main language. | aeturnum wrote: | Always glad to see another person finding their way to Elixir! | | IMO the biggest tripping point for people (including, clearly, | this author) is the freedom. They said that the "Big complicated | project structure" was a stumbling point - but there is no | structure! You can actually do it any way you want. But there are | _conventions_. Mix suggests that you lay our your project in a | certain way (and most Elixir projects are laid out that way) - | but you are not required to by the language. | | Nearly everything in the language is a convention (including the | test / dev / prod run modes). This applies to Erlang as well. It | has standard approaches, but you don't /have/ to follow them. I | frequently get confused about the way libraries tend to approach | something (do you have to do it this way? Is there a | requirement?) and the answer is generally "no, but the community | tends to think this is the best way to do it and so people | generally do it this way." | | A great example of everything being a convention: structures | aren't a language feature. They're maps with special keys and | Elixir library support. The upside and downside to this is that | you could actually do almost anything with them - if you have the | time and the skill to implement the system. MANY things are like | this when you get into it. | ljm wrote: | I'm really enjoying getting to grips with Elixir, but I'm still | really in two minds about Ecto having a macro-based SQL ORM. | | Like any ORM, the abstraction leaks, but it really throws you off | course when you're trying to map the host syntax to raw SQL. | from(t as SomeTable, where: x.z == ^y, join: x on assoc(t, :y)) | | Like, it's macro enough to make SQL feel more first-class...but | not enough to actually make it first class, so you've gotta learn | Ecto's quirks. | | It's also chainable so it's a macro over a query builder that | eventually resolves to SQL at runtime. | LispSporks22 wrote: | Lisp user here. I couldn't see what he was talking about re: | "Elixir is a Lisp" and the "why" was pretty hand-wavy, but the | author does seem pretty stoked about whatever he/she saw so good | for them. | weatherlight wrote: | hygienic macros doe not make a lisp, but.... it get you very | close to the spirit of the thing, i think that's why the author | was excited,( and it's a good reason to be.) | BaculumMeumEst wrote: | elixir seems cool and i love its tooling but the more i use | datomic, the less i want to spend my time dealing with SQL and | its baggage unless i absolutely have to. | whalesalad wrote: | what would prevent you from using datomic with elixir? | https://github.com/edubkendo/datomex | | there are other datalog-y tools as well, ie | https://github.com/naomijub/translixir | BaculumMeumEst wrote: | i lost my enthusiasm for building a jenga tower of niche | community libraries | whalesalad wrote: | that is literally clojure development | BaculumMeumEst wrote: | you can get pretty far with cognitect's libraries and | java interop | rekoros wrote: | I usually just blindly upvote anything with Erlang/Elixir in the | title, but this one I read in its entirety over some Pho | | Excellent writeup! | dgb23 wrote: | > the harder something tries to convince me of anything, the more | I expect it to suck. | | That's me vs web development in general and especially in the JS | ecosystem. Other, similar red-flags: hand holding, "best | practices", "anti-patterns" and other voodoo and cargo culting. | | The most suspicious one is prettiness: | | - custom DSL syntax without data representation | | - cosmetic wrappers that are just thin layers without substance | | - "everything is an X" for the sake of faux consistency | throwawaymaths wrote: | - cosmetic wrappers that are just thin layers without substance | | If you've ever tried to write keyword lists in erlang.... The | keyword list cosmetic wrapper is fucking amazing, not only | because it makes it easy to read, but it makes it easier to | debug and easier to one-glance see "this is a keyword list". | 59nadir wrote: | > - custom DSL syntax without data representation | | This is an interesting comment in a post about Elixir because | the Elixir ecosystem is actually full of things that should | just be data but are instead macros being used in modules. | Phoenix in particular is an especially egregious example of a | library that is badly made in almost every regard | | > - cosmetic wrappers that are just thin layers without | substance | | This one is also funny because Elixir itself is little more | than a fairly small set of convenience libraries, a syntax and | a very good tool for project management (`mix`) on top of | Erlang. You can skip the syntax and the convenience libraries | for the most part and actually just use Erlang in a `mix` | project and get the best of both worlds. The convenience | libraries usually are bad makeup on top of Erlang in many cases | and you'd be better served just learning the Erlang way anyway. | jeremyjh wrote: | Phoenix is popular partly because people like its API and its | convenience macros. It won out over Jose's own framework, | Dynamo which he scrapped in favor of becoming a core | contributor to Phoenix. Its easy to make yourself sound wise | by complaining about macros, but this largely boils down to | personal preferences, and a lot of people have different ones | from you. | | For most of the people who actually use Phoenix, the DSL | makes intuitive sense and so there isn't much learning curve, | and it is such an important library to applications that use | it that its worth taking the time to really learn it, whereas | it might not be the case for other libraries that are macro | heavy. Most libraries don't go that route though. | arrowsmith wrote: | > Phoenix in particular is an especially egregious example of | a library that is badly made in almost every regard | | Can you elaborate on this? Why do you think this? | 59nadir wrote: | The interface to almost everything either contains or is | based on a macro. This persists even in cases where you can | clearly see there needed to be no macros at all. | | The non-standard (won't work with anything else) and | basically superfluous websocket protocol has bad | fundamentals and has been marred by bad JavaScript code | being needed for it. On top of that it's pretty bloated. | | The actual channel processes could've simply followed a | standard Erlang interface but someone (...) felt they | needed to put their fingerprint on it, I guess, so it kind | of doesn't. And yes, again everything surrounding channels | is a bunch of macros until you at least get to write and | use normal functions in the actual channel module. | | They've had a long history of arbitrarily deciding to hide | settings/configuration from dependencies they use and | having no actual argument for doing so when asked to expose | them. | | If the part about macros being overused wasn't bad enough | Phoenix also promotes this type of thinking by overusing | them even in generated code, so people can follow the bad | example. | josevalim wrote: | > The interface to almost everything either contains or | is based on a macro. | | This is not true. The endpoint and router are macro | based, but once it is routed, it is all functions. Your | controller actions are functions, calling the | view/template is a function, your channel is functions, | the model/context layer are functions. | | When it comes to behaviors, we do our best to follow | Erlang/OTP conventions, but deviate where it makes sense. | For example, channel has "join" instead of "init" because | you can refuse a join but you can't refuse an init. They | have different return types and augmenting init could be | confusing if later you were to write a plain GenServer. | | It is easy to look from outside and say "someone wanted | to put their fingerprints on it" but actual discussions | were had in pretty much all of these topics. I suggest | asking around. If you asked for something and we had no | actual arguments, then please point me to such | occurrences. I will be eager to clarify (and as a rule we | generally do). | giraffe_lady wrote: | I know erlang better than I know elixir but I still prefer to | use elixir when I have the choice. | | It may be "little more than" convenience, but especially | consistency decisions like always data-first functions plus | the pipe macro is already a monumental ergonomic leap over | erlang. I love erlang but, like php, it is a language where I | have to look up the argument order and config options of | every function every time I use it. | throwawaymaths wrote: | Yep. The only problem with elixir macros is that people look at | the macros that are in core++ (exunit, plug, phoenix, ecto) and | decide it's a good idea to dsl-up everything. | | The biggest offenders IMO are commanded, Tesla, absinthe, | exmachina and now most recently ash. Then there's tons of tiny | libraries that litter hex.pm with macro-heavy nonsense. | | At least the core++ libraries make macros whose syntax/keywords | matches something _outside_ elixirland that you 'd have to know | anyways (e.g. 'get' from plug, all of SQL from ecto), but the big | offenders list are making up clever names for things, which adds | mental overhead to literally everything you do, building crazy | complicated compilation pathways (especially for overeagerly lazy | stuff) or writing function names from whole cloth that make | refactoring or searching your codebase a nightmare (or more than | one). E.g. if you're working in a domain where non-proud camel | case is the convention, don't automatically snake-case it. | bmitc wrote: | As someone who loves Elixir and knows it, this is one thing | that really makes it hard to learn Phoenix for me personally. I | have struggled learning Phoenix because it is so heavy with | macro upon macro that it feels like learning another language. | throwawaymaths wrote: | I have some bad news for you: elixir ecosystem is | consultancy-driven ecosystem. While at least better than | bigtech-driven ecosystem (cough cough), the changes you seek | are less likely to happen because | | 1. They make it easier for consultancies to templatize what | they do, which: | | - keeps their employees tied to the hard earned knowledge | | - keeps their clients tied to their services | | At least though you know that those patterns are (usually) | common and battle tested (or, at least, will be battle tested | - cough cough ash), and unlike a bigtech "their problems are | likely to be your problems". | josevalim wrote: | > - keeps their clients tied to their services | | I have heard this claim so many times but it is easy to | prove it wrong given how much we focus on documentation and | understandability around Elixir and main libs. I have had | clients asking me questions and I would answer it by | improving the docs or writing a guide, committing it to the | repo, and then asking the client for feedback. Half of the | Ecto guides were written like this. | | It is not about keeping clients at all. It is about having | a great on-boarding (and beyond) experience. | nkjnlknlk wrote: | is the claim Ash is not battle tested? | halostatue wrote: | I haven't used commanded, exmachina, or ash: | | - Tesla has a mode which can be used completely without macros, | and I am increasingly encouraging that it be the only way that | it is used. So does the author (as of 2020): | https://github.com/elixir-tesla/tesla/issues/367#issuecommen... | | There is also `req` mentioned in a recent post as an | alternative (it looks good, but I am still playing with it to | see if it is a suitable replacement for Tesla in all cases). | | - Absinthe is something of a compiler itself, because it has to | _strictly_ define things the way that is specified in the | GraphQL spec. You can now import an SDL file, but you still | need to hook resolvers and middleware into it. Honestly, I | don't think that the schema definitions in JS /TS are much | better for GraphQL in terms of readability. | | Being heavily macro-based means that there are sharp edges that | are harder to work around when you want to add your own macros | for code reuse purposes. That said, aside from the _schema_ | definition, Absinthe is entirely usable _without_ macros. | Within the schema definition, Absinthe isn't making anything | up, it's using the same basic definitions that the GraphQL spec | do, adapted for Elixir syntax. | | Exmachina didn't interest me because I don't think much of | factory_bot (which used to be called factory_girl), as I saw it | abused far more than used well (IMO, it's impossible to use | correctly). Ash...looks like an interesting experiment, but I | don't know that there's a lot of pick-up with it compared to | Phoenix. And I have yet to find a use for CQRS/ES, so there's | no reason for me to play with commanded. I certainly wouldn't | consider any of these three to be "major" players in Elixir. | Tesla and Absinthe? Yes. | freedomben wrote: | Yep this is definitely a problem, but fortunately the | culture/community around Elixir generally tends to frown on | unnecessary macros. I heard the saying, "if it can be a normal | function, it should be" many times, which pleases me. | | Overall though this isn't something I've generally run into too | much with Elixir. | throwawaymaths wrote: | Mark my prediction: as the big "non-core++" libraries get | bigger and trashier with their macros, and more used by the | community, hex.pm will become littered with even more trashy | macro libraries, and people will stop saying "don't use | macros". | johnisgood wrote: | I'm sleep deprived. Would not it rather be "start" saying | "don't use macros", given that macros are "bad"? | cschmatzler wrote: | I'm pretty sure that the libraries you consider core++ such | as ExUnit and Ecto are considered feature complete and | won't get any bigger. | throwawaymaths wrote: | Correct, but remember core++ seeded atrocities like | ExUnit.CaseTemplate. | | Anyways my prediction is about Non-core++ libs, which I | listed in gp. | josevalim wrote: | I was never fully pleased with ExUnit.CaseTemplate. If | you have suggestions I am all ears. :) | 59nadir wrote: | > Yep this is definitely a problem, but fortunately the | culture/community around Elixir generally tends to frown on | unnecessary macros. I heard the saying, "if it can be a | normal function, it should be" many times, which pleases me. | | While Elixir people usually say this, they don't at all | follow it in practice because of the terrible example set by | all the libraries. Phoenix is especially egregious and I | can't believe the grandparent didn't bring it up. | | Looking at Clojure's solution that is (as far as I can see) | very popular it makes me annoyed at the relaxed attitude | towards macros in Elixir and how bad it actually is: | | Elixir and `Plug.Router`: defmodule | MyRouter do use Plug.Router plug | :match plug :dispatch get | "/hello" do send_resp(conn, 200, "world") | end forward "/users", to: UsersRouter | match _ do send_resp(conn, 404, "oops") | end end | | Clojure and `reitit` (https://github.com/metosin/reitit): | (def router (r/routes [["/hello" {:get | (fn [r] {:status 200 :body "world"})}] ["/users" | {:name :users :router users-router}] | ["*" {:get (fn [r] {:status 404 :body "oops"})}]])) | | basically everything in the Elixir case is a macro and non- | standard syntax whereas literally of the components of the | Clojure case are just standard data types, and yet it manages | to be more readable. | no_wizard wrote: | `conn` is a magic argument isn't it? Like an implicit | argument to this block of code? | | That is one thing that really bugs me, is I can't | automatically see where the arguments are coming from. I | realize it makes code a little more verbose, but a | requirement around explicitly showing the dependencies used | is much more useful when you're refactoring, for instance, | or scaling code. | | not a hard requirement by any means, sure, and it | definitely doesn't mean something won't scale as it were, | however I am constantly frustrated by languages that allow | for implicit scoped dependencies / arguments. | halostatue wrote: | Yes, it's a bit of a magic argument, but it's the only | unhygienic variable introduced with a Plug dispatch: | | https://github.com/elixir- | plug/plug/blob/main/lib/plug/route... | | Everything else is explicitly passed, AFAICT. | arrowsmith wrote: | Maybe it's just down to familiarity, but I find the Phoenix | example more readable than the Clojure one. To each their | own I guess. | [deleted] | throwawaymaths wrote: | Actually I think plug is mostly fine since it only brings | in one macro (plug) that isn't an http verb, or http common | concept (forward e.g.). | | My huge beef with plug is that it creates an implicit conn | variable in all of the plug bodies. | | But yeah, phoenix is a combination of good choices and some | real stinkers, and I did mention it. | | Edit: I forgot about match. match "isn't great". | dqv wrote: | >My huge beef with plug is that it creates an implicit | conn variable in all of the plug bodies. | | What do you mean? That only happens if you use | Plug.Router; otherwise, you have to define a call | function that takes the conn as the first argument. You | can even go as far as explicitly calling the init | functions for each Plug manually. It's init(opts), | call(conn, opts) all the way down. | dragonwriter wrote: | > basically everything in the Elixir case is a macro and | non-standard syntax whereas literally of the components of | the Clojure case are just standard data types, and yet it | manages to be more readable. | | "Readable" is mostly a matter of "fits the grooves already | worn in my brain"; to me, the Elixir there nonstandard- | macro-based-syntax-and-all, is _vastly_ more readable than | the Clojure. | 59nadir wrote: | > "Readable" is mostly a matter of "fits the grooves | already worn in my brain"; to me, the Elixir there | nonstandard-macro-based-syntax-and-all, is vastly more | readable than the Clojure. | | I'll admit to being able to read Lisp syntax without | choking on the parens, but I don't even use Clojure (or | any other dialect that uses special syntax for the | different collection types) and I think it's way more | readable and malleable (you can literally do whatever you | want that makes sense to this data and it'll work, | meaning you're free to write whatever middleware you want | that takes and produces the expected data). | | I've used Elixir since 2015 so I have no problem actually | reading the syntax at all; I just think it's factually | much worse than the Clojure example because it's | basically just a bunch of macros you can't do much with | and lots of implicit behaviors. | | This also applies to Elixir's greater position in the | BEAM ecosystem. I think the idea was that Elixir was | going to be a boon to Erlang and other languages in there | over time but I think it's demonstrably pretty useless as | a BEAM citizen except for some of the patches they've | submitted; most big Elixir libraries can't even be used | outside of Elixir because they're full of macros and | don't even provide interfaces with just functions. | hosh wrote: | Sure. But there were improvements to the ecosystem. | Telemetry is a great example, though they ended up | porting it to Erlang so that both Erlang and Elixir | projects can use it. | josevalim wrote: | > I think the idea was that Elixir was going to be a boon | to Erlang and other languages in there over time but I | think it's demonstrably pretty useless as a BEAM citizen | except for some of the patches they've submitted | | Not sure whose idea it was but I would say this is a very | inaccurate take. Of course, we have taken much more from | Erlang than given (that's expected from hosted | languages), but I personally sit on more than 100 PRs to | Erlang/OTP. I made binary matching several times faster | by using SIMD. I improved the compiler performance | (including Erlang programs) by (conservatively) 10-20%. I | contributed compiler optimizations to reduce memory | allocation. There is a now faster sets implementation | which I contributed. Erlang/OTP 26 ships with faster map | lookups for atom keys based on a pull request I | submitted. The new logger system in Erlang takes ideas | from Elixir logger. The utf-8 string handling in Erlang | is based wholesale on Elixir's (and extended for lists). | And this is in no way a comprehensive listing [1]. | | And this is not counting everyone else in the Elixir | community who contributed and those who are now actively | working on Erlang tooling and were on-boarded to the | ecosystem via Elixir. The Erlang ecosystem now has a | package manager [2], used extensively by both languages, | rebar3 and Mix, all implemented and powered by Elixir. | | And then there are efforts like the Erlang Ecosystem | Foundation, which is made of developers and sponsored by | companies working with both languages, and it delivers | important projects around observability, documentation, | and more. For example, you can find several Erlang | projects now using ExDoc for documentation, such as Recon | [3]. | | That's my take. What are your demonstrations that we are | pretty useless for the BEAM ecosystem? | | 1: https://github.com/erlang/otp/pulls?q=is%3Apr+author%3 | Ajosev... 2: https://hex.pm/ 3: https://hexdocs.pm/recon | troupo wrote: | Elixir was the kick that Erlang needed for a long time. | josevalim wrote: | Honestly, I don't care if we were a kick or not :) but | saying we are "demonstrably pretty useless" is completely | unfair and bordering on being a bad faith argument. | hosh wrote: | Not to mention that the macros should be invoking regular | functions, making it easy to skip macros if you so choose. | | When I pivoted from Ruby to Elixir, I was expecting to do a | lot more metaprogramming, but I found that regular functions | with pattern matching already does a lot that I want for many | cases. | sodapopcan wrote: | I personally don't have any problem with heavy macro-use in | libraries, I feel like that is where they shine. So long as the | documentation is good, I don't really care how the library | itself is implemented. I would much rather have the cleaner API | in many cases. I know it can be taken too far, though. Some | funky stuff can happen in Phoenix's router, though a lot of it | is actually to reduce cyclic compile-time dependencies as the | router is a place where these necessarily happen. | | Macros in business code, however, are pure evil. I feel like | anyone who spent any time in Rails over the past decade has | learned that lesson. | throwawaymaths wrote: | Yep. I wish `pipeline`, `scope` and `resources` in Phoenix | router and also all the `use MyApp.Web, :x`, would just die | in a fire. | | Thank goodness they got rid of views though I still am | annoyed that the default path resolution on templated content | isn't explicit. | | The crazy thing is that the most amazing part of phoenix, | liveview, is almost no macros. | arrowsmith wrote: | > I wish `pipeline`, `scope` and `resources` in Phoenix | router and also all the `use MyApp.Web, :x`, would just die | in a fire. | | How would you prefer it worked/looked? | | > I still am annoyed that the default path resolution on | templated content isn't explicit. | | What do you mean by this? In the new 1.7 approach to views, | you explicitly set the path in each view using | `embed_templates` (if you're not defining your HEex | directly within the view module itself.) What part isn't | explicit? | throwawaymaths wrote: | > What do you mean by this? In the new 1.7 approach to | views, you explicitly set the path | | For example, if you wrote a liveview called FooView in | /path/to/my_liveview, a default render() will look for | /path/to/my_liveview/foo_view.html.heex | | (Also note auto-snakecasing) | | Btw, this is still a different semantic if you do the | deadview equivalent, which will try to do a path | resolution in /templates. | | I guess these are minor complaints but I would much | prefer they use the same default strategy and, say, pass | the path in `use Phoenix.Liveview` | arrowsmith wrote: | > This is still a different semantic if you do the | deadview equivalent, which will try to do a path | resolution in /templates. | | Not true in 1.7 - views* don't have any kind of "default" | template resolution; you have to explicitly state the | template path with `embed_templates`. That is if you're | not just defining your HEEx directly within the view | module itself, as I already mentioned. | | *By "views" I mean the new style that uses `use MyAppWeb, | :html`, not the old style you describe which is now (in | 1.7+) only available as the external dependency | `phoenix_view`. The new style of module is still called a | "view" by the docs: | https://hexdocs.pm/phoenix/request_lifecycle.html#from- | endpo... | sodapopcan wrote: | I never use `resources` though have no beef with `pipeline` | or `scope`, though I haven't thought too much about it. It | is a little weird getting used to which modules are getting | auto-qualified and which aren't, but I'm long passed that. | And that is actually what is "fixing" the cyclical | dependency issue. | | What's wrong with the `use MyApp.Web, :x`? You can easily | get rid of it as it's just generated boilerplate. It's a | nice little pattern to allow all the different things to | share the view helpers. If you'd like to be extra explicit, | though, just delete the file and include everything | manually. | | I'm indifferent on views because I never really used them, | haha. | halostatue wrote: | I personally would prefer something like: | defmodule MyApp.Web.Router do use MyApp.Router | end | | over defmodule MyApp.Web.Router do | use MyApp, :router end | | but that's a preference. | sodapopcan wrote: | You can do that if you want. Just remove `def router` | from `MyAppWeb` move its contents over to a custom | module: defmodule MyAppWeb.Router do | defmacro __using__(_) do quote do | use Phoenix.Router, helpers: false | import Plug.Conn import Phoenix.Controller | import Phoenix.LiveView.Router end | end end | | But why the dislike for passing a second argument to | `use`? It keeps everything together pretty nicely. | jrochkind1 wrote: | > So long as the documentation is good, I don't really care | how the library itself is implemented. | | I don't have experience in Elixir, but in my general | experience what you say is fine until you need to debug | something going wrong (or something you don't understand and | _think_ is going wrong) in a library, which always happens | eventually, no? Or until you want to PR a feature, etc. | sodapopcan wrote: | Those are fair points. In terms of PRing, though, I do | think that people are a little too "afraid" of macros. It | sometimes feels like people won't learn them out of of | principle which is a shame as they aren't that complicated. | Though anyone trying to navigate nested macros definitely | has my sympathy. | | No matter how slice it, however, macros are a massive part | of what makes Elixir Elixir. A large portion of the | language's "keywords" are just macros and they reduce a lot | of the boilerplate Erlang forces you to write. | throwawaymaths wrote: | EEx does macros well. Note that EEx.function_from_x makes | you declare the name of the function it instantiates, so | it's searchable. | | GenServer is kind of a "bad example" of a macro. It | creates a _totally hidden_ function. Though I guess to be | fair 99.9% of the time you really shouldn 't be writing | genservers in elixir. | AlchemistCamp wrote: | > 99.9% of the time you really shouldn't be writing | genservers in elixir | | Woah! Why is that? | | I've written at least one GenServer in nearly all the | Elixir projects I've worked on. They seem like one of the | base building-blocks to me. Also, if you squint a bit, | you'll see that many libraries you're working with are | essentially exposing a GenServer interface, with a few | extra features. | pests wrote: | The only thing I can think of is when developers overuse | genserver not realizing it's involving another process | and then serializing your requests (behind a queue even) | into its mailbox. That may be desirable for some but in- | process handling can sometimes be the better choice. | sodapopcan wrote: | > Also, if you squint a bit, you'll see that many | libraries you're working with are essentially exposing a | GenServer interface, with a few extra features. | | Like LiveViews :) | throwawaymaths wrote: | Your intuition as a nom-elixir user is absolutely correct. | However it's worth saying that as a working dev, there's | almost never a problem in the core++ libraries. | | Edit: lol looking at the log in elixir slack, and one of | the most recent posts is exactly trying to debug something | too magical in one of the aformentioned non-core++ | libries!! | troupo wrote: | > now most recently ash | | I've been using Ash in a side project and it's slowly growing | on me. You have to twist your brain a bit to grok it (and I | haven't, not fully). | | Pros: | | - a lot of things happen where you want them to happen. | | I found that writing stuff with Ecto involves more boilerplate | than with Ash because you have to write your queries, and your | changelogs, and your API accesses, and wire them together, but | what if you want a separate API.... With Ash it's a single | resource with a few macros. | | - quite a few escape hatches into regular Elixir | | You don't want magic behind actions? There are several ways to | hook into what's happening, or even write everything manually. | And to the calling code... it will still look the same | | - Despite all the macros the errors are usually quite good and | pinpoint the problems | | Cons: | | - too few people who truly understand Ash | | - documentation is often too terse and concise. But you can't | really blame the author who is doing _a lot_ | | - errors are not always good :) | | I do agree with you on overreliance on macros in parts of the | ecosystem | CyberDildonics wrote: | Elixir seems to benchmark as half the speed of python, which | would put it about 100x to 200x slower than C++. That's a lot of | speed to give up for the silver bullet promise of immutable data | structures (which I've never understood the appeal of in the | first place). | | https://elixirforum.com/t/elixir-vs-python-performance-bench... | elcritch wrote: | It's unclear why the techempower gives low performance for | elixir / phoenix. But from what I've heard is that in real | world applications the performance tends to scale much better | than Python or Ruby. | CyberDildonics wrote: | The link is about execution speed, I think if you start | talking about 'scale' that's a diversion, since that isn't | about the language and is more about the architecture of the | program. | BaculumMeumEst wrote: | it's because the people who contribute to techempower | benchmarks are zealots who believe that it's far more useful | and important to show their One True Language in the Best | Possible Light than to give you a useful benchmark. take a | look at the source code for some of them and see for | yourself. | stilwelldotdev wrote: | I've landed on SvelteKit and classless CSS for most of my hobby | projects. | | I am interested in Elixir though, especially Phoenix, but found | it to be difficult to manage and get started with in Windows. | | Still looking for the easy way into learning to work with web | sockets as a 41 year old man with very little spare time. | _joel wrote: | WSL2 should get you going? | freedomben wrote: | That's what I would suggest as well. WSL2 and use asdf[1] to | manage the erlang/elixir versions. | | You could also use containers pretty easily as well with | docker or podman for windows and the official Elixir | images[2]. | | [1]: https://github.com/asdf-vm/asdf | | [2]: https://hub.docker.com/_/elixir | victorbjorklund wrote: | What is "classless CSS"? Just using style attributes? | tommica wrote: | Probably just a css file that styles the html elements only | without using any classes | CollinEMac wrote: | I'm using Phoenix for my side project on a Windows machine. It | hasn't been too problematic for me. Maybe something changed | since you've tried it. | OkayPhysicist wrote: | There used to be a couple pain points when working with | Phoenix on Windows. The bcrypt library wouldn't build, | something needed to be run in Administrator mode to establish | their symlink workaround, and PostgreSQL is a little more | irritable on Windows. SASS (some node dependency in the | Javascript asset managing stuff) also flat out didn't work on | windows, but there was a drop-in replacement. | | I know the SASS issue was solved (as a side effect of | eliminating the node dependency), and I believe the bcrypt | issue was, too. | toldyouso2022 wrote: | Use virtuabox and make a vm with ubuntu, install elixir and | connect via ssh. This is what I did when I wanted to try it out | but only had win8 | [deleted] | whalesalad wrote: | The a-ha moment when you grok "Elixir is actually a Lisp" is very | exciting indeed. It's a beautiful language that fits all of its | elements together so nicely. | bmitc wrote: | Elixir, other than the language itself, has wonderful developer | tooling that's all written and configured in the language itself. | It makes me feel really comfortable because it's all right there. | You don't need external scripting languages. For some | programming, you don't even need external libraries sometimes. It | all feels very OS like, not to mention the OS-like nature of the | BEAM. | | If you're on the fence on Erlang or Elixir, watch _The Soul of | Erlang and Elixir_ by Sasa Juric: https://youtu.be/JvBT4XBdoUE | | If it doesn't make you excited about a language, I don't know | what will. It is an astounding feat that the Erlang team at | Ericsson were so ahead of the curve and remain so today. | macintux wrote: | I absolutely love Erlang. It's a succinct, powerful, amazingly | well-thought-out system design with a VM that is very | complementary. | | I just can't get past all the extra verbosity of Elixir, but | this writeup gives me hope that someday I will. | chubot wrote: | I'm also looking at Elixir and Phoenix (coming from Python/C++), | and it looks cool. Doing realtime features with Python requires | something like Tornado / asyncio, which isn't ideal IMO. | | I'm all for the immutable / message-passing architecture in the | large, but I wish that you could just write Python-style code | within processes. The VM copies all data structures at process | boundaries anyway. | | I think that language would be very popular! | | I wrote Lisp 20 years ago, before Python, but now it feels a | little annoying to "invert" all my code, for what seems like no | benefit | | e.g. from https://learnxinyminutes.com/docs/elixir/ | defmodule Recursion do def sum_list([head | tail], acc) | do sum_list(tail, acc + head) end | def sum_list([], acc) do acc end end | | I would rather just write def sum_list(L): | result = 0 for item in L: result += item | return result | | But then also have the Erlang VM to schedule processes and pass | immutable messages. | | There is obviously a builtin in Python that does this, and I'm | sure there is a better way to do this in Elixir. But I think the | general principle does hold. | [deleted] | pythonaut_16 wrote: | Have you seen Elixir list comprehensions? iex> | for n <- 1..4, do: n*n [1, 4, 9, 16] | | Or for your example: iex> l = 1..3 # equivalent | to [1,2,3] iex> Enum.reduce(l, fn item, acc -> acc + item | end) # or iex> Enum.reduce(l, &(&1+&2) # or | the built in iex> Enum.sum(l) # all return: 6 | | https://elixir-lang.org/getting-started/comprehensions.html | https://hexdocs.pm/elixir/1.12/Enum.html#reduce/2 | https://hexdocs.pm/elixir/1.12/Enum.html#sum/1 | | None of which take away from your point though: it's definitely | a different mental model than you use for Python/Go/Javascript. | [deleted] | mfitton wrote: | You might want to look into Ray. It's a Python library lets you | deploy actors (classes) and tasks (functions) and abstracts | away the management of resources, message passing, lets you | define automatic repairs, etc. that is entailed with deploying | an arbitrary amount of intercommunicating processes in Python. | | Admittedly, I haven't worked with Erlang or Elixir, so their | solution to this might be much more usable. Ray is aimed | primarily at ML use-cases, though it is quite general. | jclem wrote: | You can reduce with list comprehensions in Elixir, but it's | uncommon to see: sum_list = fn list -> | for item <- list, reduce: 0, do: | (sum -> sum + item) end sum_list.([1,2,3]) | | Other comments are correct that `Enum.reduce/2` is probably | better: Enum.reduce(list, &(&1 + &2)) | | Obviously you don't have the flexibility / mutability you refer | to in other comments with either of these, but you can always | put more in your accumulator: | get_sum_and_update_count = fn list, map -> for item | <- list, reduce: {0, map}, do: | ({sum, map} -> {sum + item, Map.update(map, item, 1, &(&1 + | 1))}) end | | (A contrived function that returns a list sum and an updated | map with the count of the values found in the list) | bcrosby95 wrote: | Built ins aside, I find most uses of recursion to be better | served by Enum.reduce. | chubot wrote: | Yeah I knew someone was going to say that (see last | sentence), but a for loop is more powerful and general than | reduce(). | | Mutability within the loop is useful, and it can be | controlled by processes and message passing. | bcrosby95 wrote: | I assumed you meant something like Enum.sum that completely | trivializes the code. In comparison, generic, higher level | functions are pretty fundamental to FP. | sodapopcan wrote: | I'm not sure "powerful" is the right word here, it's more a | matter of "what certain people are used to". If you want a | counter or whatever, you can use a tuple to give yourself | multiple accumulators. You could argue it's uglier, but I | wouldn't necessarily agree. It's something that is easy to | get used to if you remove the "but I'd rather just do it | this way" mindset. | throwawaymaths wrote: | the problem with a for loop is that it is inexplicit about | what from the outer scope can be mutated. Which isn't a | problem, for small functions but I have definitely seen | monster for loops in professionally written django code | with ~500 lines of code in the function. | | Besides being in that magical sweet spot (executes | imperatively but reads declaratively), a reduce forces you | to declare ahead of time what things can be carried over | and mutated between each iteration. | | > it can be controlled by processes and message passing. | | DO NOT DO THIS YOU WILL REGRET THIS SIMCITY MEME | freedomben wrote: | What a terrific write up! I highly recommend the read. | | I too had an ephiphany when I realized Elixir was actually a | Lisp. The language went from mildly interesting to "holy crap I | think this could be my favorite language." Add on some wildly | productive and pragmatic frameworks like Phoenix, Nerves, and | increasingly Nx, and you've got a hell of a toolkit. | | My biggest criticism of Elixir has been the difficulty of writing | quick scripts, but that story has improved greatly over the last | couple of years. I still turn to Ruby for scripts (especially | since it's often present on systems and so easy to install), but | this is a good reminder that it's time to try Elixir again for | that. In some ways it may be better, such as dealing with | dependencies. For exmaple I try hard to avoid using any non- | standard libs with Ruby scripts so I can just use the system | ruby, and don't have to ship a Gemfile and/or install any gems, | or mess with chruby/asdf. With Elixir that story looks even | better since the deps can be part of the script itself. | sergiotapia wrote: | Here's a great repo showcasing how to use it more like a quick | scripting language. | https://github.com/wojtekmach/mix_install_examples | capableweb wrote: | > I too had an ephiphany when I realized Elixir was actually a | Lisp. | | Is it actually? Last time I looked at Elixir (granted, that was | a while ago), the syntax for writing macros was different than | the syntax for writing ordinary code, so it fails even at a | simple thing like that, it doesn't seem to support homogeneous | meta-programming at all. | | But again, I feel like I might be wrong here and I'm happy to | be proven wrong. | bmitc wrote: | What is the actual failure? The macros are written with and | by processing the built-in data structures. | sodapopcan wrote: | Ya, it's not _actually_ a lisp. I can 't find the source but | Jose has stated part of the idea was to give you lisp-like | metaprogramming with a non-lisp syntax (sorry, Jose, if I | have mis-quoted). | | Even the regular syntax is sort of lispish, though, if you | remove the syntactic sugar. It's all macros and | datastructres. defmodule Foo do | def bar do "baz" end end | | is really: defmodule Foo, do: (def bar, do: | "baz") | | ...which is lispish if you squint the right way. | zambal wrote: | A bit pedantic I guess, but that still uses some syntactic | sugar (optional brackets and keyword syntax). Removing all | syntactic sugar would look like this: | defmodule(Foo, [{:do, def(:bar, [{:do, "baz"}])}]) | | Even aliases (like Foo) are also a kind of syntactic sugar | for a specific type of atom (Foo is actually the atom | :"Elixir.Foo") | sodapopcan wrote: | Ha, ya I meant remove the `do` sugar. | foldr wrote: | That's just syntax sugar. Even the original Lisp was supposed | to have sugar on top of S-expressions, although that never | really happened. | | https://en.m.wikipedia.org/wiki/M-expression | jjtheblunt wrote: | I think Mathematica has had a slight variant since 1988 | (i've been using it since then, but never M-expressions, | but they look awfully similar). | anamexis wrote: | It's listed under the "Implementations" section of that | wiki article. | pmarreck wrote: | You can write macros (as well as functions, actually) that | accept AST and emit transformed AST back. It has quote and | unquote. Turns out that it doesn't need homoiconicity to | accomplish Lisp-level macro capability, which means it has | all the power of a Lisp but with actual syntax (which is, | like it or not, more appealing to many people) in a language | with deep pattern-matching and completely immutable data | guarantees. | barkerja wrote: | > My biggest criticism of Elixir has been the difficulty of | writing quick scripts | | Curious what you find to be the biggest pain point(s) here. Is | it runtime containment? Library access? Etc. | monsieurbanana wrote: | Is the size of the erlang vm one such point? I think I | remember reading it's about 500mb, and you won't find it | installed by default in many systems. | bongobingo1 wrote: | Most of my phoenix apps sit under or around 100mb resident, | and they load a fair bout more than a script probably | would. | square_usual wrote: | Startup time is another. For example: $ | elixir test.exs hello, world! $ | hyperfine "elixir test.exs" Benchmark 1: elixir | test.exs Time (mean +- s): 471.1 ms +- 2.6 | ms [User: 187.4 ms, System: 83.1 ms] Range | (min ... max): 467.1 ms ... 475.6 ms 10 runs | | Compared to: $ ruby test.rb | hello, world! $ hyperfine "ruby test.rb" | Benchmark 1: ruby test.rb Time (mean +- s): | 36.3 ms +- 2.6 ms [User: 26.0 ms, System: 8.4 ms] | Range (min ... max): 34.5 ms ... 53.6 ms 53 runs | | In practice, I've been able to get the ruby startup time to | as low as 6ms - this is what I use for scripts running as | keyboard macros, for example. I cannot practically use | elixir for that. | hosh wrote: | Huh, interesting. I bet for keyboard macros, it would | work better by invoking a call to something that is | already running to reduce startup time. Kinda like the | emacs server. | | BEAM should still be able to compile new code on the fly, | for one-off scripts | square_usual wrote: | > keyboard macros [...] would work better by invoking a | call to something that is already running to reduce | startup time | | Maybe, but that comes with two disadvantages: | | - I would have to re-architect my scripts to work like | that, and run a server with uncertain memory costs | perpetually; and - I would have to use something with | faster start time to run the call on my keyboard macros, | e.g. bash, which would mean writing bash instead of | elixir/ruby and/or being clever. | barkerja wrote: | Using escript, I am able to almost halve the startup | time. But it's still ~4x slower than ruby. | hyperfine "./derp" Benchmark 1: ./derp | Time (mean +- s): 241.0 ms +- 7.4 ms [User: | 146.9 ms, System: 170.8 ms] Range (min ... | max): 235.1 ms ... 261.7 ms 11 runs | bcardarella wrote: | For me Elixir's Livebook has become a killer "scripting" tool. | cutler wrote: | Re Elixir for scripting, what's the point? Procedural Ruby, | Perl, Python or bash have been around for decades and are | exactly what you need for short sysadmin scripts. | Elixir/Erlang's niche is massive lightweight conucurrency and | is the wrong tool for this domain. | travisgriggs wrote: | I often write some little toolets in Elixir, just to hone | skills and give myself an opportunity to explore the libray. | Often after I e first written it in Python. I agree it feels | a little misaligned, but it's nice to be able to use it for | other reasons. | epiccoleman wrote: | The Enumerable APIs, regex handling, low-bullshit functional | approach, and great REPL make it a pretty nice scripting | language. I've done quite a few Advent of Code puzzles with | it, and it always feels like such a nice multitool for | chewing up the input files into workable formats. | | It's not the first tool I'd reach for, I'm still a filthy | bash hacker at heart, but I could definitely see using it for | the right problem. | | It's also just fun to write, which is valuable in its own | way. | cutler wrote: | What you've described is functional-style/dry Ruby. | epiccoleman wrote: | Well, no, what I'm describing is Elixir. | | If your point is that the potential use cases overlap too | much with Ruby, I mean, fine, write Ruby. I like Elixir | more. I'm not picking either language for pure | performance, but rather for ergonomic purposes, so we're | into kinda subjective territory. | malkosta wrote: | Problem with writing scripts in Erlang VM is the slow startup | time...it isn't suited for that. Although I love it for pretty | much everything else besides scripts and executables. | pmarreck wrote: | Yeah, this miffs me too (a half second startup time, | locally), which has got me even looking at languages like | Idris that can compile down to C and then thus to an instant- | start app. | ghayes wrote: | Also it's not the best for creating OS processes and/or | interacting with stdio. | jrochkind1 wrote: | > For exmaple I try hard to avoid using any non-standard libs | with Ruby scripts so I can just use the system ruby, and don't | have to ship a Gemfile and/or install any gems | | The ruby "story" for Gemfile dependencies for single-file | scripts have gotten a BIT better since possibly last time you | looked at it. | | It will of course necessarily involve installing gems still | though. Ideally for your use case, I feel like you'd want to | install them to a local (not system-default) location ... which | is ordinarily possible with bundler, but oddly the maintainers | seem to think it's an anti-use-case for inline bundler? | https://github.com/rubygems/bundler/issues/7131. I dunno. | | Anyway, I put this here not to convince you, your decision is | reasonable, but just other info for other readers. | coolros wrote: | That was a good read, well done. I've been using Elixir for about | a year now and I just smile when I'm coding. I'm still a little | unsure about it's place and where it'll go, but I have loved | exploring and learning BEAM with a little nicer syntax. Jose is | great and watching the introduction of a type system is | interesting too | satvikpendem wrote: | Elixir is cool, I used to use it for web app backends before | adopting TypeScript and Rust. The reason I adopted them was the | same reason I stopped using Elixir after a while: type safety. It | was getting increasingly hard to be productive in Elixir in a | large application due to runtime type errors that are caught in | statically typed languages. | johnisgood wrote: | Strange, I cannot recall the last time I ran into one and I | write a lot of Erlang. Both Erlang and Elixir share the "Let It | Fail" philosophy, additionally it is also highly encouraged to | use pattern matching, guards, and error-handling techniques to | deal with potential type-related issues and errors. | | On the other hand, I get it all the time with Python, for | example. | cpursley wrote: | I've found that pattern matching in the function head and | guards get you most of the way there. | satvikpendem wrote: | Yes however I get that in TS and Rust while also having | stronger type guarantees. I don't think pattern matching is | an alternative to static types, it's a supplement. | weatherlight wrote: | Rust, sure. Love me some Rust. | | Typescript's type system isn't sound and you can still get | runtime errors. (Type systems should be bomb-proof or just | get out of the way.) | johnisgood wrote: | Well, I suppose to each their own. I use languages with and | without static typing. I love Ada the most though, because | the way you define types is very different from the most | widespread way. In Ada, you define the range. | | Examples: type Day is (Monday, | Tuesday, Wednesday, Thursday, | Friday, Saturday, Sunday); subtype | Business_Day is Day range Monday .. Friday; subtype | Weekend_Day is Day range Saturday .. Sunday; subtype | Dice_Throw is Integer range 1 .. 6; type | Arr_Type is array (Integer range <>) of Character; | type Color is (White, Red, Yellow, Green, Blue, Brown, | Black); type Column is range 1 .. 72; type | Table is array(1 .. 10) of Integer; type | Device_Register is range 0 .. 2**5 - 1 with Size => 5; | type Commands is (Off, On); type Commands2 is new | Integer with Static_Predicate => Commands in 2 | 4; | hmmokidk wrote: | How tested were your applications? | jnsaff2 wrote: | If you want to get a mindbending experience of the articles "it's | macros all the way down" then here is one for you in glorious 3 | minutes and 39 seconds: | https://www.youtube.com/watch?v=x5W3CmZJMLs | tommica wrote: | That's pretty cool! | pmarreck wrote: | It looks like it got HackerNews'd. The stack seems to be | Happstack, a Haskell lib. | | Perhaps if it was served by Phoenix... /obvious comment is | obvious | hu3 wrote: | You're correct. | | It says at the bottom: powered by https://github.com/jgm/gitit | | Readme states that: "Gitit is a wiki program written in | Haskell. It uses Happstack for the web server and pandoc for | markup processing." | davidw wrote: | That's a pretty good write up. | | There's a fine line between making things easier and more | readable and having less boilerplate code, and pouring a bit too | much magic and macros into things. | | I'm always curious to see what people do with Elixir. The BEAM | environment offers a lot in terms of a platform, but if you're | just using it to serve web dynamic web pages, Rails is going to | be a better pick in _some_ circumstances because of the huge | number of libraries, people who know it, documentation, hosting | and the rest of the ecosystem. | pdimitar wrote: | The transparent parallelism makes it an amazing fit for pretty | much anything and everything that doesn't require minimum | system resources and microsecond-level of response times. | | 1. Web apps work awesomely because they tolerate sudden bursts | of load much, much better than Rails. Rails deployments | regularly fall over on bursty workloads unless complex load- | balancing setups have been put in front of them. | | 2. Which brings me to: operations / infra story is much | simpler, and it is thus cheaper and easier to maintain Elixir | apps, even when they span multiple nodes (because Erlang's | builtin mechanism to do mesh networking / distribution works | well enough for 99% of the projects out there). | | 3. Complex service trees f.ex. scrapers that also present their | data in a visual CMS backoffice UI and background tasks | infrastructure -- all of that can live on literally the same | node, share the same code repo and be very easy to manage and | maintain as a result. | | 4. Oh, that also reminds me: almost anything and everything you | would need Redis for, you can have it natively with | Erlang/Elixir. | | 5. Corollary to point 3: long-lived daemons that are not even | web apps / APIs work really well under Elixir due to the | supervision tree guarantees of Erlang's underlying OTP | framework. If you configure it well (the defaults are not | always optimal) you can have your invisible mesh of services | survive extended outages of the 3rd party APIs it depends on. | | 6. In the last years, LiveView and Livebooks are amazing | additions that help severely reduce the need of JS and provide | an alternative to Jupyter Notebooks, respectively. Though it | has to be said that LiveView works best when the latencies to | the backend aren't too big, say, 200ms or less. Beyond one | certain human perception threshold it starts to feel sluggish | however. | | I could go on and on and give plenty of examples from my | career. I've replaced a lot of shell scripts and PHP / Python / | JS services with Elixir, and each migration was a crushing | success in every way. We're talking 15+ such projects. Only 1-2 | of them got back to their original language simply because the | companies / teams were too risk-averse and didn't want to hire | Elixir devs (or train their current people). But the network | effects are always a chicken-and-egg problem; if people never | want to bet something on the tech then it obviously is never | going to be appealing to them. | | There are many who made the plunge though and are happy with | the results. | davidw wrote: | > If you configure it well (the defaults are not always | optimal) you can have your invisible mesh of services survive | extended outages of the 3rd party APIs it depends on. | | This is something that annoyed me a bit with OTP. The basic | strategies aren't really enough for that, so you need | something like https://github.com/jlouis/fuse | | I wrote something like that myself, but it hasn't seen a ton | of use: https://github.com/davidw/hardcore | megaboy101 wrote: | Where I previously worked we used Elixir as the backend for a | early-stage social app. | | We only really encountered the lack-of-libraries issue a single | time (we needed a Neo4j driver that supported their hosting | platform). | | But aside from that, Elixir was a great choice and served us | well. When our app went semi-viral all we needed to do was | increase our instance size in AWS, never really needed to worry | about horizontal scaling thankfully. | | Our app also needed a lot of realtime messaging and updates, | which was genuinely a breeze with Phoenix. I don't think I | could ever to back to trying to finagle a websocket API in | Python. | hosh wrote: | If anything, scaling Elixir apps favors vertical scaling. | Horizontal scaling starts hitting the limits of dist erlang | (since, unless you restrict the topolog, every node connects | with every other node). | | It makes for an interesting time when deploying to | Kubernetes. But we figured out how to increase the number of | cores per erl node during peak daily traffic. | | I'm working for a Nodejs shop now. For all its use of async | stuff, it simply does not scale as well as Elixir (not to | mention the deep dysfunctions in the Nodejs ecosystem). | dsiegel2275 wrote: | If I recall the things I've read on this in the past, the | horizontal scaling limitations of distributed Erlang are | encountered around like 500 to 1,000 nodes? Which I have to | imagine means the large, large majority of shops using | Elixir and scaling horizontally will be just fine, as they | are typically in the size of 2 - 10, or maybe 20 nodes. | hosh wrote: | Having done both Rails and Elixir, Elixir is vastly easier to | scale. Not just because it can use up all the available cores, | but also because a REPL in a production environment makes | troubleshooting and identifying bottlenecks easier. When I | scaled Rails, it was a struggle, and the epiphany I had when I | had to modify how Sidekick worked was that Elixir and Erlang | had built-in primitives to do what is major refactor of | Sidekick to get Sidekick to do what I want. | | One of the things I had success with in a non-web applications | is writing Kubernetes Operators in Elixir. Though I also want | to experiment with the embedded Prolog-in-Elixir for those. | cschmatzler wrote: | Phoenix is obviously "the big thing" and no other | language/framework combination has something as good as | LiveView. Rails cannot compete there. Other than that, building | Livebook apps for our customer success team has been really | great and easy. | | There's quite a big push for ML in Elixir right now, and then | there's also Nerves for embedded programming, which I've never | dabbled in but it looks nice. | cultofmetatron wrote: | ecto is also just an amazing db wrapper in general. you | basically write sql in elixir which means you can optimize | the crap out of your queries and its easy to steop down to | actual sql where needed via fragments. | hosh wrote: | And you can still use composable queries if you still want | to (equivalent to Rail's named scopes). | slekker wrote: | Do you have any write up about Livebooks for your CS team? | Sounds like an interesting use case! | OkayPhysicist wrote: | LiveView is definitely Elixir's killer app. It's what takes | Phoenix from "a really good web framework" to "the singular | best web framework", in my experience. Ecto is also a best- | in-class data-layer adapter (ORM seems wrong and reductive). | metaltyphoon wrote: | > no other language/framework combination has something as | good as LiveView | | You just have to look. Blazor does what LiveView do and on | upcoming. NET 8 it will leapfrog it. | sodapopcan wrote: | > Rails is going to be a better pick in some circumstances | because of the huge number of libraries. | | This isn't really as big a problem as many people think. I've | been out of Rails for a while now but haven't really felt the | pain of missing anything with Phoenix. I've noticed there _aren | 't_ often Elixir wrappers around third party APIs, but those | are really not a big deal to create a small version on your own | with only what you need. I always used to wrap the wrappers | anyway! As far as UI stuff goes, there are actually a lot of | really nice vanilla JS libs out there which play really nicely | with LiveView's JS hooks. | | I would be interested to hear what people have been _sorely_ | missing, though. | | EDIT: Said "are" when I meant "aren't" | arrowsmith wrote: | Your experience matches mine. And ChatGPT has been a game- | changer - if there isn't an Elixir library for some third- | party API, GPT is very good at generating some wrapper | functions in Elixir using the API docs. | davidw wrote: | Oh, I don't think the library thing and ecosystem is really | an obstacle for using Elixir so much as it makes Rails a | 'safe bet'. | | If I'm putting on my business hat, I need a reason to use | Elixir instead of Rails and that probably has something to do | with a better concurrency story, but I'm always curious to | hear what other people are getting out of it. | | My previous experience with BEAM was using Erlang in a semi- | embedded environment and it was fantastic for that. Solid, | dependable, deterministic, great response times... all of | that. But while we did have a web interface to the system, it | wasn't a web site. | bcrosby95 wrote: | For us its the simplified production environment. We use | BEAM's clustering capability to forgo things like redis | and/or a message queue. It probably doesn't matter for | every company, but it helps for us where we have zero full | time ops people. | hmmokidk wrote: | And if you forgo those things you can easily test them. | davidw wrote: | That's a pretty good reason. Some people might react | "well, you're going to need those things broken out | anyway as you scale" or something to that effect, but it | can be really nice to just not need them until you have | scaled further. There are plenty of smaller applications | where you just don't want or need all the extras and the | longer you can keep it simpler, the better off you are. | sodapopcan wrote: | Ya, this is one big bonus in my eyes. I have certainly | hear the argument several times that "installing redis is | really easy" and it is! But it's another moving part that | often isn't necessary with BEAM. | | In a current project I'm also able to use OTP to create a | single microservice for my monolith that runs on its own | node and the two can communicate with run-of-the-mill | message passing without the need for an HTTP API. | OkayPhysicist wrote: | The BEAM's multi-node scaling works really well. The | argument that you'll need to break things out if you get | big enough doesn't really hold water. | hosh wrote: | And even if you need to break things out, you can build | different variants of distributions that can all still | work together. | davidw wrote: | BEAM isn't magic scaling sauce, and you're going to run | into trouble if you get big enough. But that's a "good | problem to have". And it's probably 'enough' for many | businesses as-is. | OkayPhysicist wrote: | It's not magic, but neither are any of the alternatives. | There needs to be a compelling "my constellation of | services written in a variety of languages, communicating | via a half-baked homebrew collection of API calls beats a | constellation of distributed Erlang applications | communicating via message passing over the BEAM" to claim | that Erlang has scaling issues relative to the | alternative. | | The reality is that asynchronous, parallel, distributed | computing is hard, Erlang makes it easier. Not easy, but | easier. | toast0 wrote: | > Some people might react "well, you're going to need | those things broken out anyway as you scale" or something | to that effect, but it can be really nice to just not | need them until you have scaled further. | | Dist messaging and mnesia scale pretty far. Although it | must be noted that they were original built around rock | solid networking (two nodes in one chasis), so if your | networking is flakey, you have to handle that; my | recommendation is to make your network not flakey, but | that's easier to say than it is to do. | davidw wrote: | I would pair BEAM with Postgres, not Mnesia as that's | going to limit you in a lot of ways. Unless you | reaaaaaally know what you're doing. | toast0 wrote: | Well, I like to think I know what I'm doing. And I've | participated in some big Mnesia operations. | | That said, redis is in memory key-value, and Mnesia does | in memory key-value too. If you're using Postgres's | relational stuff or data bigger than memory, that's a | different thing. Mnesia has some relational facilities, | but I dunno if anybody uses them much; mnesia can use | disc_only_copies, but that's not a good time. Of course, | memory only gets you pretty big tables these days; I ran | some mnesia nodes with 768GB, but a couple TB isn't too | hard to put together these days. | arrowsmith wrote: | My reason to use Phoenix instead of Rails: development | speed. I'm just so blazingly productive in Phoenix that | nothing else compares, including Rails. Every time I'm | forced to develop in another framework I now get | agonisingly frustrated by how long it takes to get anything | done. | throwanem wrote: | Seems struggling at the moment. Archive link: | https://web.archive.org/web/20230803145324/https://wiki.alop... | mcguire wrote: | " _This is the root of my curmudgeoniness: Magic is never worth | it. 99% of the time, Magic breaks. And when it does, and someone | inevitably asks me to help fix it, I do it by getting out the | machete and chopping out all the happy shiny convenient shit | until you can see what is actually going on. And when you dig | through the Magic and try to figure out what the hell is actually | going on, most of the time it's either stupid and broken by | design, or it's not very magical at all and you're just like "why | didn't you just say this in the first place?"_ | | " _Over and over again, it turns out that there is no such thing | as Magic, and anyone who says otherwise is skimming over details | that will bite you in the ass later on. This is fine for many | purposes, because 90% of programs are small hacks and one-off | tools and so "later" very seldom actually happens._ " | | Oh, yeah. This. So much this. A dump-truck load of this. | | Even better when everybody is using different Magic, or the guy | who set up this Magic left two years ago and everything has been | done my cargo-cult since. | weatherlight wrote: | Elixir is probably my favorite dynamic language and a lot of that | has to do with the community that sprung up around it. I wish it | were more popular. | hosh wrote: | I don't wish it to be super popular. | | I heard the argument before that JS (and Nodejs) is popular | (top 3), so you should go into it. | | I'm now in a nodejs shop. Turns out, the way Erlang and Elixir | is designed serves as a filtering function for hiring. People | who just wants to code without putting a lot of thought into | it, don't go into Elixir and land in JS instead. (All the | current coworkers I have wants to make things better but we are | saddled with code that has been ... oddly written) | | At the last Elixir shop I was at, I was part of a small crew | that was more experienced as a whole than other shops I have | been at. And I liked it. | no_wizard wrote: | Popularity is a multiple faceted issue w/r/t quality of | engineers in any given language. | | One caveat to any of it is the easier a language is to grok | and the more use cases it has, the more likely it will | attract all types of developers and there will always be more | "bottom end" developers than "top end" developers, as is | patterned out in any large distribution. | | That said, here's some facets to consider about this | | - Its not likely its the language (or to be charitable, not | _just_ the language) at play here. As noted above, the more | popular something is, the more likely you end up with a wider | varieties of folks at very different backgrounds / skill | levels etc. Python and PHP have similar issues. | | - The more popular the language is, is often correlated to | its use cases. For example, JavaScript is hugely popular in a | wide swath of problem domains, from the server, to the web | (its de facto monopoly right now) to desktop apps to even now | mobile (Ionic, NativeScript etc). This leads to the top | developers in the language often going to very lucrative | positions that one would also presumably have to be working | alongside or as part of to be working with them | | - Its harder in a bigger pool to work with the top N % of | developers in any given language or (better yet, any given | environment / problem space deploying that language as part | of its core technological backbone). The big "sea" in the | middle is what you're most likely to be apart of | | I think smaller communities benefit from organic interest, | people who are enthusiastic to use the technology and | therefore often the perceived quality of those developers is | higher (and often it does correlate, see: the history of | Clojure) | | I don't think a language in and of itself is to blame, except | in that maybe, because some languages like Python and | JavaScript are so easy to pickup as opposed to say, Java, | Kotlin, C# or Rust, that they attract more developers in | general. That said, I think its the laws of distribution at | work, and not really the driven by the language per se. ___________________________________________________________________ (page generated 2023-08-03 23:00 UTC)