🧪 Problem-Driven Systems Lab

🦀 Caso 12 — Rust 1.83#

⬅️ Caso 12 · ⚖️ Comparativa de los 7 stacks · 🦀 Perfil de Rust · 🧬 Todos los perfiles

Stack Rust operativo del caso 12. Incidente con owner ausente que revienta vs runbook codificado que degrada de forma controlada.

Primitivas nativas#

PrimitivaRol
Option<T>La ausencia esta en el tipo de retorno de pick_owner_*.
Operador ?Propaga la ausencia hacia arriba sin escribir un solo if.
match exhaustivo sobre OptionOmitir el brazo None no compila.
.unwrap() + panic::catch_unwindEl atajo que convierte ausencia en panic, y el ultimo recurso que lo contiene.

Contraste#

Legacy.unwrap() es el atajo que convierte la ausencia en panic:

rust
let owner  = pick_owner_legacy(&scenario_owned).unwrap();  // panic si no hay owner
let script = owner.runbook.get(&key_owned).unwrap();       // panic si no hay runbook

Contenido con el ultimo recurso:

rust
let outcome = panic::catch_unwind(move || { ... });
match outcome {
    Ok((executed, mttr)) => { ... }
    Err(_) => { LEGACY_CRASHED.fetch_add(1, Ordering::Relaxed); ... }
}

Distributed — el operador ? propaga la ausencia sin un solo if:

rust
let script: Option<String> = (|| {
    let owner  = pick_owner_distributed(scenario)?;   // None → sale aca
    let script = owner.runbook.get(runbook_key)?;     // None → sale aca
    Some(script.clone())
})();

let (mttr, result) = match script {
    Some(_) => (rand_between(15, 10), "executed_by_primary"),
    None    => (rand_between(35, 15), "owner_absent_handled_via_team_runbook"),
};

Rutas#

RutaQue muestra
/healthliveness
/incident-legacy?scenario=owner_absent&runbook=db_failoverstatus: crashed, mttr_min: 120
/incident-distributed?scenario=owner_absent&runbook=db_failoverstatus: handled, MTTR mucho menor
/share-knowledge?owner=bob&runbook=db_failoversube coverage +15 y bus_factor +1
/incidentshistorial de los ultimos 30 incidentes
/diagnostics/summaryincidentes por variante + coverage y bus factor
/reset-labvuelve a un solo owner y coverage 30

Hub#

docker compose -f compose.rust.yml up -d --build
curl "http://127.0.0.1:8700/12/incident-legacy?scenario=owner_absent"
curl "http://127.0.0.1:8700/12/share-knowledge?owner=bob"
curl "http://127.0.0.1:8700/12/incident-distributed?scenario=owner_absent"

Verificado: la variante legacy devuelve panic: called Option::unwrap() on a None value; la distributed devuelve owner_absent_handled_via_team_runbook; y share-knowledge sube coverage de 30 a 45 y bus factor de 1 a 2.

Option<T> cierra el arco que abren los otros seis stacks#

Los siete lenguajes resuelven la misma pregunta —"¿y si no hay owner?"— con herramientas distintas:

StackHerramientaSe puede ignorar el chequeo?
PHP / Pythonisset() / if x is NoneSi, olvidarlo es un TypeError en runtime
Nodeoptional chaining ?.Si, undefined se propaga en silencio
JavaOptional<T>Si — .get() sin isPresent() compila
.NETnullable reference typesSi, el chequeo es un warning, no un error
Gocomma-ok v, ok := m[k]Si — v, _ := m[k] es legal
RustOption<T> + match exhaustivoNo: omitir el brazo None no compila

Y el operador ? hace que el camino correcto sea tambien el mas corto de escribir, que es la unica forma de que una convencion sobreviva a un equipo real.

Lo que Rust NO hace: impedir el atajo. .unwrap() existe, es una palabra, y convierte cualquier ausencia en un panic. Este caso lo usa a proposito en la variante legacy para demostrarlo. Un .unwrap() en codigo de produccion es exactamente el mismo olor que un Optional.get() sin isPresent() — la diferencia es que se puede grepear en una sola pasada, y que ningun linter serio de Rust lo deja pasar sin justificacion.

Ver esta carpeta en GitHub ↗