---
theme: default
title: Why I Needed Rust
titleTemplate: '%s - Rustikon 2026'
layout: cover
background: ./images/charles-assuncao-1BbOtIqx21I-unsplash.jpg
class: photo-bg
---
# Why I Needed Rust

## Finally, Infrastructure Automation I Can Sleep On

Jesús Pérez Lorenzo · Rustikon 2026

<div class="meters">
  <span>🛡 ●●●○○</span>
  <span>😴 ●●●○○</span>
  <span>🔥 ●○○○○</span>
</div>

<style scoped>
.meters {
  margin-top: 2rem;
  display: flex;
  gap: rem;
  font-size: 1rem;
  opacity: 0.6;
  font-family: monospace;
}
.photo-bg {
  position: relative;
}
.photo-bg::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.52);
  pointer-events: none;
  z-index: 0;
}
.photo-bg .slidev-layout {
  position: relative;
  z-index: 1;
}
</style>

<!--
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."
-->

---

# 38 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>

> Each time, I thought I had the answer.
> Each time, reality proved me wrong.

<!--
Don't dwell. Move fast through this slide.
The point is: I've tried everything. This isn't a beginner's opinion.
-->

---
layout: section
---

# The Evolution

How we got here

---
background: https://images.unsplash.com/photo-1cTFuvI14J4?auto=format&fit=crop&w=1920&q=80
class: photo-bg
---

# 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">
  🛡 ●●●●○ &nbsp; 😴 ●●●●○ &nbsp; 🔥 ●○○○○
</div>

<style>
.meters-slide {
  position: absolute;
  bottom: 2rem;
  right: 2rem;
  font-family: monospace;
  font-size: 0.85rem;
  opacity: 0.7;
  background: var(--slidev-theme-background);
  padding: 0.5rem 1.5rem;
  border-radius: 6px;
  border: 1px solid rgba(128,128,128,0.2);
}
</style>

<!--
You had one server. You knew what was on it.
You could sleep.
-->

---
background: https://images.unsplash.com/photo-M5tzZtFCOfs?auto=format&fit=crop&w=1920&q=80
class: photo-bg
---

# 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.*

<div class="meters-slide">
  🛡 ●●●○○ &nbsp; 😴 ●●●○○ &nbsp; 🔥 ●●○○○
</div>

<!--
More pieces. More people. Getting interesting.
-->

---
background: https://images.unsplash.com/photo-CuZ8VdwRpyk?auto=format&fit=crop&w=1920&q=80
class: photo-bg
---

# 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.*

<div class="meters-slide">
  🛡 ●●○○○ &nbsp; 😴 ●○○○○ &nbsp; 🔥 ●●●●○
</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: center
background: https://images.unsplash.com/photo-lLLZkSmxe7A?auto=format&fit=crop&w=1920&q=80
class: photo-bg
---

<div class="standalone-slide">

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">
  🛡 ●○○○○ &nbsp;&nbsp; 😴 ○○○○○ &nbsp;&nbsp; 🔥 ●●●●●
</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: section
---

# Why IaC Fails

The restaurant problem

---
layout: two-cols
background: "./images/blackieshoot-fuR0Iwu5dkk-unsplash.jpg"
class: 'restaurant'
---
<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 | "Truth" 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>

::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.

**Configuration drift is the same thing:** Implicit state. Not explicit. Not propagated. Lost silently.

**The cost of failure depends on *where* it happens:**
- 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

> **Fail early = fail cheap. Fail in production = nightmare.**
</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.

**Configuration drift is silent renegotiation:**<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: center
---

<div class="standalone-slide">

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">
  🛡 ●○○○○ &nbsp;&nbsp; 😴 ○○○○○ &nbsp;&nbsp; 🔥 ●●●●●
</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.
-->

---

# Three Questions Without Answers

**Question 1 — Why do we wait for things to break?**
- "Works on my machine" — in production, I don't know
- Fail late = maximum cost. We want: fail fast, fail cheap

**Question 2 — Do we actually know what we want?**
- 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?

**Question 3 — Can we guarantee determinism?**
- 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: center
---

<div class="standalone-slide">

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: center
---

<div class="standalone-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;">(alarm state as the new normal)</span>

</div>

<div class="meters-standalone">
  🛡 ●○○○○ &nbsp;&nbsp; 😴 ○○○○○ &nbsp;&nbsp; 🔥 ●●●●●
</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
---

# Rust

The answer to all three questions

---

# The Bridge: From Serde to Types

Serde loads structurally valid config. 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.** Not the config format. The model of what it can contain.

Serde validates shape.
Types validate meaning.
The compiler validates *before the binary exists*.

<!--
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

**Answer to Question 1: fail early, fail cheap**

```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
```

**Answer to Question 2: explicit contracts**

```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

**Answer to Question 3: guaranteed determinism**

```rust
// Closed domain — you can't forget a case
enum RollbackStrategy {
    ConfigDriven,
    Conservative, // preserve unless marked for 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

<br> 
    
> *The compiler is the waiter who validates the order before it reaches the kitchen.*
> *Before the guest waits. Before the ingredient is missing.*

<div class="meters-slide">
  🛡 ●●●●○ &nbsp; 😴 ●●●●○ &nbsp; 🔥 ●●○○○
</div>

---

# 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: fear.*
>
> *What you can measure: MTTR.*
>
> *Before: > 30 minutes. Now: < 5 minutes.*

<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">
  🛡 ●●●●●&nbsp; 😴 ●●●●●&nbsp; 🔥 ●○○○○
</div>

---
layout: center
background: https://images.unsplash.com/photo-e1dnFk7_570?auto=format&fit=crop&w=1920&q=80
class: photo-bg
---

<div class="standalone-slide">

Continuous CI/CD.

Types. Compiler. Explicit state.

**Continuous certainty.**

<span style="font-size: 1.2rem; opacity: 0.6;">(to keep sleeping well)</span>

</div>

<div class="meters-standalone">
  🛡 ●●●●● &nbsp;&nbsp; 😴 ●●●●● &nbsp;&nbsp; 🔥 ●○○○○
</div>

<!--
Resolution. The arc closes.

The title of the talk, demonstrated.
-->

---
layout: section
---

# In Production

This is not theory

---
layout: two-cols
---

# Nickel as Typed Source of Truth

**YAML rejected. TOML rejected.<br>Reason: no type safety.**

```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::
Result (ADR-003):<br>**zero configuration type errors in production.**

Config hierarchy:<br>
defaults → workspace → profile → environment → runtime
<br>
<br>
<br>
Each layer merges.<br>
Type system catches conflicts.<br>
At config time — not deployment time.

> *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.
-->

---

# Traits as Provider Contracts

**The kitchen can change. 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>,
    pub checkpoints: Vec<WorkflowCheckpoint>,  // what happened and when
    pub provider_states: HashMap<String, ProviderState>,
}
```

- 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.
-->

---

# Dependency Graph — Fail Fast, Fail Cheap

**`fail_fast: bool` is not a config option. It's a principle encoded as a type.**

```rust
pub struct WorkflowConfig {
    pub max_parallel_tasks:          usize,
    pub task_timeout_seconds:        u64,
    pub fail_fast:                   bool,  // halt on first failure
    pub checkpoint_interval_seconds: u64,   // recovery point granularity
}
```

Typed DAG — dependency resolution enforced at workflow compile time:

```
containerd (Hard) → etcd (Hard) → kubernetes
                                → cilium    (requires: kubernetes)
                                → rook-ceph (requires: kubernetes + cilium)
```

- `DependencyType::Hard` — failure stops the chain. Always.
- `DependencyType::Soft` — continues, explicitly degraded.
- `DependencyType::Optional` — missing is expected and fine.

> *Not a runbook. Not a comment. A type the compiler enforces.*

<div class="meters-slide">
  🛡 ●●●●● &nbsp; 😴 ●●●●● &nbsp; 🔥 ●○○○○
</div>

<!--
The bridge between "fail early = fail cheap" and the actual production code.
-->

---
layout: two-cols
---

# Real Applications

::left::

### Kubernetes

The orchestrator provisions cluster components as a typed workflow:

```
containerd
  → etcd
  → kubernetes control plane
    → CoreDNS
    → Cilium (CNI)
      → Rook-Ceph (storage)
```

Each dependency is a `DependencyType`.
The compiler catches installing Cilium without Kubernetes.
Not the on-call engineer at 2 AM.

::right::

### Blockchain Validators

Validators require brutal uptime. A validator that fails loses funds.

- **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.
-->

---

# Self-Healing — Typed Remediation

**When something breaks at 3 AM — the system responds, not you.**

```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.
```

**What happens at 3 AM:**
- Alert fires → `RemediationEngine` matches condition → runs `RestartService`
- Works: silent. Nobody woken up.
- Fails 3×: page sent — with full state, checkpoint, and execution history.

> *You wake up to information. Not to chaos.*

<div class="meters-slide">
  🛡 ●●●●● &nbsp; 😴 ●●●●● &nbsp; 🔥 ●○○○○
</div>

<!--
ADR-010: automated incident response.
"At 3 AM, without you." — this is what that means, concretely.
-->

---
layout: center
---

<div class="standalone-slide 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">
  🛡 ●●●●● &nbsp;&nbsp; 😴 ●●●●● &nbsp;&nbsp; 🔥 ●○○○○
</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.
-->

---

# Disaster Recovery

**Rollback as a type, not a procedure**

```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.
```

**Multi-backend backup:** restic, borg, tar, rsync — all as enum variants.<br>
Production backup and DR restore use the same type, the same schema.

> *"Works in prod but not in DR" can't happen if the state is the same type.*

<!--
Self-healing (ADR-010): RemediationEngine runs typed playbooks.
If remediation fails 3 times, it escalates to a human.
It doesn't loop indefinitely.
-->

---
layout: section
---

# Why This Matters

For everyone in this room

---
layout: two-cols
---

# For You

::left::

### If you've been frustrated like me

- Rust solves the problems *you already know*
  — not hypothetical ones
- This isn't hype. I've seen technologies
  come and go for decades.
- Give it a real chance.
- Your sleep will thank you.

<br>

**Start here:**
- Model your infrastructure as types
- Replace stringly-typed config with enums
- Let the compiler be your pre-validator

::right::

### If you're earlier in your career

- Don't waste decades on fragile infrastructure
- Start with type safety from day one
- Build for reliability — not just for speed
- You'll thank yourself later

<br>

**The shortest path:**
- Learn the type system deeply
- Understand ownership as state management
- Traits as contracts between systems

<!--
Not a sales pitch. Not evangelism.
38 years of experience saying: this matters.
-->

---
layout: center
---

<div class="standalone-slide perspective">

At my age, I have perspective.

I've seen technologies come and go.

**Rust isn't hype.**

It solves real problems
I've had for decades.

More years isn't a liability.

**It's 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
---

# Why I Needed Rust

## Because I Wanted to Sleep

<div class="meters-final">
  <span>🛡 ●●●●●</span>
  <span>😴 ●●●●●</span>
  <span>🔥 ●○○○○</span>
</div>

## Thank you very much 

Questions?

**provisioning.systems** 

· **jesusperez.pro** 

<style>
.meters-final {
  display: flex;
  gap: 2rem;
  font-size: 1.4rem;
  font-family: monospace;
  margin: 2rem 0;
  color: #27ae60;
}
</style>

<!--
Final slide. Three meters in green.

The title of the talk, demonstrated.

Direct eye contact. Slow delivery.
-->
