lorenzo

lorenzo

Does my frustration with Node merit switching to Elixir?

Hey everone!

I created a prototype for my app using Nodejs for the api. But the framework I chose wasnt great (in general theresnt any great node framework) and I find I’m wasting a lot of time setting everything up myself: an orm, testing, seeding, typescript, dependency injection etc. I have a basic setup going but it feels brittle. I really don’t know how people can be productive with nodejs. And it’s even worse since I chose to use graphql and most frameworks/docs/tutorials tailor towards REST.

My question is, is it worth switching to Elixir despite having more experience with Javascript/Node? They’re both performant, so my main concern I guess would be productivity. But part of me is thinking “the grass is always greener.” With Elixir I’d have to learn an entire new language and framework. But part of me feels that I’d be easier to learn well since everything fits nicely together.

Other factors:

  • Apollo graphql has done wonders for node.js. It makes a huge framework less necessary, but you still have to figure out how to integrate it with your setup. While absinthe seems to fit nicely with Elixir/Phoenix out of the box.
  • It’s nice to have everything in one monorepo and one language (Javadcript plus typescript). But part of me feels that trying to keep this is causing more headaches than its solving.
  • Deployment with Node.js is a breeze - all it takes is a single command to deploy to zeit’s now. Whereas from what I’ve read deploying Elixir is not as fun.
  • The node.js ecosystem is so fragmented that it’s hard to learn. There isn’t really any great books that guide you through the process since theres so many solutions for everything. Whereas with Elixir, I feel that the path would be more straight-forward. The question is time. I’ve already taken way too much time getting my app going and I feel like I’m running in circles at this point.

Anyway, I’d love to hear any advice or other considerations you may have on this whole backend fiasco, especially if any of you recently switched from Node.js as well.

Thanks!

Most Liked

aamerabbas

aamerabbas

Hi, I switched from Node to Elixir. I am generally happy with the switch, but it really just depends on what your needs and expectations are. I personally really like the coherence of the community and the batteries-included approach of Phoenix. The community has basically taken the opinionated stance of Rails, but fixed most of the shortcomings.

Anyway, I’m sorry people are not answering your questions seriously. We all have to start somewhere and it’s very frustrating when people trivialize these challenges. I went through some of these struggles myself. Let me tell you my setup, and I hope it helps you out.

I am essentially doing the following for my Phoenix application:

  • I build my Elixir code using the “mix release” task
  • I get all the dependencies and package them up in a container
  • I deploy using Kubernetes (in my case, on Google Cloud)
  • I use BitBucket pipelines to automate the testing and deployment process.

My Dockerfile looks something like this:

FROM elixir:1.7.1-alpine
ARG APP_NAME=my_app
ARG PHOENIX_SUBDIR=.
ENV MIX_ENV=prod REPLACE_OS_VARS=true TERM=xterm
WORKDIR /opt/app
RUN apk update \
    && apk --no-cache --update add nodejs nodejs-npm make g++ python git imagemagick \
    && mix local.rebar --force \
    && mix local.hex --force
COPY . .
RUN mix do deps.get, deps.compile, compile
RUN cd ${PHOENIX_SUBDIR}/assets \
    && npm install \
    && ./node_modules/brunch/bin/brunch build -p \
    && cd .. \
    && mix phx.digest
RUN mix release --env=prod --verbose \
    && mv _build/prod/rel/${APP_NAME} /opt/release
FROM alpine:latest
RUN apk update && apk --no-cache --update add bash openssl-dev imagemagick
ENV PORT=8080 MIX_ENV=prod REPLACE_OS_VARS=true
WORKDIR /opt/app
EXPOSE ${PORT}
COPY --from=0 /opt/release .
CMD ["/opt/app/bin/my_app", "migrate_seed_and_start"]

My bitbucket pipeline config looks something like this

image: elixir:1.7.1-alpine

pipelines:
  default:
    - step:
        name: Test
        script:
          - apk update
          - apk --no-cache --update add coreutils nodejs nodejs-npm make g++ python git imagemagick bash curl tar
          - MIX_ENV=test mix local.rebar --force
          - MIX_ENV=test mix local.hex --force
          - MIX_ENV=test mix deps.get
          - MIX_ENV=test mix deps.compile
          - MIX_ENV=test mix ecto.create
          - MIX_ENV=test mix ecto.migrate
          - mix test
        services:
          - database
    - step:
        name: Build and Deploy
        trigger: manual
        script:
          - apk update
          - apk --no-cache --update add coreutils nodejs nodejs-npm make g++ python git imagemagick bash curl tar
          # Installing gcloud
          - curl -o $HOME/google-cloud-sdk.tar.gz https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-207.0.0-linux-x86_64.tar.gz
          - tar -xvf $HOME/google-cloud-sdk.tar.gz -C $HOME/
          - $HOME/google-cloud-sdk/install.sh
          - source $HOME/google-cloud-sdk/path.bash.inc
          - export PATH="$HOME/google-cloud-sdk/bin:$PATH"
          - gcloud -v -q
          # Installing kubectl
          - gcloud components install kubectl -q
          # Authentication
          - echo $GCLOUD_API_KEYFILE | base64 --decode --ignore-garbage > ./gcloud-api-key.json
          - gcloud auth activate-service-account --key-file gcloud-api-key.json
          - gcloud config set project my_app
          - gcloud container clusters get-credentials my_app --zone=europe-west1-d
          - kubectl version
          # Deploy
          - source $BITBUCKET_CLONE_DIR/build.sh $BITBUCKET_BUILD_NUMBER
          - source $BITBUCKET_CLONE_DIR/deploy.sh $BITBUCKET_BUILD_NUMBER
        services:
          - docker
              
definitions:
  services:
    database:
      image: postgres:9.6
      environment:
        POSTGRES_PASSWORD: secret
    docker:
      memory: 2048

Also, you will notice a build.sh and deploy.sh file referenced here. These are small simple scripts I made. They look like this:

Build.sh

VERSION="$1";

if [ -z "$VERSION" ]
then
  echo "Must specify a version to tag the docker container";
  exit;
fi

docker build --no-cache -t "eu.gcr.io/my_app/my_app:$VERSION" . && \
gcloud docker -- push "eu.gcr.io/my_app/my_app:$VERSION"

Deploy.sh

#!/bin/bash

VERSION="$1";

if [ -z "$VERSION" ]
then
  echo "Must specify a version to tag the docker container";
  exit;
fi

kubectl set image deployment/my_app my_app=eu.gcr.io/my_app/my_app:$VERSION
OvermindDL1

OvermindDL1

Well hey, the Absinthe Elixir library has you covered there!

If you use any of the immutable functional libraries in javascript then you’ve got the ideas of Elixir already down, if not then that will mean learning a bit new of a paradigm.

Elixir is worth learning due to the entire BEAM VM it runs on though, but honestly if your current system runs well and can be maintained without much issue I’d keep it. But if you want to learn a new way, or if you want to be able to scale well, or if you just likely want to shorten your code and improve maintainability then Elixir would be great to use. Just be aware of what you are doing, though porting an existing working project from something else to Elixir is definitely a good way to learn things. :slight_smile:

Yep, Absinthe works with the Apollo client code just fine too!

Never heard of zeit’s, but deploying my elixir server’s is just running a single shell script then bouncing the server via systemd (which I could easily automate too, but haven’t yet because eh… easy enough).

Elixir is exceptionally well documented and has a fantastic community for sure!

But yeah, if your current thing works and you see it doing fine as it is in the future then I’d say just keep at it, only port it over if you want to learn. However if you see pain with it in the future then it may be worth porting to Elixir sooner.

aaron-price

aaron-price

TLDR: My biggest regret was not switching to elixir sooner. I suggest following the udemy course by Stephen Grider. It’s a bit old, but it should give you enough to decide whether you want to make the leap or not.

I also came from node (nextjs + redux + mongodb + heroku) for many of the same reasons.
My current project is Elixir + phoenix + react + redux + postgres (for users) + arangodb (for graph data) + graphql inside arangodb. I don’t bother with absinthe, just send a POST request with a string.

For my own project I wanted something really performant, and the js crowd seems to think that js is performant because it’s async. But dealing with async was a huge pain my rear. Especially when you start using things like mongoose, where it uses it’s own promise library, but parts of it you can do with async/await (promises), but there’s the occasional undocumented thing in mongoose that ONLY works with old school callbacks… That lead to a great deal of frustration.

Elixir is more performant. WAY more. And its async system (processes) is WAY easier to reason about. Processes are also truly asyncronous, while the js event loop is technically just a highly optimized, yet synchronous system.

Then you have immutability. I remember the time I spent days trying to figure out why my array was changing by itself. Oh, you used an Array.prototype method on a different array? Too bad!

That is not an issue in elixir.

Or how about setting things up. Expressjs is awesome because it’s so lightweight and lets you roll your own stack… but eventually I found that to be its greatest weakness. There’s several different ways to do anything in node. When you look for help, you often have to explain your whole setup, and pray that someone had the same setup with the same problem.

Elixir comes with testing. I find it better than jest, jasmine, or mocha.
Elixir has a rails-like framework (phoenix). Built in CSRF validation and sessions, ORM, and an intuitive organization of code. Of course if you really want to roll your own, that’s still easy enough.

Where Next?

Popular in Discussions Top

AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
mbenatti
Following https://github.com/tbrand/which_is_the_fastest |> https://raw.githubusercontent.com/tbrand/which_is_the_fastest/master/imgs...
New
AstonJ
I’ve just started the Phoenix part of the utterly brilliant online course by @pragdave. On generating the Phoenix app he uses the --no-ec...
New
New
WildYorkies
It seems that the more I read, the more I find Elixir users speaking about all the ways that Elixir is not good for x, y, and z use cases...
New
tmbb
This is a post to discuss the new Phoenix LiveView functionality. From Chris’s talk, it appears that they generate all HTML on the serve...
342 18243 126
New
opsb
We’re considering our architecture from a viewpoint of scaling our traffic heavily over the next 6 months. Our current deployment is runn...
New
pillaiindu
I want to convert a Phoenix LiveView CRUD website to a CRUD mobile app. What do you think is the easiest way to do so?
New
arpan
Hello everyone :wave: Today I am very excited to announce a project that I have been working on for almost 3 months now. The project is...
New
shishini
I think this twitter post and youtube video didn’t get as much attention as I hoped I am still new to Elixir, so can’t really judge ...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement