Rework BEAM slide for web dev audience, mention Oban for background jobs

Torey Heinz committed Feb 22, 2026
commit 3d6739c7419b19e9aba23cd75171877d62baaacb
Showing 1 changed file with 14 additions and 10 deletions
slides/01-intro.html +14 -10
@@ @@ -157,10 +157,10 @@
<h2>The BEAM</h2>
<p>Erlang's virtual machine &mdash; designed from scratch for concurrent, networked applications.</p>
<ul>
- <li class="fragment"><strong>Millions of lightweight processes</strong> &mdash; not OS threads, much cheaper</li>
- <li class="fragment"><strong>Preemptive scheduling</strong> &mdash; no single process can hog the CPU</li>
- <li class="fragment"><strong>Per-process garbage collection</strong> &mdash; no stop-the-world pauses</li>
- <li class="fragment"><strong>Built-in distribution</strong> &mdash; processes communicate across machines</li>
+ <li class="fragment"><strong>One process per request</strong> &mdash; ~2KB each, millions at once</li>
+ <li class="fragment"><strong>Preemptive scheduling</strong> &mdash; no request can starve others</li>
+ <li class="fragment"><strong>Per-process GC</strong> &mdash; no stop-the-world pauses</li>
+ <li class="fragment"><strong>Crash isolation</strong> &mdash; a single process can't take down the app</li>
</ul>
<p class="fragment muted" style="margin-top: 1em; font-style: italic;">
Arguably the best runtime ever built for this problem.<br/>
@@ @@ -168,7 +168,12 @@
</p>
<aside class="notes">
- The BEAM is the runtime that actually runs the code, and it's fundamentally different from the JVM or Node. Lightweight processes cost about 2KB each, and you can run millions of them. The scheduler is preemptive — no process can block others. And garbage collection is per-process, so you never get those stop-the-world pauses. The catch? Erlang syntax is... an acquired taste. That's where Elixir comes in.
+ The BEAM is the runtime, and it's fundamentally different from V8 or the JVM.<br>
+ Every request gets its own process — about 2KB each — so you can handle millions concurrently. Not threads, not coroutines — real isolated processes.<br>
+ The scheduler is preemptive. In Node, one CPU-heavy request blocks the event loop for everyone. On the BEAM, the scheduler gives every process a fair slice — no one gets starved.<br>
+ Garbage collection happens per-process. In Node or the JVM, GC can pause your entire app. Here, only the process being collected pauses — everyone else keeps running.<br>
+ And crash isolation — if one request hits a bug, that process dies alone. The rest of your app doesn't even notice. Compare that to an unhandled exception crashing your Node process.<br>
+ The catch? Erlang syntax is... an acquired taste. That's where Elixir comes in.
</aside>
</section>
@@ @@ -180,9 +185,8 @@
&ldquo;What if we took the best runtime in the world and made it a joy to write?&rdquo;
</blockquote>
<ul>
- <li class="fragment"><strong>Modern syntax</strong> &mdash; inspired by Ruby, approachable for web devs</li>
+ <li class="fragment"><strong>Modern syntax</strong> &mdash; inspired by Ruby</li>
<li class="fragment"><strong>Excellent tooling</strong> &mdash; Mix, Hex, ExUnit</li>
- <li class="fragment"><strong>Metaprogramming</strong> &mdash; macros that extend the language cleanly</li>
<li class="fragment"><strong>Full Erlang access</strong> &mdash; 40 years of battle-tested libraries</li>
</ul>
<p class="fragment small" style="margin-top: 0.8em; color: #555;">
@@ @@ -241,12 +245,12 @@
<ul>
<li class="fragment"><strong>Concurrency</strong> &mdash; web apps are I/O bound; most time is spent waiting on databases, APIs, file systems</li>
<li class="fragment"><strong>Fault tolerance</strong> &mdash; processes crash in isolation, supervisors auto-restart them</li>
- <li class="fragment"><strong>Real-time built in</strong> &mdash; WebSockets via Phoenix Channels &amp; LiveView, no extra infra</li>
- <li class="fragment"><strong>Built-in background processing</strong> &mdash; GenServers replace Redis + Sidekiq/Bull</li>
+ <li class="fragment"><strong>Real-time built in</strong> &mdash; WebSockets via Phoenix Channels &amp; LiveView, no extra infrastructure</li>
+ <li class="fragment"><strong>Background jobs built in</strong> &mdash; native processes + Oban replace Redis + Sidekiq/Bull</li>
</ul>
<aside class="notes">
- Web apps are I/O bound — most time is spent waiting on databases and APIs. The BEAM was built for exactly this. But it's not just concurrency. Fault tolerance means one bad request doesn't crash your app — supervisors restart failed processes automatically. Real-time is built right in with Phoenix Channels and LiveView — no Redis pub/sub or Socket.io needed. And background processing? GenServers handle what you'd normally need Sidekiq or Bull for — rate limiters, caches, scheduled jobs — all in the same app, no external dependencies.
+ Web apps are I/O bound — most time is spent waiting on databases and APIs. The BEAM was built for exactly this. But it's not just concurrency. Fault tolerance means one bad request doesn't crash your app — supervisors restart failed processes automatically. Real-time is built right in with Phoenix Channels and LiveView — no Redis pub/sub or Socket.io needed. And background processing? The BEAM lets you spin up lightweight processes for things like rate limiters and caches right in your app. For persistent job queues — retries, scheduling, prioritization — there's Oban, backed by Postgres. No Redis required. It replaces what you'd use Sidekiq or Bull for.
</aside>
</section>