Refine slides with naming, code simplification, and further trimming

Torey Heinz committed Feb 23, 2026
commit 73a555636aae6c5fb782fcb33e19dad509819c01
Showing 3 changed files with 16 additions and 56 deletions
scratch.md +3 -0
@@ @@ -194,3 +194,6 @@ Review each of these files for typos and consistency. Are we building a case for
- slides/01-intro.html
- 02-the-language.livemd
- slides/03-real-world.html
+
+
+ Let's add this screen shout after "The Core Function" it shows our EPP health page for OrbitFour
slides/01-intro.html +1 -2
@@ @@ -138,12 +138,11 @@
<p class="fragment small muted">The BEAM VM was designed from scratch for this:</p>
<ul>
<li class="fragment"><strong>Lightweight processes</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; one process can't take down the app</li>
</ul>
<p class="fragment muted" style="margin-top: 0.8em; font-style: italic;">
- Battle-tested for 40 years. Nine nines of uptime.<br/>
+ Battle-tested for 40 years. 99.999999% uptime.<br/>
It just wasn't fun to work with...
</p>
slides/03-real-world.html +12 -54
@@ @@ -30,11 +30,11 @@
<section>
<h2>Three Production Systems</h2>
- <p class="muted">Going beyond basic CRUD apps</p>
+ <p class="muted">Going beyond basic Web apps</p>
<ol>
- <li class="fragment"><strong>Email Marketing</strong> &mdash; 500k+ personalized emails</li>
- <li class="fragment"><strong>Domain Registry</strong> &mdash; TCP connections to Verisign</li>
- <li class="fragment"><strong>Internal Admin</strong> &mdash; Multi-site LiveView dashboard</li>
+ <li class="fragment"><strong>Vianet Marketing</strong> &mdash; Email marketing platform</li>
+ <li class="fragment"><strong>OrbitFour</strong> &mdash; full featured domain registration platform</li>
+ <li class="fragment"><strong>Vianet Admin</strong> &mdash; Multi-site LiveView dashboard</li>
</ol>
<aside class="notes">
@@ @@ -43,22 +43,22 @@
</section>
<!-- =============================================
- SECTION 3.1: Email Marketing
+ SECTION 3.1: Vianet Marketing
============================================= -->
<section class="section-divider" data-transition="zoom">
- <h2>Email Marketing</h2>
- <p>500,000+ personalized emails through AWS SES</p>
+ <h2>Vianet Marketing</h2>
+ <p>Sending emails through AWS Simple Email Service (SES)</p>
<aside class="notes">
- First system: our email marketing platform. This sends half a million personalized emails through AWS SES. The challenge isn't just volume — it's doing it reliably without exceeding rate limits.
+ First system: our Vianet marketing platform. This sends half a million personalized emails through AWS SES. The challenge isn't just volume — it's doing it reliably without exceeding rate limits.
</aside>
</section>
<section data-transition="fade">
<img src="images/vianet-marketing.jpg" alt="Vianet Marketing email campaign dashboard" style="max-height: 85vh; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.3);">
<aside class="notes">
- This is our email marketing platform. On the left you can see the campaign details — audience, member count, schedule. On the right, the actual email preview. Over half a million members, and each one gets a personalized email.
+ This is our Vianet marketing platform. On the left you can see the campaign details — audience, member count, schedule. On the right, the actual email preview. Over half a million members, and each one gets a personalized email.
</aside>
</section>
@@ @@ -101,11 +101,11 @@
<pre><code class="language-elixir" data-trim>
def perform(%Oban.Job{args: args}) do
- campaign = Campaigns.get_campaign!(args["campaign_id"])
+ member_ids = Campaigns.member_ids!(args["campaign_id"])
# Stream from DB → chunk → bulk insert jobs
Repo.transaction(fn ->
- Repo.stream(member_ids_query(campaign), max_rows: 2_000)
+ Repo.stream(member_ids(campaign), max_rows: 2_000)
|> Stream.chunk_every(2_000)
|> Enum.each(fn member_ids ->
member_ids
@@ @@ -134,13 +134,11 @@ def perform(%Oban.Job{args: args} = job) do
{:ok, member} <- get_member_with_site(member_id),
{:ok, _} <- validate_email(member.email),
{:ok, campaign} <- get_campaign_with_site(campaign_id),
- {:ok, campaign_email} <- reserve_campaign_email(campaign, member),
{:ok, _} <- EmailRateLimiter.ready?()
) do
send_campaign_email(campaign, member)
else
{:not_ready, :exceeded_rate} -> {:snooze, 1}
- {:not_ready, :exceeded_daily} -> {:snooze, min(backoff(job), 3_600)}
{:already_sent} -> {:discard, :already_sent}
{:invalid_email} -> {:discard, :invalid_email}
{:error, result} -> {:error, result}
@@ @@ -167,8 +165,6 @@ defmodule Marketing.EmailRateLimiter do
def ready?, do: GenServer.call(__MODULE__, :acquire)
def handle_call(:acquire, _from, state) do
- state = refill(state)
-
if state.tokens >= 1.0 do
{:reply, {:ok, :token}, %{state | tokens: state.tokens - 1.0}}
else
@@ @@ -330,44 +326,6 @@ end
</aside>
</section>
- <section>
- <h2>LiveView: Assign Async</h2>
- <p class="muted small">Load from three databases concurrently &mdash; loading states are automatic</p>
-
- <pre class="tiny-code"><code class="language-elixir" data-trim data-line-numbers="1-13|15-23">
- # In mount — load data asynchronously from three databases
- socket
- |> assign_async(
- [:puppies_admins, :roommates_admins, :rr_admins],
- fn ->
- {:ok, %{
- puppies_admins: Puppies.Admins.get_active_admins(),
- roommates_admins: Roommates.Admins.get_admins(),
- rr_admins: ReputableRooms.Admins.get_admins()
- }}
- end
- )
-
- # In template — spinner while loading, then render
- &lt;.async_result :let={admins} assign={@puppies_admins}&gt;
- &lt;:loading&gt;&lt;.spinner /&gt;&lt;/:loading&gt;
- &lt;.input
- type="select"
- label="Puppies admin"
- options={Enum.map(admins, &amp;{&amp;1.name, &amp;1.id})}
- /&gt;
- &lt;/.async_result&gt;
- </code></pre>
-
- <p class="fragment" style="font-size: 0.7em; color: #555;">
- <strong>No loading state management. No useEffect. No fetch.</strong>
- </p>
-
- <aside class="notes">
- Here's assign_async in action. The mount function loads admin lists from three different databases concurrently. Loading states are automatic — the template gets spinners for free. When data arrives, the async_result component renders the content. Compare this to React: you'd need useState, useEffect, a loading boolean, error handling — all wired up manually. Here LiveView handles it all.
- </aside>
- </section>
-
<!-- =============================================
SECTION: Wrap-up
@@ @@ -386,7 +344,7 @@ socket
<ol>
<li class="fragment"><strong>Why Elixir?</strong> &mdash; The BEAM, 40 years of reliability</li>
<li class="fragment"><strong>The Language</strong> &mdash; Pattern matching, processes, supervision, LiveView</li>
- <li class="fragment"><strong>Real-World Code</strong> &mdash; 500k emails, a domain registrar, multi-site admin</li>
+ <li class="fragment"><strong>Real-World Code</strong> &mdash; marketing emails, a domain registrar, multi-site admin</li>
</ol>
<ul style="margin-top: 1em; list-style: none; padding: 0;">
<li class="fragment">Concurrency is the <strong>default</strong>, not an afterthought</li>