Política y Nivel
El nivel es la distancia a las entradas y salidas — cuanto más lejos de la E/S, mayor el nivel. Las dependencias del código fuente siempre deben apuntar hacia las políticas de más alto nivel y más estables.
Por qué importa
Cada política en un sistema tiene un nivel — definido por su distancia de las entradas y salidas. Leer de un archivo es de bajo nivel: está directamente adyacente a un dispositivo de entrada. Escribir en una pantalla es de bajo nivel: está adyacente a un dispositivo de salida. Un algoritmo de cifrado, sin embargo, es de alto nivel: transforma datos pero no le importa de dónde vienen ni adónde irán. Es máximamente distante de cualquier dispositivo de E/S particular.
Este concepto gobierna la dirección de las dependencias. Las políticas de bajo nivel cambian con frecuencia — formatos de archivo, formas de API, estructuras de UI. Las políticas de alto nivel cambian raramente — lógica de negocio, algoritmos, reglas fundamentales. Si una política de bajo nivel depende de una de alto nivel (correctamente), un cambio en el formato de archivo nunca toca la lógica de cifrado. Si la dependencia está invertida — si el algoritmo de alto nivel conoce el archivo — un cambio trivial en el formato de entrada requiere tocar el código más valioso del sistema.
✗El problema
An encrypt() function that simultaneously opens files, iterates characters, and applies the cipher — all levels mixed in one function, impossible to reuse the cipher logic alone.
Bad
import sys
def encrypt(input_path: str, output_path: str, shift: int) -> None:
# Low-level: file I/O (close to input/output devices)
with open(input_path, "r") as fin, open(output_path, "w") as fout:
for line in fin:
result = ""
for char in line:
# High-level: cipher rule (farthest from I/O)
if char.isalpha():
base = ord("A") if char.isupper() else ord("a")
result += chr((ord(char) - base + shift) % 26 + base)
else:
result += char
fout.write(result)
# The cipher algorithm is buried inside file-open and file-write.
# To reuse the cipher for HTTP, stdin, or sockets: copy-paste only.
# To test the cipher alone: must provide real files.
# All levels are at the same level — there is no level.
import { readFileSync, writeFileSync } from "fs";
export function encryptFile(inputPath: string, outputPath: string, shift: number): void {
const content = readFileSync(inputPath, "utf-8"); // low-level
const result = content.split("").map(char => { // mixed levels
if (/[a-z]/i.test(char)) {
const base = char >= "a" ? 97 : 65;
const offset = (char.charCodeAt(0) - base + shift) % 26;
return String.fromCharCode(base + offset); // high-level cipher rule
}
return char;
}).join("");
writeFileSync(outputPath, result, "utf-8"); // low-level
}
// The cipher is trapped inside file I/O. Not reusable. Not independently testable.
✓La solución
Pure cipher function at the highest level — knows nothing about I/O. File and stdin wrappers at lower levels depend on it, not the reverse.
Good
# High-level policy (farthest from I/O) — pure and reusable
def caesar_cipher(text: str, shift: int) -> str:
result = []
for char in text:
if char.isalpha():
base = ord("A") if char.isupper() else ord("a")
result.append(chr((ord(char) - base + shift) % 26 + base))
else:
result.append(char)
return "".join(result)
# Lower-level: file-based wiring (depends on caesar_cipher, not vice versa)
def encrypt_file(input_path: str, output_path: str, shift: int) -> None:
with open(input_path, "r") as fin, open(output_path, "w") as fout:
for line in fin:
fout.write(caesar_cipher(line, shift))
# Lower-level: stdin/stdout wiring (depends on the same high-level rule)
def encrypt_stdin(shift: int) -> None:
import sys
for line in sys.stdin:
sys.stdout.write(caesar_cipher(line, shift))
# Dependency direction: encrypt_file → caesar_cipher (low → high, correct)
# Test: assert caesar_cipher("Hello", 1) == "Ifmmp" — no file system needed.
// High-level policy — depends on nothing, changes only for business reasons
export function caesarCipher(text: string, shift: number): string {
return text.split("").map(char => {
if (/[a-z]/i.test(char)) {
const base = char >= "a" ? 97 : 65;
const offset = (char.charCodeAt(0) - base + shift) % 26;
return String.fromCharCode(base + offset);
}
return char;
}).join("");
}
// Lower-level: file-based wiring
import { readFileSync, writeFileSync } from "fs";
export function encryptFile(inputPath: string, outputPath: string, shift: number): void {
writeFileSync(outputPath, caesarCipher(readFileSync(inputPath, "utf-8"), shift), "utf-8");
}
// Lower-level: HTTP wiring (same high-level rule, different delivery mechanism)
import type { Request, Response } from "express";
export function encryptEndpoint(req: Request, res: Response): void {
const { text, shift } = req.body as { text: string; shift: number };
res.json({ encrypted: caesarCipher(text, shift) });
}
// caesarCipher depends on nothing.
// encryptFile and encryptEndpoint depend on caesarCipher.
// Dependencies flow from volatile (I/O) → stable (cipher rule).
// Test: expect(caesarCipher("Hello", 1)).toBe("Ifmmp");
💡Conclusión clave
Las políticas de alto nivel cambian raramente y por razones de negocio. Los detalles de bajo nivel cambian con frecuencia y por razones técnicas. Las dependencias deben fluir de lo volátil a lo estable — desde la frontera de E/S hacia adentro, hacia el algoritmo. Nunca al revés.
🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.
Pista: Las políticas de alto nivel cambian poco y por razones de negocio. Los detalles de bajo nivel cambian con frecuencia y por razones técnicas. Las dependencias deben fluir de lo volátil a lo estable.
✗ Tu versión