Parte 11 — Proyecto integrador políglota · ⏱️ Duración estimada: 90 min · Nivel: Intermedio ✅ Clase construida — 10 implementaciones del núcleo verificadas contra
casos.json.
Construimos el componente de automatización: los scripts que ejecutan tareas repetitivas sin que nadie
las mire —limpiar temporales, respaldar, desplegar, mandar informes—. Es el pegamento del sistema, el que
hace que las piezas trabajen juntas de noche y en fin de semana. Hoy modelamos su forma esencial: procesar
un lote de n tareas y confirmar su finalización.
La automatización es uno de los pilares de The Pragmatic Programmer, donde Hunt y Thomas dedican un capítulo entero a "la ubicuidad de la automatización" con una tesis contundente: todo lo que haces a mano más de una vez es un candidato a script, porque las manos se cansan, se distraen y se equivocan, mientras un script hace lo mismo la vez mil que la primera. Esa fiabilidad no es solo comodidad: es la base de la reproducibilidad. Un despliegue automatizado se puede auditar, versionar y repetir idéntico; un despliegue manual es una anécdota irrepetible. Por eso este componente, aunque humilde, sostiene la salud del sistema entero.
Al finalizar, podrás:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Automatización | Tareas repetitivas sin intervención humana |
| 2 | Scripting | El pegamento que compone los componentes |
| 3 | Lote de tareas | Procesar en serie y confirmar |
La automatización es ejecutar tareas repetitivas sin intervención humana; su valor es la fiabilidad y la reproducibilidad, no solo el tiempo ahorrado. Un script es un programa que orquesta o automatiza pasos —el pegamento que une componentes que no fueron diseñados para hablarse directamente—. Un lote es un conjunto de tareas procesadas juntas, la unidad típica de un trabajo nocturno.
Hay una propiedad silenciosa pero crucial en este mundo: la idempotencia. Un buen script de
automatización se puede volver a lanzar tras un fallo sin causar estragos —respaldar dos veces no rompe
nada, pero cobrar dos veces sí—. Nygard, en Release It!, advierte que los trabajos automáticos son
justamente donde los fallos se acumulan en silencio: si nadie mira y nadie registra, un lote roto puede
llevar semanas pasando desapercibido. De ahí que confirmar la finalización —el estado=completado de esta
clase— no sea decorativo: es la señal que un sistema de monitoreo necesita para saber que la noche fue bien.
Un script nocturno procesa las tareas pendientes: limpia archivos temporales, respalda la base de datos, notifica por correo, y al terminar confirma. Si una de esas tareas falla y el script se detiene sin avisar, el respaldo no se hizo y nadie se entera hasta que hace falta restaurarlo —el peor momento posible—. Por eso la automatización real se apoya en tres cosas que este ejercicio mínimo prefigura: procesar el lote, registrar el resultado y confirmar el desenlace. Python y Bash dominan aquí por su rapidez de escritura y su ubicuidad: están en todas partes y expresan "haz esto, luego esto" con un mínimo de ceremonia.
n (número de tareas)tareas=<n> estado=completadoEspecificación y verificación en casos.json:
| stdin | esperado |
|---|---|
5 |
tareas=5 estado=completado |
0 |
tareas=0 estado=completado |
3 |
tareas=3 estado=completado |
LEER n ; procesar n tareas ; ESCRIBIR completado
Mismo algoritmo, forma idiomática en cada lenguaje. Todas producen la salida de casos.json.
Cada bloque es el archivo real de implementaciones/: el enlace de cada lenguaje abre su fuente, y el comando de al lado lo ejecuta.
python/main.py · python main.pyimport sys
n = int(sys.stdin.readline())
print(f"tareas={n} estado=completado")
🧬 El mismo programa en la familia Scripting dinámico: Ruby · Perl · Lua · Tcl · R
javascript/main.mjs · node main.mjsimport { readFileSync } from "node:fs";
const n = parseInt(readFileSync(0, "utf8").trim(), 10);
console.log(`tareas=${n} estado=completado`);
🧬 El mismo programa en la familia JavaScript / web: Dart · ActionScript
typescript/main.ts · pnpm exec tsx main.tsimport { readFileSync } from "node:fs";
const n: number = parseInt(readFileSync(0, "utf8").trim(), 10);
console.log(`tareas=${n} estado=completado`);
🧬 El mismo programa en la familia JavaScript / web: Dart · ActionScript
java/Main.java · java Main.javaimport java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
System.out.println("tareas=" + n + " estado=completado");
}
}
🧬 El mismo programa en la familia JVM: Kotlin · Scala · Groovy · Clojure
csharp/Program.cs · dotnet runusing System;
int n = int.Parse(Console.In.ReadToEnd().Trim());
Console.WriteLine($"tareas={n} estado=completado");
🧬 El mismo programa en la familia .NET: F# · VB.NET
go/main.go · go run main.gopackage main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
line, _ := bufio.NewReader(os.Stdin).ReadString('\n')
n, _ := strconv.Atoi(strings.TrimSpace(line))
fmt.Printf("tareas=%d estado=completado\n", n)
}
🧬 El mismo programa en la familia Sistemas: Zig · Nim · D
rust/main.rs · rustc main.rs -o main && ./mainuse std::io::Read;
fn main() {
let mut s = String::new();
std::io::stdin().read_to_string(&mut s).unwrap();
let n: i64 = s.trim().parse().unwrap();
println!("tareas={n} estado=completado");
}
🧬 El mismo programa en la familia Sistemas: Zig · Nim · D
c/main.c · cc main.c -o main && ./main#include <stdio.h>
int main(void) {
long n;
if (scanf("%ld", &n) != 1) return 1;
printf("tareas=%ld estado=completado\n", n);
return 0;
}
🧬 El mismo programa en la familia C / llaves: C++ · Objective-C
sql/main.sql · sqlite3 :memory: < main.sql-- SQL automatiza con procedimientos/trabajos; aqui, el conteo.
WITH t(n) AS (VALUES (5))
SELECT printf('tareas=%d estado=completado', n) AS resultado FROM t;
🧬 El mismo programa en la familia Lógica y declarativa: Prolog · Datalog
php/main.php · php main.php<?php
$n = (int) trim(fgets(STDIN));
echo "tareas=$n estado=completado\n";
🧬 El mismo programa en la familia Scripting dinámico: Ruby · Perl · Lua · Tcl · R
SQL es declarativo: no lee de stdin como los demás; su implementación muestra la misma idea sobre una tabla de casos, y el verificador la marca como ilustrativa.
| Clase de diferencia | Observación entre lenguajes |
|---|---|
| Sintáctica | Formatear la salida en cada lenguaje. |
| Semántica | La automatización procesa y confirma. |
| Paradigmática | SQL automatiza con procedimientos/trabajos. |
Python y Bash dominan el scripting; herramientas como cron y Airflow orquestan tareas.
Los mismos casos para todas las implementaciones: casos.json. Verifica la equivalencia:
python scripts/verificar_equivalencia.py 171
Detalle en reto.md.
Libros de la parte:
Libros de los lenguajes del núcleo:
⏮️ Clase 170 · 📂 Parte · 📚 Índice · 🌐 Atlas · Clase 172 ⏭️