What is Partifly?
Partifly is a communication platform similar to the Discord and Slack platform, but with different goals. It's goal is to orientate people into their own friend groups, create planned events which you actually end up doing without the hassle. A person can simply click a button if they're attending, or not. https://partifly.com is still in its early development and is not yet a completed project.
Now for real: why Phoenix and Elixir, and not something like Node.js, Go, Rust..?
Phoenix and Elixir excel at concurrency, real-time features with their BEAM VM capabilities. Elixir is built on top of the Erlang programming language used in massive systems such as WhatsApp powering 2.3 billion daily active users! Go, Rust, Node.js (TypeScript) are all great languages and runtimes, but we chose Elixir and Phoenix because our main priority was scalability, real-time features, and easy deployments. The partifly backend is deployed on fly.io which has excellent Elixir and BEAM VM support.
What are the tradeoffs we faced?
There were definitely some tradeoffs that we faced when developing Partifly with Phoenix and Elixir.
The ecosystem is a lot smaller compared to Python, Rust, Go.
There are no official standard libraries for Stripe, GCP, and so on. So you'd have to write most of it by hand. But, with the help of AI assistance we managed to shrink the time and debugging of writing the boilerplate implementation.
Different paradigms than other frameworks.
In different ecosystems you would usually stumble upon words like 'middleware'. In Phoenix middleware is a plug. There are a lot of abstractions made inside Phoenix where it takes time and patience to getting used to.
And what are the good things about Phoenix?
Phoenix code generation
Phoenix has an array of useful commands you can run for generating migrations, MVCs, CRUD resources.
Project Generation: Run
mix phx.new my_appto scaffold a brand new Phoenix directory structure.Contexts and Schemas: Use
mix phx.gen.contextto generate the domain logic, schema, and database migration without UI components.HTML Scaffolding: Run
mix phx.gen.htmlto generate a full web interface with controllers, views, and templates for a resource.LiveView Scaffolding: Use
mix phx.gen.liveto build real-time, interactive LiveView CRUD interfaces.Authentication: Run
mix phx.gen.authto add a pre-built, secure authentication system complete with user registration and login.
Ecto as an 'ORM'
Ecto is not really a traditional ORM but more of a database wrapper around SQL for elixir. Elixir is immutable and there is no possible way to mutate objects, so Ecto takes a separate approach on working with SQL databases:
Core Components of Ecto
Instead of a single active record model, Ecto is split into four main parts:
Ecto.Repo: A repository that acts as a wrapper to execute database operations and manage connections.Ecto.Schema: Maps database table columns to Elixir structs (plain data maps).Ecto.Query: A domain-specific language (DSL) for writing type-safe, composable database queries.Ecto.Changeset: Handles casting, filtering, and data validation before changes hit the database.
The let is 'crash' philosophy.
Ahh, this is the classic for almost any BEAM oriented programming language. In a different programming language, runtime, or ecosystem you would write many edge cases where software can be faulty, and crash. Elixir takes a different approach: LET IT CRASH! But why? Elixir has supervisors where each supervisor can restart a failing process (usually called children).
It has different strategies:
Restart Strategies
:one_for_one: If a child process dies, only that specific process is restarted.:one_for_all: If any child process dies, all other children managed by the supervisor are killed and restarted.:rest_for_one: If a child process dies, any processes started after it in the supervision list are terminated and restarted.
Easy distribution; no need to bring in a Kubernetes cluster.
Let's take Go for example; the native language powering Kubernetes. A typical Go service is packaged into containers and deployed behind a load balancer. As the number of instances grows, something needs to decide where the containers run, restart failed instances, scale replicas, perform rolling deployments, and maintain desired state of the cluster. Kubernetes was designed to solve this infrastructure problem.
Kubernetes runs across a cluster of physical or virtual machines called nodes. The control plane manages the cluster's desired state and makes decisions such as scheduling workloads onto nodes. The worker nodes are the machines that run your workloads, with containers grouped into Pods.
With BEAM, distribution can happen at the application-runtime level instead. Having a BEAM cluster with different nodes (BEAM node A, BEAM node B, each of them containing processes).
Beam node scan communicate with each other using Erlang's built-in distribution mechanisms. Processes can send messages across nodes immutably, where applications can use distributed registries such as PubSub, and OTP provides supervision and fault-tolerance primitives. Instead of immediately introducing another orchestration layer such a Kubernetes, you can simply have a Load Balancer attached to different BEAM machines inside of a Distributed BEAM application.
Thanks for reading!
Thank you fellow reader! If you'd like to check out partifly: https://partifly.com

