Elixir untuk Technical Leader — Bab 1 dari 10

Kenapa Elixir & BEAM

Bukan "bahasa terbaik di dunia" — tapi bahasa yang paling cocok untuk LabaBersih. Dan kamu harus tau kenapa.


Sejarah Singkat (2 Menit)

Elixir lahir tahun 2012, dibuat oleh José Valim — core contributor Ruby on Rails. Dia frustrasi: Ruby bagus untuk developer happiness, tapi jelek untuk concurrency (handle banyak hal bersamaan).

José gak bikin dari nol. Dia bangun Elixir di atas BEAM — virtual machine yang sudah proven selama 30+ tahun di industri telekomunikasi (Ericsson, WhatsApp).

Analogi BEAM = mesin mobil yang sudah terbukti 30 tahun (Ericsson). Elixir = bodi mobil baru yang lebih nyaman dikendarai. Kamu dapet keandalan mesin lama + kenyamanan desain baru.

Timeline penting:

TahunEventRelevansi
1986Erlang dibuat di EricssonFondasi BEAM — dipakai untuk switch telepon yang gak boleh mati
1998Erlang di-open-sourceKomunitas mulai tumbuh
2009WhatsApp pakai Erlang2 juta koneksi per server. Proof bahwa BEAM scale.
2012Elixir v0.1 rilisSyntax modern di atas BEAM
2014Phoenix Framework rilisWeb framework — competitor Ruby on Rails
2016Phoenix LiveViewReal-time UI tanpa JavaScript — ini yang LabaBersih pakai
2024Elixir 1.17+ stableMature, production-ready, growing

BEAM — Mesin di Balik Elixir

BEAM = Bogdan/Björn's Erlang Abstract Machine. Ini virtual machine (kayak JVM untuk Java). Semua code Elixir jalan di atas BEAM.

Kenapa BEAM spesial? 4 Superpower:

1. Lightweight Processes (Bukan Thread OS)

BEAM bisa jalankan jutaan proses secara bersamaan. Bukan thread OS yang berat (1 thread = ~1MB RAM). BEAM process cuma ~2KB.

# Di LabaBersih, setiap user yang buka browser = 1 LiveView process
# 100 user online = 100 process. Ringan banget.
# Di Next.js v1: 100 user = 100 HTTP connection, masing-masing stateless
Buat Hafish Ini kenapa LabaBersih bisa handle Nelly + tim buka dashboard bersamaan tanpa lag. Setiap tab browser = 1 BEAM process yang independent. Kalau 1 crash, yang lain gak kena.

2. Fault Tolerance ("Let it crash")

Filosofi BEAM: kalau 1 proses error, biarkan crash — supervisor akan restart otomatis. Gak perlu try-catch di mana-mana.

v1 (Next.js + Supabase)
1 Edge Function error = user lihat halaman error. Manual refresh. Kalau error di cron job, gak ada yang restart — harus manual redeploy.
v2 (Elixir/BEAM)
1 process crash = supervisor restart dalam milidetik. User bahkan gak sadar ada error. Oban job gagal? Auto-retry sesuai config.

3. Hot Code Reload

BEAM bisa update code tanpa mematikan server. Ericsson pakai ini untuk switch telepon yang literally gak boleh mati 24/7.

Untuk LabaBersih: saat development, kamu ubah code → browser auto-refresh (LiveView). Gak perlu restart server.

4. Distribution (Multi-Node)

BEAM process bisa komunikasi antar server semudah komunikasi di 1 server. Ini kenapa WhatsApp bisa 2 juta koneksi per server — mereka connect banyak BEAM node.

Untuk LabaBersih sekarang: belum perlu (1 server Fly.io cukup). Tapi kalau scale ke 50.000 order/hari, tinggal tambah node. Arsitektur gak perlu berubah.


Kenapa Elixir Cocok untuk LabaBersih

Ini bukan soal "Elixir terbaik" — ini soal match antara kebutuhan bisnis dan kemampuan teknologi.

Kebutuhan LabaBersihSolusi ElixirSolusi Lain
6.300 order/hari, banyak concurrent user BEAM processes, ringan, gak butuh scaling infrastruktur Node.js bisa, tapi butuh load balancer + multiple instances lebih cepat
Real-time dashboard (stok, order, laporan) LiveView — server push ke browser via WebSocket. Built-in. React + WebSocket = 2 layer terpisah, lebih complex
Background jobs (sync API, daily journal, cron) Oban — persistent job queue, retry, scheduling. 1 dependency. Redis + Bull/BullMQ + separate worker process
Atomic transactions (ship order = 5 langkah) Ecto + Repo.transaction — kalau 1 gagal, semua rollback Prisma/Drizzle bisa, tapi pattern-nya kurang natural
Pattern matching untuk status transition Built-in di bahasa. "dikemas" → "dikirim" = 1 baris code. If-else chain. Error-prone.
Hosting murah ($10-15/bulan) Fly.io — Phoenix optimized, Singapore region Vercel + Supabase = $45/bulan (v1 actual cost)
1 bahasa end-to-end Elixir untuk backend + LiveView untuk frontend = 1 bahasa TypeScript + React + SQL = 3 bahasa/paradigma
Keputusan kamu benar Kamu pilih Elixir bukan karena hype — tapi karena kebutuhan: real-time, concurrent, murah, 1 bahasa. Itu keputusan teknis yang solid.

v1 vs v2 — Perbedaan Arsitektur

Supaya kamu paham apa yang berubah secara fundamental:

v1: 3 Layer Terpisah

# v1 Architecture (Next.js + Supabase)

Browser (React/Next.js)
    ↓ HTTP request
Supabase Edge Functions (31 functions, Deno runtime)
    ↓ SQL query
PostgreSQL (Supabase, + 16 RPC functions di database)

# Masalah:
# - Logic tersebar di 3 tempat (React, Edge, SQL)
# - Gak ada shared type system
# - Error baru ketemu saat runtime
# - Edge Function stateless = gak bisa share state

v2: 1 Layer Terintegrasi

# v2 Architecture (Elixir/Phoenix)

Browser (HTML dari LiveView, minimal JS)
    ↑↓ WebSocket (persistent connection)
Phoenix LiveView + Contexts (semua logic di 1 tempat)
    ↓ Ecto query
PostgreSQL (Fly.io, zero stored procedures)

# Keuntungan:
# - Logic HANYA di Elixir contexts (1 tempat)
# - Compile-time error checking
# - Persistent WebSocket = real-time tanpa polling
# - Database bersih = hanya data, gak ada logic
Implikasi untuk kamu sebagai leader Di v1, kalau ada bug kamu harus cari di 3 tempat (React? Edge Function? RPC?). Di v2, bug PASTI di context file. 1 tempat. Ini bukan cuma soal teknologi — ini soal kecepatan kamu menemukan dan mengarahkan fix.

Compile-Time Safety — Kenapa Ini Game Changer

Ini yang tadi kamu lihat dari LSP diagnostics. Elixir punya 3 lapis pengecekan sebelum code jalan di production:

Lapis 1: Compiler

Elixir compiler cek setiap kali kamu save file:

# Kamu tulis ini (typo di nama function):
Orders.shiip_order(order_id, email)

# Compiler langsung bilang:
# ** (UndefinedFunctionError) function Orders.shiip_order/2 is undefined
# Did you mean: ship_order/2

# Di v1 (JavaScript): GADA ERROR sampai user klik button dan function dipanggil

Lapis 2: Dialyzer (Type Analysis)

Ini yang ElixirLS pakai — analisis tipe data tanpa kamu nulis type annotation:

# Dialyzer detect: "pattern {:ok, _} can never match"
# Artinya: function itu SELALU return {:error, _}
# Code path {:ok, _} = DEAD CODE, gak pernah kepakai

# Ini yang tadi kamu lihat di sync_facebook.ex, sync_scalev.ex, sync_tiktok_ads.ex
# Kalau di v1: gak ada yang detect. Silent fail.

Lapis 3: Tests (ExUnit)

# 133+ automated tests di LabaBersih v2
# v1 punya: 0 (nol) automated tests

# Setiap function penting di-test:
# - ship_order happy path + edge cases
# - jurnal balanced (debit = credit)
# - FEFO lot consumption order
# - Status transition enforcement
Red Flag kalau kamu lihat ini Kalau Claude bikin function tanpa test → TOLAK. Aturan LabaBersih: setiap function WAJIB punya test. Gak ada "nanti aja". Ini bukan optional — ini insurance policy untuk bisnis kamu.

Batteries Included — Tooling Bawaan Elixir

Salah satu alasan Elixir terasa "lengkap" dibanding stack lain: hampir semua tools yang kamu butuhkan sudah built-in atau 1 dependency away. Gak perlu rakit sendiri kayak JavaScript ecosystem.

Tools Inti (Built-in, gak perlu install)

ToolApaCommandAnalogi di Dunia Lain
Mix Build tool + project manager + task runner. SATU tool untuk semuanya. mix compile, mix deps.get, mix ecto.migrate npm + webpack + Makefile jadi satu
IEx Interactive shell. Bisa connect ke server yang sedang jalan dan jalankan function live. iex -S mix Chrome DevTools console, tapi untuk backend
ExUnit Testing framework. Built-in, zero config. mix test Jest (JS) — tapi gak perlu install
Logger Structured logging. Level: debug, info, warning, error. Logger.info("Order shipped") console.log tapi terstruktur + level
Hex Package manager & registry. mix hex.search oban npm registry
Observer GUI monitor semua BEAM processes, memory, CPU. Bisa lihat real-time. :observer.start() di IEx Chrome DevTools Performance tab

Tools Ecosystem (1 dependency, minimal config)

ToolApaCommandAnalogi
ExDoc Generate website dokumentasi dari @moduledoc dan @doc di code kamu. mix docs → buka doc/index.html JSDoc / Swagger — tapi output-nya cantik
Credo Code linter. Cek style, complexity, consistency. mix credo ESLint — tapi tanpa config 50 baris
Dialyzer Type checker. Analisis tipe data tanpa kamu nulis type annotation. Ini yang dipakai ElixirLS (LSP) untuk detect dead code. mix dialyzer TypeScript compiler (tapi optional & inferred)
Sobelow Security scanner. Detect SQL injection, XSS, hardcoded secrets. mix sobelow npm audit + Snyk
Phoenix LiveDashboard Real-time web monitoring. Buka di browser, lihat memory, query time, Oban jobs. Buka /dev/dashboard di browser Vercel Analytics + Datadog — tapi gratis & built-in

Perbandingan Langsung: v1 vs v2

v1 (Next.js + Supabase)

Build: npm + webpack + next
Test: Jest (install, config)
Lint: ESLint + Prettier (2 tools, 2 configs)
Type: TypeScript (setup tsconfig)
Docs: Gak ada
Monitor: Gak ada built-in
Security: npm audit (noise banyak)
Deps: node_modules ~500MB
v2 (Elixir/Phoenix)

Build: Mix (1 tool)
Test: ExUnit (built-in, zero config)
Lint: Credo (1 dep, zero config)
Type: Dialyzer (otomatis via LSP)
Docs: ExDoc → website docs
Monitor: LiveDashboard (buka browser)
Security: Sobelow (1 dep, zero config)
Deps: _build + deps ~50MB

Mix Commands yang Kamu Harus Tau

Ini perintah terminal yang bisa kamu jalankan sendiri tanpa Claude:

# ── DEVELOPMENT ──
mix phx.server          # Start development server (buka localhost:4000)
mix deps.get            # Install dependencies (kayak npm install)
mix compile             # Compile code — detect errors SEBELUM jalankan

# ── DATABASE ──
mix ecto.create         # Buat database baru
mix ecto.migrate        # Jalankan migration (ubah struktur tabel)
mix ecto.rollback       # Undo migration terakhir (kalau salah)
mix ecto.reset          # Drop + create + migrate (HATI-HATI: hapus semua data!)
mix run priv/repo/seeds.exs  # Isi data sample

# ── QUALITY ──
mix test                # Jalankan semua test (133+ tests)
mix test --failed       # Cuma jalankan test yang gagal terakhir
mix test test/lababersih/orders/orders_test.exs  # Test 1 file aja
mix credo               # Code quality check
mix sobelow             # Security scan
mix dialyzer            # Type analysis (lama pertama kali, cepat setelahnya)

# ── DOCS ──
mix docs                # Generate HTML docs → buka doc/index.html
mix hex.docs online ecto  # Buka docs library di browser

# ── DEPLOYMENT ──
mix phx.gen.release     # Generate Dockerfile untuk production
mix release             # Build production binary
fly deploy              # Deploy ke Fly.io (ini CLI Fly, bukan Mix)
Buat Hafish Kamu gak perlu hapal semua. Yang paling sering kamu pakai: mix test (cek apakah code saya gak rusak), mix compile (cek error), mix phx.server (jalankan app lokal). 3 command itu cukup untuk 90% workflow kamu.

ExDoc — Documentation dari Code (Detail)

Ini fitur favorit Elixir community. Setiap @moduledoc dan @doc yang ditulis di code otomatis jadi halaman dokumentasi.

defmodule Lababersih.Orders do
  @moduledoc """
  Order management — pesanan, packing, shipment.

  ## Fungsi Utama
  - `create_order/2` — buat pesanan baru
  - `ship_order/2` — kirim pesanan (atomic 5 langkah)
  - `delete_order/1` — hapus + reverse stok + void jurnal
  """

  @doc """
  Ship order — ATOMIC transaction (5 langkah):
  1. Validasi status = dikemas
  2. Update status → dikirim, set shipped_at
  3. Potong stok per item (FEFO+FIFO lot consumption)
  4. Generate jurnal penjualan + HPP
  5. Insert audit trail

  ## Contoh

      iex> Orders.ship_order("PS2603-00001", "nelly@lababersih.id")
      {:ok, %{order: %Order{}, journal: %JournalEntry{}}}
  """
  def ship_order(order_id, actor_email) do
    # ... implementation
  end
end

Jalankan mix docs → semua @doc di atas jadi halaman web yang bisa di-browse, lengkap dengan navigasi, search, dan cross-reference antar module. Ini yang lu lihat di hexdocs.pm untuk library Elixir manapun.

Implikasi untuk kamu Setiap kali Claude bikin function baru, dia HARUS tulis @doc. Kamu bisa cek: jalankan mix docs, buka di browser, baca apakah dokumentasinya masuk akal. Ini review tanpa baca code — baca docs-nya aja.

IEx — Interactive Shell (Power Tool)

IEx = Interactive Elixir. Bayangkan Chrome DevTools console, tapi bisa akses seluruh backend.

# Start IEx dengan project LabaBersih loaded:
$ iex -S mix

# Sekarang kamu bisa jalankan function APAPUN:
iex> Lababersih.Orders.get_order!("PS2603-00001")
%Order{id: "PS2603-00001", customer_name: "Budi", status: "dikemas", ...}

iex> Lababersih.Inventory.list_products(org_id)
[%Product{name: "Forbest", stok: 100}, ...]

iex> Lababersih.Accounting.trial_balance(org_id)
%{total_debit: #Decimal<5516585336>, total_credit: #Decimal<5516585336>, balanced: true}

# Bahkan bisa connect ke PRODUCTION server yang sedang jalan!
# (Fly.io: fly ssh console)
Hati-hati! IEx di production = power tool. Bisa langsung query/modify data live. Jangan sembarangan jalankan function yang punya side effects (ship_order, delete_order) kecuali memang sengaja.

Immutability — Data Gak Bisa Diubah Diam-Diam

Di Elixir, semua data immutable (gak bisa diubah setelah dibuat). Kalau mau ubah, harus bikin salinan baru.

# JavaScript (v1) — mutable, BAHAYA:
order.status = "dikirim"     # langsung ubah object asli
# Siapa yang ubah? Kapan? Gak ada record.

# Elixir (v2) — immutable, AMAN:
new_order = %{order | status: "dikirim"}
# order asli GAK BERUBAH. new_order = salinan dengan status baru.
# Kalau ada bug, order asli masih intact.
Analogi Accounting Ini persis kayak prinsip jurnal akuntansi: kamu gak boleh hapus/edit jurnal yang sudah posted. Mau koreksi? Bikin jurnal baru (void + re-post). Elixir enforce prinsip ini di level bahasa.

Kenapa ini penting untuk LabaBersih:


Pattern Matching — Preview

Ini akan dibahas mendalam di Bab 2, tapi preview karena ini yang bikin Elixir sangat readable:

# Status transition di LabaBersih v2 (Elixir)
def advance_order_status("dibuat"),    do: {:ok, "diproses"}
def advance_order_status("diproses"),  do: {:ok, "selesai"}
def advance_order_status("selesai"),   do: {:error, "sudah selesai"}
def advance_order_status(status),      do: {:error, "status #{status} gak bisa maju"}

# Baca dari atas ke bawah:
# - "dibuat" → boleh maju ke "diproses"
# - "diproses" → boleh maju ke "selesai"
# - "selesai" → GAK BOLEH maju (sudah final)
# - status lain → GAK BOLEH
#
# Gak ada if-else. Gak ada switch-case. Cuma pattern matching.
# Kamu bisa BACA ini dan langsung paham business rule-nya.
JavaScript equivalent (v1)
function advanceStatus(status) {
  if (status === "dibuat") return "diproses"
  if (status === "diproses") return "selesai"
  if (status === "selesai") throw new Error("sudah selesai")
  throw new Error(`status ${status} gak bisa maju`)
}
Elixir (v2)
def advance("dibuat"),    do: {:ok, "diproses"}
def advance("diproses"),  do: {:ok, "selesai"}
def advance("selesai"),   do: {:error, "sudah final"}
def advance(other),       do: {:error, "invalid"}

Perhatikan: Elixir gak pakai throw / exception. Semua error di-return sebagai {:error, reason}. Caller HARUS handle kedua case. Gak ada silent failure.


Ekosistem — Siapa Lagi yang Pakai

Elixir bukan bahasa eksperimen. Ini perusahaan yang pakai di production:

PerusahaanScalePakai Untuk
WhatsApp2 miliar userBackend messaging (Erlang/BEAM)
Discord200 juta userReal-time messaging, 5 juta concurrent connections
Pinterest450 juta userNotification system, rate limiter
PepsiCoEnterpriseE-commerce platform
Heroku-Routing layer (Erlang)
BrexFintechCore banking system
SupabaseIronic :)Realtime engine (Elixir)
Fly.ioHostingInternal tooling + proxy (Elixir)
Fun fact Supabase (yang kamu pakai di v1) internally pakai Elixir untuk realtime engine mereka. Dan Fly.io (hosting v2) juga dibangun pakai Elixir. Kamu literally pindah ke stack yang provider kamu sendiri pakai.

Risiko — Yang Harus Kamu Tau

Sebagai leader, kamu HARUS tau risikonya. Ini bukan bahasa sempurna.

RisikoLevelMitigasi
Developer pool kecil
Lebih sedikit Elixir dev dibanding JS/Python
Medium Kamu pakai AI (Claude) sebagai developer. Dan Elixir dev yang ada biasanya berkualitas tinggi (self-selected community).
Library ecosystem lebih kecil
Gak sebanyak npm
Medium Hex.pm punya 15.000+ package. Untuk kebutuhan LabaBersih: Ecto, Phoenix, Oban, Swoosh, Req — semua mature. Yang niche, bikin sendiri.
BEAM hosting terbatas
Gak semua hosting support BEAM
Low Fly.io, Gigalixir, Render, AWS (Docker), GCP (Docker). Worst case: Docker container jalan di mana aja.
Fly.io tiba-tiba tutup Low Phoenix release = Docker image standard. Migrate ke provider lain dalam hitungan jam. Gak ada vendor lock-in.
BEAM discontinued Very Low BEAM di-maintain oleh Ericsson (perusahaan telekomunikasi $25B). Erlang/OTP di-develop aktif sejak 1986. Open source. Kalau Ericsson stop, community fork (sudah terjadi — Erlang open-sourced tahun 1998).
José Valim berhenti Low Elixir sudah punya core team, Dashbit (perusahaan José) sustainable, dan banyak kontributor. Bahasa sudah mature.
Exit Strategy (Worst Case) Kalau semua hal buruk terjadi bersamaan (Fly.io tutup + Elixir abandoned + gak ada developer):

1. Export PostgreSQL data (pg_dump) — data kamu aman, format standard
2. Business logic sudah terdokumentasi di CLAUDE.md + business-rules.md
3. Rewrite ke bahasa lain (Go, Node.js) menggunakan dokumentasi yang sama
4. Data structure gak berubah — hanya application layer yang perlu ditulis ulang

Ini JAUH lebih aman dari v1 di mana logic tersebar di 31 Edge Functions + 16 RPC tanpa dokumentasi.

Checklist Review — Pertanyaan yang Bisa Kamu Tanya

Setelah baca bab ini, kamu sekarang bisa tanya hal-hal ini ke Claude (atau developer manapun):

PertanyaanJawaban yang benarRed flag
"Kenapa function ini gak di-test?" "Saya akan bikin test-nya sekarang." "Gak perlu, ini function kecil." ← TOLAK
"Ini jalan di 1 transaction?" "Ya, pakai Repo.transaction, kalau gagal rollback semua." "Setiap step independent." ← BAHAYA untuk operasi multi-step
"Kalau Fly.io mati, gimana?" "Docker image standard, bisa deploy di Render/AWS/GCP dalam jam." "Kita terikat Fly.io." ← SALAH, Phoenix gak vendor-locked
"Kenapa gak pakai TypeScript aja?" "Bisa, tapi untuk case LabaBersih (concurrent, real-time, transactional), Elixir lebih natural. Dan hosting lebih murah." "Elixir terbaik untuk semua case." ← Gak ada bahasa terbaik universal
"Compile error vs runtime error — bedanya?" "Compile = ketemu sebelum deploy (gratis). Runtime = ketemu saat user klik (mahal)." Gak bisa jelasin bedanya ← foundational gap

Ringkasan Bab 1

5 hal yang kamu sekarang tau:

1. BEAM = mesin 30+ tahun dari Ericsson, proven di WhatsApp/Discord scale
2. Elixir = syntax modern di atas BEAM, dibuat 2012, mature
3. Cocok untuk LabaBersih karena: concurrent, real-time, 1 bahasa, murah
4. 3 lapis safety: compiler + dialyzer + tests (v1 punya 0 dari 3)
5. Risiko rendah: BEAM bukan niche, exit strategy jelas, gak vendor-locked