ontoref/assets/presentation/last_slides.md
Jesús Pérez d59644b96f
feat: unified auth model, project onboarding, install pipeline, config management
The full scope across this batch: POST /sessions key→token exchange, SessionStore dual-index with revoke_by_id, CLI Bearer injection (ONTOREF_TOKEN), ontoref setup
  --gen-keys, install scripts, daemon config form roundtrip, ADR-004/005, on+re self-description update (fully-self-described), and landing page refresh.
2026-03-13 20:56:31 +00:00

1117 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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