1289 lines
30 KiB
Markdown
1289 lines
30 KiB
Markdown
|
|
---
|
|||
|
|
theme: default
|
|||
|
|
#theme: ./themes/rust-vibe
|
|||
|
|
title: Why I Needed Rust
|
|||
|
|
titleTemplate: '%s - Rustikon 2026'
|
|||
|
|
layout: cover
|
|||
|
|
keywords: Rust,programming
|
|||
|
|
download: true
|
|||
|
|
exportFilename: Rustikon_2026_Why_I_Need_Rust
|
|||
|
|
monaco: true
|
|||
|
|
remoteAssets: true
|
|||
|
|
selectable: true
|
|||
|
|
record: true
|
|||
|
|
colorSchema: dark
|
|||
|
|
#colorSchema: white
|
|||
|
|
lineNumbers: false
|
|||
|
|
themeConfig:
|
|||
|
|
primary: '#f74c00'
|
|||
|
|
logoHeader: '/ferris.svg'
|
|||
|
|
fonts:
|
|||
|
|
mono: 'Victor Mono'
|
|||
|
|
drawings:
|
|||
|
|
enabled: true
|
|||
|
|
persist: false
|
|||
|
|
presenterOnly: false
|
|||
|
|
syncAll: true
|
|||
|
|
scripts:
|
|||
|
|
- setup/image-overlay.ts
|
|||
|
|
background: ./images/charles-assuncao-1BbOtIqx21I-unsplash.jpg
|
|||
|
|
class: 'justify-center flex flex-cols photo-bg'
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<h1 class="absolute top-11 left-1/4 font-medium"> Why I Needed Rust </h1>
|
|||
|
|
|
|||
|
|
<h2 class="absolute top-35 left-2/10 font-medium">
|
|||
|
|
Finally, Infrastructure Automation I Can Sleep On
|
|||
|
|
</h2>
|
|||
|
|
|
|||
|
|
<img class="absolute top-48 left-4/10 w-45" src="/jesusperez_w.svg">
|
|||
|
|
|
|||
|
|
<div class="hidden meters-slide bg-transparent!">
|
|||
|
|
<span> 🛡 ●●●○○</span>
|
|||
|
|
<span> 😴 ●●●○○</span>
|
|||
|
|
<span> 🔥 ●○○○○</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
h1, h2, p { z-index: 10}
|
|||
|
|
.meters {
|
|||
|
|
margin-top: 2rem !important;
|
|||
|
|
display: flex;
|
|||
|
|
gap: 2 rem;
|
|||
|
|
font-size: 1rem;
|
|||
|
|
opacity: 0.6 !important;
|
|||
|
|
font-family: monospace;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.two-cols {
|
|||
|
|
column-gap: 1.5rem !important;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<Footer />
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Open: "Who here has been woken up at 3 AM by an infrastructure failure?"
|
|||
|
|
|
|||
|
|
Pause. Look at the room. Nod.
|
|||
|
|
|
|||
|
|
"This talk is for you."
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# <YearsCounter :startYear="1988" :speed="80" :delay="1" /> Years. One Problem.
|
|||
|
|
|
|||
|
|
**1987 → 2025**
|
|||
|
|
|
|||
|
|
<div class="journey">
|
|||
|
|
|
|||
|
|
| Era | Tool | Lesson |
|
|||
|
|
|-----|------|--------|
|
|||
|
|
| 1990s | Perl | Power without safety is a disaster |
|
|||
|
|
| 2000s | Python | Pragmatism without guarantees is fragile |
|
|||
|
|
| 2010s | Bash · Chef · Ansible · Terraform | More tools don't solve paradigm problems |
|
|||
|
|
| 2020s | Go · ??? | |
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="box-highlight text-shadow-lg text-sm p-2 w-1/3 ml-1/3">
|
|||
|
|
Each time, I thought I had the answer. <br>
|
|||
|
|
Each time, reality proved me wrong.
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Don't dwell. Move fast through this slide.
|
|||
|
|
The point is: I've tried everything. This isn't a beginner's opinion.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: ./mYBMP8pW4uQ.webp
|
|||
|
|
class: 'text-center photo-bg'
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# The Evolution
|
|||
|
|
|
|||
|
|
How we got here
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Stage 1 — Local (late 80s / early 90s)
|
|||
|
|
|
|||
|
|
**Dumb terminals. Single machine. One state.**
|
|||
|
|
|
|||
|
|
- Local development, long deployment cycles, low urgency
|
|||
|
|
- One state — easy to observe, easy to control
|
|||
|
|
- IaC: procedural scripts, logic hidden inside the application
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
> **The Perl Era:** we could do anything.
|
|||
|
|
>
|
|||
|
|
> We could also break anything.
|
|||
|
|
>
|
|||
|
|
> Beautiful, terrifying metaprogramming.
|
|||
|
|
>
|
|||
|
|
> No safety net.
|
|||
|
|
|
|||
|
|
> Silent failures at 3 AM.
|
|||
|
|
>
|
|||
|
|
> *Lesson: power without safety is a disaster.*
|
|||
|
|
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●●●○ 😴 ●●●●○ 🔥 ●○○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
You had one server. You knew what was on it.
|
|||
|
|
You could sleep.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Stage 2 — Networks / Internet
|
|||
|
|
|
|||
|
|
**Systems getting farther away. More people. More coordination.**
|
|||
|
|
|
|||
|
|
- Remote access, distributed teams, security becomes relevant
|
|||
|
|
- Cost of downtime rises — processes become critical
|
|||
|
|
- Harmonizing: package installs, config, updates across multiple machines in parallel
|
|||
|
|
- IaC: reproducible automation, first declarative attempts
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
> **The Python Era:** rapid development, great community.
|
|||
|
|
>
|
|||
|
|
> But nothing stopped you from being wrong.
|
|||
|
|
>
|
|||
|
|
> Type hints came late — and optional.
|
|||
|
|
>
|
|||
|
|
> Runtime errors >> compile-time errors.
|
|||
|
|
>
|
|||
|
|
> *Lesson: pragmatism without guarantees is fragile.*
|
|||
|
|
|
|||
|
|
<small>More pieces. More people. Getting interesting.</small>
|
|||
|
|
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●●○○ 😴 ●●●○○ 🔥 ●●○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Stage 3 — Containers / Cloud / CI-CD
|
|||
|
|
|
|||
|
|
**Everything. Everywhere. All at once.**
|
|||
|
|
|
|||
|
|
- Monolith → distributed, 24×7×365, high availability
|
|||
|
|
- Cloud, hybrid, multi-cloud, on-prem — simultaneously
|
|||
|
|
- Rollback and rollforward: database transactions, but for infrastructure
|
|||
|
|
- Scale horizontally AND vertically — and *descale*
|
|||
|
|
- CI/CD continuous: new features, new deploys, permanent churn
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
> **The Cloud/IaC Era:** Ansible, Terraform, Chef, Puppet.
|
|||
|
|
>
|
|||
|
|
> What changed? The syntax.
|
|||
|
|
>
|
|||
|
|
> What didn't? The fundamental problems.
|
|||
|
|
>
|
|||
|
|
> Still fighting type safety. Still discovering errors in production.
|
|||
|
|
>
|
|||
|
|
> *Lesson: more tools don't solve paradigm problems.*
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●○○○ 😴 ●○○○○ 🔥 ●●●●○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Did we increase productivity? Yes.
|
|||
|
|
Did we increase stress? Yes.
|
|||
|
|
Did we increase the chances of failure? Also yes.
|
|||
|
|
Do we have more control and safety? No.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: ./3XXSKa4jKaM.webp
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide photo-bg w-140 p-5 ml-1/5 box-highlight text-shadow-lg">
|
|||
|
|
|
|||
|
|
I could automate infrastructure.
|
|||
|
|
|
|||
|
|
But I couldn't make it reliable.
|
|||
|
|
|
|||
|
|
I couldn't prevent mistakes.
|
|||
|
|
|
|||
|
|
**I couldn't sleep.**
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="meters-standalone">
|
|||
|
|
🛡 ●○○○○ 😴 ○○○○○ 🔥 ●●●●●
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.standalone-slide {
|
|||
|
|
font-size: 2rem;
|
|||
|
|
line-height: 2.2;
|
|||
|
|
text-align: center;
|
|||
|
|
color: var(--slidev-theme-foreground);
|
|||
|
|
}
|
|||
|
|
.standalone-slide strong {
|
|||
|
|
color: #e74c3c;
|
|||
|
|
}
|
|||
|
|
.meters-standalone {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 3rem;
|
|||
|
|
left: 50%;
|
|||
|
|
transform: translateX(-50%);
|
|||
|
|
font-family: monospace;
|
|||
|
|
font-size: 1rem;
|
|||
|
|
opacity: 0.8;
|
|||
|
|
letter-spacing: 0.25em;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
No irony here. Personal. Long pause after "I couldn't sleep."
|
|||
|
|
|
|||
|
|
What you can't measure: fear.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
class: text-center
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
|
|||
|
|
# Why IaC Fails
|
|||
|
|
|
|||
|
|
The restaurant problem
|
|||
|
|
|
|||
|
|
<img class="inline" src="/failed.png" width="100">
|
|||
|
|
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
class: 'restaurant bg-photo'
|
|||
|
|
---
|
|||
|
|
<style>
|
|||
|
|
.slidev-layout.two-columns:has(.restaurant) {
|
|||
|
|
background-image: linear-gradient(rgba(0,0,0,0.62), rgba(0,0,0,0.62)),
|
|||
|
|
url("./images/blackieshoot-fuR0Iwu5dkk-unsplash.jpg") !important
|
|||
|
|
;
|
|||
|
|
background-repeat: no-repeat;
|
|||
|
|
background-position: center center;
|
|||
|
|
background-size: cover !important;
|
|||
|
|
}
|
|||
|
|
.restaurant {
|
|||
|
|
color: white !important;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
# The Restaurant
|
|||
|
|
|
|||
|
|
Every restaurant has at least three actors.
|
|||
|
|
|
|||
|
|
| Restaurant | Infrastructure |
|
|||
|
|
|---|---|
|
|||
|
|
| Guest declares<br> what they want | Declarative config <br>(YAML, HCL) |
|
|||
|
|
| Waiter validates<br> and transmits | Orchestrator<br> (K8s, Ansible) |
|
|||
|
|
| Kitchen executes<br> and delivers | Runtime / provisioning |
|
|||
|
|
| Dish arrives —<br> or doesn't | Deployment succeeds — or not |
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
**What makes it work — or not:**
|
|||
|
|
|
|||
|
|
The guest **declares**. Doesn't implement.
|
|||
|
|
|
|||
|
|
The waiter must know what's possible — <br> *before going to the kitchen*.
|
|||
|
|
|
|||
|
|
> "I want X" → waiter goes to kitchen
|
|||
|
|
><br> → "we don't have X, why is it on the menu?"
|
|||
|
|
><br>→ back to the table.
|
|||
|
|
><br>
|
|||
|
|
><br>
|
|||
|
|
> Equivalent: I configured a host with port 8443<br>→ that port isn't allowed<br> → reconfigure from zero.
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
The declarative model is correct. The problem is validation.
|
|||
|
|
|
|||
|
|
Key insight: the waiter is the orchestrator. They're the one who should catch impossible orders.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# The Truth That Mutates
|
|||
|
|
|
|||
|
|
**State is not static.<br> It can change at every step of the chain.**
|
|||
|
|
|
|||
|
|
<div class="chain">
|
|||
|
|
|
|||
|
|
| Step | <span class="ulvibe">**Truth**</span> for this actor |
|
|||
|
|
|---|---|
|
|||
|
|
| Guest speaks | What they want |
|
|||
|
|
| Waiter's notepad | What was written down |
|
|||
|
|
| Kitchen markings | What's done / not done |
|
|||
|
|
| Payment ticket | What was actually served |
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
> <span class="ulvibe">**Fail early = fail cheap. Fail in production = nightmare.**</span>
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
<div style="margin-top: -15px">
|
|||
|
|
|
|||
|
|
**The context problem:** <br>
|
|||
|
|
The waiter knows the regular customer:<br> *"always no salt."* <br>
|
|||
|
|
|
|||
|
|
The kitchen doesn't. If the waiter changes<br> — that context disappears.
|
|||
|
|
|
|||
|
|
<span class="ulvibe">**Configuration drift is the same thing:**</span> Implicit state. Not explicit. Not propagated. Lost silently.
|
|||
|
|
|
|||
|
|
<span class="ulvibe">**The cost of failure depends on *where* it happens:**</span>
|
|||
|
|
- Fail at the *table* (impossible order):<br> cheap — caught before kitchen
|
|||
|
|
- Fail in *kitchen* (ingredient missing):<br> medium — renegotiate with guest
|
|||
|
|
- Fail at *delivery* (wrong dish arrives):<br> expensive — experience destroyed
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
"No mushrooms available — can I substitute vegetables?"
|
|||
|
|
That renegotiation must be explicit. Traced. Re-authorized. Not silent.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# "We Don't Have Mushrooms"
|
|||
|
|
|
|||
|
|
**When an actor in the chain can't fulfill part of the order.**
|
|||
|
|
|
|||
|
|
> "Can I substitute vegetables?"
|
|||
|
|
>
|
|||
|
|
> That renegotiation must be **explicit. Traced. Re-authorized.**<br>Not silent. Not assumed.
|
|||
|
|
|
|||
|
|
<span class="ulvibe">**Configuration drift is silent renegotiation:**</span><br>
|
|||
|
|
The system changes. Nobody notified. State diverges without trace.
|
|||
|
|
|
|||
|
|
**Rust's answer — `Option<T>`:**
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// The waiter cannot silently skip a missing ingredient
|
|||
|
|
let mushrooms: Option<Ingredient> = order.mushrooms;
|
|||
|
|
match mushrooms {
|
|||
|
|
Some(m) => add_to_dish(m),
|
|||
|
|
None => renegotiate_with_guest(&guest)?, // explicit. always.
|
|||
|
|
}
|
|||
|
|
// drift = treating None as Some. Rust makes that impossible.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
> *The compiler is the waiter who cannot pretend an ingredient exists.*
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Option<T> is the language-level answer to configuration drift.
|
|||
|
|
The restaurant analogy closes here before we move to YAML hell.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# The Config Evolution
|
|||
|
|
|
|||
|
|
**How we got from code to YAML hell**
|
|||
|
|
|
|||
|
|
<div class="evolution">
|
|||
|
|
|
|||
|
|
1. **Hardcoded** — everything inside the binary. Full control. Zero flexibility.
|
|||
|
|
|
|||
|
|
2. **External config (JSON)** — works between machines. Unreadable for humans at scale.
|
|||
|
|
|
|||
|
|
3. **YAML / TOML** — more readable. Fragile syntax. Implicit types. Silent errors.
|
|||
|
|
|
|||
|
|
4. **YAML + Serde** — Serde validates the *structure*:
|
|||
|
|
- Does the field exist? Is it the right type?
|
|||
|
|
- Do we accept `"elephant"` as a pet? If the type is `String`... yes.
|
|||
|
|
- **Serde validates shape. Not meaning.**
|
|||
|
|
|
|||
|
|
5. **Helm / Jinja templates** — YAML generated from variables (in YAML).
|
|||
|
|
- Does it validate the content of the generated YAML? **No. Not at all.**
|
|||
|
|
- Like using an LLM with a markdown reference: the format is there,
|
|||
|
|
but is the content correct?<br>Nobody guarantees that.
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.evolution { font-size: 0.9rem; }
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
We got tired of writing YAML. So we wrote tools that write YAML.
|
|||
|
|
|
|||
|
|
The output of those tools? Still not semantically validated.
|
|||
|
|
|
|||
|
|
We just added a layer of indirection between us and the problem.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: ./3XXSKa4jKaM.webp
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide photo-bg w-90 p-5 ml-1/3 box-highlight text-shadow-lg title-slide bg-gray-800 opacity-85">
|
|||
|
|
|
|||
|
|
Continuous CI/CD.
|
|||
|
|
|
|||
|
|
No semantic validation.
|
|||
|
|
|
|||
|
|
**Continuous hope.**
|
|||
|
|
|
|||
|
|
<span style="font-size: 1.2rem; opacity: 0.6;">(crossing our fingers in production)</span>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="meters-standalone ml-1/3">
|
|||
|
|
🛡 ●○○○○ 😴 ○○○○○ 🔥 ●●●●●
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
"What we do is write what we want — like a letter to Santa Claus. And we cross our fingers."
|
|||
|
|
|
|||
|
|
Ironic tone. The audience recognizes this.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
class: items-list
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.items-list li {color: #676464;}
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
# Three Questions Without Answers
|
|||
|
|
|
|||
|
|
<div class="text-xl"> Question 1 — <span class="text-orange-500">
|
|||
|
|
— Why do we wait for things to break?
|
|||
|
|
</span></div>
|
|||
|
|
|
|||
|
|
- "Works on my machine" — in production, I don't know
|
|||
|
|
- Fail late = maximum cost. We want: fail fast, fail cheap
|
|||
|
|
|
|||
|
|
<div class="text-xl"> Question 2 — <span class="text-orange-500">
|
|||
|
|
— Do we actually know what we want?
|
|||
|
|
</span></div>
|
|||
|
|
|
|||
|
|
- Is the declaration sufficient and consistent with what's *possible*?
|
|||
|
|
- What are the boundaries? Static or dynamic? What is the source of truth — and when does it mutate?
|
|||
|
|
|
|||
|
|
<div class="text-xl"> Question 3 — <span class="text-orange-500">
|
|||
|
|
Can we guarantee determinism ?
|
|||
|
|
</span></div>
|
|||
|
|
|
|||
|
|
- CI/CD without semantic validation = continuous hope
|
|||
|
|
- We want certainty, not randomness
|
|||
|
|
- "Works on my machine" cannot be the production standard
|
|||
|
|
|
|||
|
|
> *We're not inventing anything new. Everything already exists.
|
|||
|
|
> The question is whether we're managing it correctly.*
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
These three questions are the core of the talk.
|
|||
|
|
Everything that follows is Rust's answer to each one.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: /jr-korpa-vg0Mph2RmI4-unsplash.jpg
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide photo-bg w-90 p-5 ml-1/3 box-highlight text-shadow-lg title-slide bg-gray-800 opacity-75">
|
|||
|
|
|
|||
|
|
The *tools* weren't the problem.
|
|||
|
|
|
|||
|
|
The *languages* weren't the problem.
|
|||
|
|
|
|||
|
|
**The paradigm was the problem.**
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Moment of clarity. Everything snaps into place.
|
|||
|
|
|
|||
|
|
I needed something that forced clarity — not enabled chaos.
|
|||
|
|
That prevented errors — before production.
|
|||
|
|
That made assumptions explicit — not hidden.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: andrew-neel-jtsW--Z6bFw-unsplash.jpg
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide photo-bg w-90 p-5 ml-1/3 box-highlight text-shadow-lg title-slide">
|
|||
|
|
|
|||
|
|
Systems we don't know how to control.
|
|||
|
|
|
|||
|
|
We hope they work.
|
|||
|
|
|
|||
|
|
When they don't — we fix them.
|
|||
|
|
|
|||
|
|
**Continuous nightmare.**
|
|||
|
|
|
|||
|
|
<span style="font-size: 1.2rem; opacity: 0.6;">(<span class="ulvibe"> alarm state</span> as the new normal)</span>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="meters-standalone ml-1/3">
|
|||
|
|
🛡 ●○○○○ 😴 ○○○○○ 🔥 ●●●●●
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
No irony. Dark. This is the emotional floor of the talk.
|
|||
|
|
|
|||
|
|
Long pause here. Let it land.
|
|||
|
|
|
|||
|
|
Then: "There's a better way."
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: section
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<img src="/ferris-heart.svg" width="120" class="-mt-5 ml-2.17/5">
|
|||
|
|
|
|||
|
|
<div class="text-8xl font-semibold mt-5"> Rust </div>
|
|||
|
|
|
|||
|
|
The answer to all three questions
|
|||
|
|
|
|||
|
|
<img src="/rust-laspalmas-dark.svg" width="280" class="-mt-8 ml-1.7/5">
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# The Bridge: From Serde to Types
|
|||
|
|
|
|||
|
|
Serde loads structurally valid config.<br>
|
|||
|
|
But `"elephant"` as `pet: String` compiles.
|
|||
|
|
|
|||
|
|
**Rust's answer: don't use `String`. Use a type.**
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// Before: String — anything goes
|
|||
|
|
pet: String // "elephant" compiles. "unicorn" compiles. 🤷
|
|||
|
|
|
|||
|
|
// After: closed domain — impossible values don't exist
|
|||
|
|
enum Pet { Dog, Cat, Rabbit } // "elephant" doesn't compile
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**This is the shift.**:
|
|||
|
|
|
|||
|
|
<h4 class="box-highlight p-2">Not the config format. The model of what it can contain.</h4>
|
|||
|
|
|
|||
|
|
<u>Serde</u> validates <span class="ulvibe">shape</span> | <u>Types</u> validate <span class="ulvibe">meaning</span><br>
|
|||
|
|
|
|||
|
|
The <u>compiler</u> validates *before the binary exists*.<br>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
This is the answer to Question 2: "Do we know what we want?"
|
|||
|
|
|
|||
|
|
Yes. When we define it as a type.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# What Rust Gives Us
|
|||
|
|
|
|||
|
|
<div class="mb-2"><span class="text-gray-300">Answer to Question 1:</span> <span class="ulvibe font-semibold">fail early, fail cheap</span></div>
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// Immutability by default — invariants are invariants
|
|||
|
|
let config = load_config()?; // cannot change silently
|
|||
|
|
// Option<T> — no nulls, no assumptions
|
|||
|
|
let mushrooms: Option<Ingredient> = order.mushrooms;
|
|||
|
|
match mushrooms {
|
|||
|
|
Some(m) => add_to_dish(m),
|
|||
|
|
None => notify_kitchen_to_skip(), // explicit. always.
|
|||
|
|
}
|
|||
|
|
// Enums as closed domains
|
|||
|
|
enum CloudProvider { Hetzner, UpCloud, AWS, GCP, Azure, OnPrem }
|
|||
|
|
enum Port { Valid(u16) } // not any integer — a valid port
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
<div class="mt-3"><span class="text-gray-300">Answer to Question 2:</span> <span class="ulvibe font-semibold">explicit contracts</span></div>
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// Traits define what every actor in the chain must fulfill
|
|||
|
|
#[async_trait]
|
|||
|
|
pub trait TaskStorage: Send + Sync {
|
|||
|
|
async fn create_task(&self, task: WorkflowTask) -> StorageResult<WorkflowTask>;
|
|||
|
|
async fn update_task(&self, id: &str, status: TaskStatus) -> StorageResult<()>;
|
|||
|
|
// Add a new provider: implement this trait or it doesn't compile
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
"I want tomato. You can invent whatever you want —
|
|||
|
|
but without tomato, it's not the dish I ordered."
|
|||
|
|
|
|||
|
|
That's immutability. Invariants stay invariant.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# The Compiler as Pre-Validator
|
|||
|
|
|
|||
|
|
<div class="mb-2"><span class="text-gray-300">Answer to Question 3: </span>
|
|||
|
|
<span class="ulvibe font-semibold">guaranteed determinism</span></div>
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// Closed domain — you can't forget a case
|
|||
|
|
enum RollbackStrategy {
|
|||
|
|
ConfigDriven,
|
|||
|
|
Conservative, // preserve unless marked deletion
|
|||
|
|
Aggressive, // revert all changes
|
|||
|
|
Custom { operations: Vec<String> },
|
|||
|
|
}
|
|||
|
|
// The compiler enforces exhaustive handling
|
|||
|
|
match strategy {
|
|||
|
|
RollbackStrategy::ConfigDriven => ...,
|
|||
|
|
RollbackStrategy::Conservative => ...,
|
|||
|
|
RollbackStrategy::Aggressive => ...,
|
|||
|
|
RollbackStrategy::Custom { .. } => ...,
|
|||
|
|
// miss one → compile error
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
**The** *compiler* **validates:**
|
|||
|
|
- Before building the binary
|
|||
|
|
- Not after hours of execution
|
|||
|
|
- Not when a function nobody touched in months finally gets called
|
|||
|
|
- Predictable behavior: <br> memory, resources, workflows
|
|||
|
|
|
|||
|
|
<div class="box-highlight text-sm font-normal leading-5">
|
|||
|
|
The compiler is the waiter who validates the order.<br>
|
|||
|
|
Before it reaches the kitchen.<br>
|
|||
|
|
Before the guest waits.<br>
|
|||
|
|
Before any ingredient is missing.<br>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●●●○ 😴 ●●●●○ 🔥 ●●○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: clouds_lpa.jpg
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide -mt-8 photo-bg px-5 box-highlight text-shadow-lgi title-slide bg-gray-900 opacity-70">
|
|||
|
|
|
|||
|
|
# The Human Impact
|
|||
|
|
|
|||
|
|
**When the system is trustworthy:**
|
|||
|
|
|
|||
|
|
<div class="impact-grid">
|
|||
|
|
|
|||
|
|
✓ Sleep comes back
|
|||
|
|
|
|||
|
|
✓ Confidence returns
|
|||
|
|
|
|||
|
|
✓ The team trusts the automation
|
|||
|
|
|
|||
|
|
✓ Stress decreases
|
|||
|
|
|
|||
|
|
✓ You can actually rest
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
> *What you can't measure: <span class="text-white">fear</span>.*
|
|||
|
|
>
|
|||
|
|
> *What you can measure: <span class="text-white">MTTR</span>.*
|
|||
|
|
>
|
|||
|
|
> *Before: > 30 minutes. Now: <span class="text-white">< 5 minutes</span>.*
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.impact-grid {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: 1fr 1fr;
|
|||
|
|
gap: 1.5rem;
|
|||
|
|
margin: 2rem 0;
|
|||
|
|
font-size: 1.4rem;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
<br>
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●●●● 😴 ●●●●● 🔥 ●○○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: /jude-infantini-mI-QcAP95Ok-unsplash.jpg
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide box-highlight ml-1.5/5 w-150 text-shadow-lg text-2xl">
|
|||
|
|
|
|||
|
|
Continuous CI/CD.
|
|||
|
|
|
|||
|
|
Types. Compiler. Explicit state.
|
|||
|
|
|
|||
|
|
<span class="font-extrabold">**Continuous certainty.**</span>
|
|||
|
|
|
|||
|
|
<span style="font-size: 1.2rem; opacity: 0.6;">(to keep sleeping well)</span>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="meters-standalone ml-1.5/5">
|
|||
|
|
🛡 ●●●●● 😴 ●●●●● 🔥 ●○○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Resolution. The arc closes.
|
|||
|
|
|
|||
|
|
The title of the talk, demonstrated.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: section
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<img src="/ferris-heart.svg" width="120" class="-mt-4 ml-2.17/5">
|
|||
|
|
|
|||
|
|
<div class="text-7xl font-semibold mt-4"> In Production </div>
|
|||
|
|
|
|||
|
|
This is not theory
|
|||
|
|
|
|||
|
|
<img src="/provisioning.svg" width="280" class="ml-1.7/5">
|
|||
|
|
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: center
|
|||
|
|
name: provisioning
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref, computed } from 'vue'
|
|||
|
|
const useWhite = ref(false)
|
|||
|
|
const bgStyle = computed(() => ({
|
|||
|
|
backgroundImage: `url('${useWhite.value ? "/w-arch-diag-v2.svg" : "/arch-diag-v2.svg"}')`,
|
|||
|
|
backgroundSize: 'contain',
|
|||
|
|
backgroundRepeat: 'no-repeat',
|
|||
|
|
backgroundPosition: 'center',
|
|||
|
|
position: 'absolute',
|
|||
|
|
inset: '0',
|
|||
|
|
cursor: 'pointer',
|
|||
|
|
}))
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<div @click="useWhite = !useWhite" :style="bgStyle" />
|
|||
|
|
|
|||
|
|
<div @click="useWhite = !useWhite" style="position: absolute; bottom: 1.2rem; right: 1.5rem; opacity: 0.35; font-size: 1.1rem; cursor: pointer; user-select: none;">
|
|||
|
|
🌗
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Architecture overview. Let it breathe.
|
|||
|
|
Don't narrate every component — just: "this is what we're talking about."
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Nickel
|
|||
|
|
|
|||
|
|
**YAML rejected. TOML rejected.<br>Reason: no type safety.**
|
|||
|
|
|
|||
|
|
YAML wrote what we wanted.<br>
|
|||
|
|
It couldn't say what was *possible*.<br>
|
|||
|
|
|
|||
|
|
Nickel closes that gap <br>
|
|||
|
|
— at config time, not at 3 AM.
|
|||
|
|
|
|||
|
|
```haskell
|
|||
|
|
# Infrastructure schema
|
|||
|
|
# — validated at config compile time
|
|||
|
|
{
|
|||
|
|
compute | {
|
|||
|
|
region | String,
|
|||
|
|
count | Number & (fun n => n > 0),
|
|||
|
|
scaling | {
|
|||
|
|
min | Number & (fun n => n > 0),
|
|||
|
|
max | Number & (fun n => n >= min),
|
|||
|
|
# -- compiler verifies this relationship
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
::right::
|
|||
|
|
# Typed Source of Truth
|
|||
|
|
Result (ADR-003):<br>**zero configuration type errors in production.**
|
|||
|
|
|
|||
|
|
Config hierarchy:<br>
|
|||
|
|
|
|||
|
|
defaults → workspace → profile → <br> environment → runtime
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
Each layer merges.<br>
|
|||
|
|
Type system catches conflicts.<br>
|
|||
|
|
At config time — not deployment time.
|
|||
|
|
|
|||
|
|
The guest wrote an impossible order.<br>
|
|||
|
|
Nickel makes impossible orders unwritable.
|
|||
|
|
|
|||
|
|
> *Serde validates shape.*
|
|||
|
|
>
|
|||
|
|
> *Nickel validates meaning.*
|
|||
|
|
>
|
|||
|
|
> *The compiler validates before deployment.*
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
This is the practical answer to "how do you do typed IaC?"
|
|||
|
|
|
|||
|
|
Not YAML + validation script. Not JSON Schema. A typed language.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Traits as Provider
|
|||
|
|
|
|||
|
|
**The kitchen can change.<br>AWS ≠ UpCloud ≠ bare metal. Same menu.**
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// Every provider implements the same contract
|
|||
|
|
enum DependencyType { Hard, Soft, Optional }
|
|||
|
|
enum TaskStatus {
|
|||
|
|
Pending, Running, Completed, Failed, Cancelled
|
|||
|
|
}
|
|||
|
|
// Dependency resolution
|
|||
|
|
// — the orchestrator knows the order
|
|||
|
|
// Installing Kubernetes:
|
|||
|
|
// containerd (Hard) → etcd (Hard) → kubernetes
|
|||
|
|
// → cilium (requires kubernetes)
|
|||
|
|
// → rook-ceph (requires cilium)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Explicit state — no drift:**
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
pub struct WorkflowExecutionState {
|
|||
|
|
pub task_states: HashMap<String, TaskExecutionState>,
|
|||
|
|
// what happened and when
|
|||
|
|
pub checkpoints: Vec<WorkflowCheckpoint>,
|
|||
|
|
pub provider_states: HashMap<String, ProviderState>,
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
::right::
|
|||
|
|
# Contracts
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
- Checkpoint every 5 minutes
|
|||
|
|
- No implicit state.
|
|||
|
|
> No *"the waiter remembers the customer doesn't want salt."*
|
|||
|
|
- It's in the order. Always. Explicit.
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Add a new provider: implement the trait or it doesn't compile.
|
|||
|
|
There's no way to forget a case.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
class: -mt-7
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Dependency Graph
|
|||
|
|
|
|||
|
|
**Fail_fast: bool is not a config option.<br>
|
|||
|
|
It's a principle encoded as a type.**
|
|||
|
|
|
|||
|
|
Typed DAG — dependency resolution enforced<br> at workflow compile time:
|
|||
|
|
|
|||
|
|
The kitchen doesn't serve the main course <br> before the starter is done.<br>
|
|||
|
|
|
|||
|
|
`DependencyType::Hard` is that rule.<br> In the type system, not in a runbook.
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
pub struct WorkflowConfig {
|
|||
|
|
pub max_parallel_tasks: usize,
|
|||
|
|
pub task_timeout_seconds: u64,
|
|||
|
|
// halt on first failure
|
|||
|
|
pub fail_fast: bool,
|
|||
|
|
// recovery point granularity
|
|||
|
|
pub checkpoint_interval_seconds: u64,
|
|||
|
|
}
|
|||
|
|
containerd (Hard) → etcd (Hard) → kubernetes
|
|||
|
|
→ cilium (requires: kubernetes)
|
|||
|
|
→ rook-ceph (requires: kubernetes + cilium)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
# Fail Fast, Fail Cheap
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
- `DependencyType::Hard` <br> - failure stops the chain. Always.
|
|||
|
|
- `DependencyType::Soft` <br> - continues, explicitly degraded.
|
|||
|
|
- `DependencyType::Optional` <br> - missing is expected and fine.
|
|||
|
|
<br>
|
|||
|
|
> *The compiler catches the install order.*<br>
|
|||
|
|
> *Not the on-call engineer at 2 AM.*
|
|||
|
|
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●●●● 😴 ●●●●● 🔥 ●○○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
The bridge between "fail early = fail cheap" and the actual production code.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Real Applications
|
|||
|
|
|
|||
|
|
### Kubernetes
|
|||
|
|
|
|||
|
|
The orchestrator provisions cluster<br>components as a typed workflow:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
containerd
|
|||
|
|
→ etcd
|
|||
|
|
→ kubernetes control plane
|
|||
|
|
→ CoreDNS
|
|||
|
|
→ Cilium (CNI)
|
|||
|
|
→ Rook-Ceph (storage)
|
|||
|
|
```
|
|||
|
|
Each dependency is a `DependencyType`.<br>
|
|||
|
|
The compiler catches: <br>installing Cilium without Kubernetes.<br>
|
|||
|
|
Not the on-call engineer at 2 AM.<br>
|
|||
|
|
|
|||
|
|
>*"In my machine it works" has a price here.*
|
|||
|
|
>
|
|||
|
|
> *This is the highest-stakes infrastructure in the deck.*
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
### Blockchain Validators
|
|||
|
|
|
|||
|
|
Validators require brutal uptime.<br>
|
|||
|
|
A validator that fails loses funds — not your infrastructure's money.<br>
|
|||
|
|
**Your customer's.**
|
|||
|
|
|
|||
|
|
- **Post-quantum cryptography**: CRYSTALS-Kyber + Falcon + AES-256-GCM hybrid. Validator keys protected against quantum computers.
|
|||
|
|
- **SLOs with real error budgets**: 99.99% = 52.6 min downtime/year. Prometheus blocks deploys when burn rate exceeds budget.
|
|||
|
|
- **Deterministic config**: validator parameters are types. A `bond_amount` that isn't a valid `u128` doesn't compile.
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
These are not toy examples.
|
|||
|
|
Production systems with SLOs, encryption, and self-healing.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Disaster Recovery
|
|||
|
|
|
|||
|
|
**Rollback as a type, not a procedure**
|
|||
|
|
|
|||
|
|
3 AM. Something broke. You need to rollback.<br>
|
|||
|
|
Without types: you improvise.<br>
|
|||
|
|
With types: you choose a strategy<br>
|
|||
|
|
— or it doesn't compile.
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// Checkpoint = complete system snapshot
|
|||
|
|
pub struct Checkpoint {
|
|||
|
|
pub workflow_state: Option<WorkflowExecutionState>,
|
|||
|
|
pub resources: Vec<ResourceSnapshot>,
|
|||
|
|
pub provider_states: HashMap<String, ProviderState>,
|
|||
|
|
}
|
|||
|
|
// Rollback strategy = typed choice, not a runbook
|
|||
|
|
enum RollbackStrategy {
|
|||
|
|
ConfigDriven,
|
|||
|
|
Conservative, // preserve unless marked for deletion
|
|||
|
|
Aggressive, // revert all changes
|
|||
|
|
Custom { operations: Vec<String> },
|
|||
|
|
}
|
|||
|
|
// You cannot do rollback without choosing a strategy.
|
|||
|
|
// The compiler doesn't let you ignore the case.
|
|||
|
|
```
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
**Multi-backend backup:** restic, borg, tar, rsync<br>
|
|||
|
|
— all as enum variants.<br>
|
|||
|
|
|
|||
|
|
Production backup and DR restore use the same type, the same schema.
|
|||
|
|
|
|||
|
|
> *The runbook exists.*
|
|||
|
|
>
|
|||
|
|
> *Nobody reads it clearly at 3 AM under pressure.*
|
|||
|
|
>
|
|||
|
|
> *The type forces the decision before the crisis.*
|
|||
|
|
>
|
|||
|
|
> *The state is the same in prod and in DR. Always.*
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Self-healing (ADR-010): RemediationEngine runs typed playbooks.
|
|||
|
|
If remediation fails 3 times, it escalates to a human.
|
|||
|
|
It doesn't loop indefinitely.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Self-Healing
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
> **When something breaks at 3 AM** <br>
|
|||
|
|
> — **the system responds, not you.**
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
```rust
|
|||
|
|
enum RemediationAction {
|
|||
|
|
ScaleService { service: String, replicas: u32 },
|
|||
|
|
FailoverService { service: String, region: Region },
|
|||
|
|
RestartService { service: String },
|
|||
|
|
ClearCache { service: String, scope: CacheScope },
|
|||
|
|
}
|
|||
|
|
// Typed playbooks. Not shell scripts. Not hope.
|
|||
|
|
// Fails 3 times → escalates to human.
|
|||
|
|
// Never loops indefinitely.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
# — Typed Remediation
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
**What happens at 3 AM:**
|
|||
|
|
|
|||
|
|
- Alert fires <br>→ `RemediationEngine` matches condition<br> → runs `RestartService`<br>
|
|||
|
|
|
|||
|
|
- Works: silent. Nobody woken up.<br>
|
|||
|
|
- Fails 3×: page sent <br>— with full state, checkpoint, <br> and execution history.
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
> *You wake up to information. Not to chaos.*
|
|||
|
|
|
|||
|
|
<div class="meters-slide">
|
|||
|
|
🛡 ●●●●● 😴 ●●●●● 🔥 ●○○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
ADR-010: automated incident response.
|
|||
|
|
"At 3 AM, without you." — this is what that means, concretely.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: /jude-infantini-mI-QcAP95Ok-unsplash.jpg
|
|||
|
|
class: photo-bg
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide box-highlight ml-0.8/5 w-200 text-shadow-lg text-2xl mttr">
|
|||
|
|
|
|||
|
|
Without types. Without compiler. Without explicit state.
|
|||
|
|
|
|||
|
|
**MTTR > 30 minutes.**
|
|||
|
|
|
|||
|
|
<div class="divider">────────────────────────</div>
|
|||
|
|
|
|||
|
|
Rust. Types. Explicit state.
|
|||
|
|
Automated response.
|
|||
|
|
|
|||
|
|
**MTTR < 5 minutes.**
|
|||
|
|
|
|||
|
|
<span style="font-size: 1.2rem; opacity: 0.6;">(at 3 AM. without you.)</span>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="meters-standalone ml-0.8/5 -mt-2">
|
|||
|
|
🛡 ●●●●● 😴 ●●●●● 🔥 ●○○○○
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.mttr { line-height: 1.8; }
|
|||
|
|
.mttr strong { color: #27ae60; }
|
|||
|
|
.mttr strong:first-of-type { color: #e74c3c; }
|
|||
|
|
.divider {
|
|||
|
|
margin: 1.5rem 0;
|
|||
|
|
opacity: 0.3;
|
|||
|
|
font-size: 1.2rem;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Real numbers. Not promises.
|
|||
|
|
|
|||
|
|
Pause after "without you."
|
|||
|
|
That's the title of the talk.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="mt-0.8/2 text-2xl">
|
|||
|
|
|
|||
|
|
<h1 class="text-7xl font-semibold pb-5"> Why This Matters</h1>
|
|||
|
|
|
|||
|
|
For everyone in this room
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
<img src="/crate_in_wall.jpg" class="object-cover object-center rounded-lg h-120">
|
|||
|
|
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: two-cols
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# For You
|
|||
|
|
|
|||
|
|
<h3 class="ulvibe">If you've been frustrated like me</h3>
|
|||
|
|
|
|||
|
|
- Rust solves problems you already have.
|
|||
|
|
- This is not hype. It is operational relief.
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
<h3 class="ulvibe font-semibold">Start here:</h3>
|
|||
|
|
|
|||
|
|
- Model your infrastructure as types
|
|||
|
|
- Let the compiler pre-validate before deployment
|
|||
|
|
|
|||
|
|
::right::
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
<h3 class="ulvibe">If you're earlier in your career</h3>
|
|||
|
|
|
|||
|
|
- Start with type safety from day one.
|
|||
|
|
- Build for reliability, not only speed.
|
|||
|
|
|
|||
|
|
<br>
|
|||
|
|
<br>
|
|||
|
|
|
|||
|
|
<h3 class="mt-2 ulvibe font-semibold">The shortest path:</h3>
|
|||
|
|
|
|||
|
|
- Types for config.
|
|||
|
|
- Traits for providers.
|
|||
|
|
- Determinism for operations.
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Not a sales pitch. Not evangelism.
|
|||
|
|
38 years of experience saying: this matters.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
background: ./mYBMP8pW4uQ.webp
|
|||
|
|
class: 'text-center photo-bg'
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide text-shadow-lg text-3xl perspective">
|
|||
|
|
|
|||
|
|
I have perspective from long production experience.
|
|||
|
|
|
|||
|
|
I have seen technologies come and go.
|
|||
|
|
|
|||
|
|
*Rust is not hype. Rust is relief with evidence.*
|
|||
|
|
|
|||
|
|
It solves real operational problems I had for decades.
|
|||
|
|
|
|||
|
|
More years is not a liability.
|
|||
|
|
|
|||
|
|
**It is an advantage.**
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.perspective { line-height: 2; }
|
|||
|
|
.perspective strong { color: #e67e22; }
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Not an apology. Not bragging.
|
|||
|
|
|
|||
|
|
Just: I can tell you — from experience — this matters.
|
|||
|
|
-->
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
layout: cover
|
|||
|
|
name: end
|
|||
|
|
background: ./images/cleo-heck-1-l3ds6xcVI-unsplash.jpg
|
|||
|
|
class: 'photo-bg'
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div class="standalone-slide text-shadow-lg text-xl perspective">
|
|||
|
|
|
|||
|
|
# Why I Needed Rust
|
|||
|
|
|
|||
|
|
<div class="meters-final -mt-3 mb-1">
|
|||
|
|
<span>🛡 ●●●●●</span>
|
|||
|
|
<span>😴 ●●●●●</span>
|
|||
|
|
<span>🔥 ●○○○○</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="text-xl leading-11 text-gray-200"> Three Closing Lines</div>
|
|||
|
|
|
|||
|
|
<div class="text-2xl leading-11 text-orange-200">
|
|||
|
|
I have lived this problem for decades.<br>
|
|||
|
|
Rust gave me deterministic systems and better sleep.<br>
|
|||
|
|
Start small: model infrastructure as types.
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="text-5xl leading-12 text-gray-200 my-5">
|
|||
|
|
Thank you. Questions?
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<small>More info: </small>
|
|||
|
|
· **jesusperez.pro** <br>
|
|||
|
|
|
|||
|
|
<small> · **provisioning.systems** · **vapora.dev** · **rustelo.dev** </small>
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<style>
|
|||
|
|
.meters-final {
|
|||
|
|
display: inline-flex;
|
|||
|
|
gap: 2rem;
|
|||
|
|
font-size: 1.4rem;
|
|||
|
|
font-family: monospace;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<!--
|
|||
|
|
Final slide. Three meters in green.
|
|||
|
|
|
|||
|
|
The title of the talk, demonstrated.
|
|||
|
|
|
|||
|
|
Direct eye contact. Slow delivery.
|
|||
|
|
-->
|