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
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
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. ![]()
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
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.
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









