Skip to main content

Inicia sesión en CleanKata

Sigue tu progreso, gana XP y desbloquea todas las lecciones.

Al iniciar sesión aceptas nuestros Términos de uso y Política de privacidad.

Arquitectura Limpia60 XP6 min

¿Qué es la Arquitectura? Soporte del Ciclo de Vida

El propósito principal de la arquitectura es soportar el ciclo de vida del sistema — desarrollo, despliegue, operación y mantenimiento — para maximizar la productividad y minimizar el costo.

Por qué importa

La arquitectura no se trata de hacer que un sistema funcione — incluso una mala arquitectura puede producir un sistema funcional. La arquitectura consiste en mantener el sistema fácil de desarrollar, fácil de desplegar, fácil de operar y fácil de mantener. Estas cuatro fases del ciclo de vida son la verdadera medida de la calidad arquitectónica. La estrategia es dejar el mayor número de opciones abiertas el mayor tiempo posible mientras el sistema demuestra su forma real.

Un equipo de diez personas necesita trabajar en la misma base de código sin colisionar constantemente. Un sistema con miles de usuarios necesita poder desplegarse sin reconstruirlo todo. Un equipo de operaciones necesita monitorizar y gestionar el sistema sin tocar el código fuente. Y cada cambio — ya sea añadir una funcionalidad o corregir un bug — debe estar localizado y contenido. La arquitectura moldea qué tan bien sirve el sistema a estas cuatro necesidades a lo largo de toda su vida útil.

✗El problema

All lifecycle concerns wired into one file — teams block each other, every deployment touches everything, and adding one feature requires understanding everything.

Bad

# main.py — every feature, every layer, every concern
import flask, sqlalchemy, redis, stripe, smtplib, pandas

def handle_request(request):
    user  = db.query("SELECT * FROM users WHERE token = ?", request.token)
    order = db.query("SELECT * FROM orders WHERE id = ?", request.order_id)
    discount = 0.1 if user.is_premium else 0
    total    = order.amount * (1 - discount)
    stripe.charge(user.card_token, total)
    smtp.send(user.email, f"Your order total is ${total}")
    redis.incr("orders_processed")
    return {"status": "ok", "total": total}

# Every developer edits main.py — constant merge conflicts (development).
# Any change rebuilds and redeploys everything (deployment).
# A new feature requires reading all 500 lines (maintenance).
// server.ts — all concerns in one file
import express from "express";
import { Pool } from "pg";
import Stripe from "stripe";
import nodemailer from "nodemailer";

app.post("/orders/:id/process", async (req, res) => {
  const user  = await db.query("SELECT * FROM users WHERE token = $1", [req.headers.token]);
  const order = await db.query("SELECT * FROM orders WHERE id = $1", [req.params.id]);
  const discount = user.rows[0].is_premium ? 0.1 : 0;
  const total    = order.rows[0].amount * (1 - discount);
  await stripe.charges.create({ amount: total * 100, currency: "usd" });
  await mailer.sendMail({ to: user.rows[0].email, subject: `Total: ${total}` });
  res.json({ total });
});
// One file. One deployment unit. Every team steps on every other team.

✓La solución

Separate modules by lifecycle concern — each layer is independently owned, testable, and deployable.

Good

# domain/orders.py — business rules (changes for business reasons)
class OrderService:
    def __init__(self, order_repo, payment_gateway, notifier):
        self._orders    = order_repo
        self._payments  = payment_gateway
        self._notifier  = notifier

    def process(self, order_id: str, user) -> Decimal:
        order    = self._orders.get(order_id)
        discount = Decimal("0.1") if user.is_premium else Decimal("0")
        total    = order.amount * (1 - discount)
        self._payments.charge(user.payment_method, total)
        self._notifier.send(user.email, total)
        return total

# api/routes.py       — HTTP boundary (changes for API consumer reasons)
# infrastructure/db.py — Persistence (changes for DB reasons)
# cli/commands.py     — CLI interface (changes for ops reasons)
# Each module is owned by one team and deployable independently.
// src/domain/OrderService.ts — business rules only
export class OrderService {
  constructor(
    private orders:   OrderRepository,
    private payments: PaymentGateway,
    private notifier: Notifier,
  ) {}

  async process(orderId: string, user: User): Promise {
    const order    = await this.orders.get(orderId);
    const discount = user.isPremium ? 0.1 : 0;
    const total    = order.amount * (1 - discount);
    await this.payments.charge(user.paymentMethod, total);
    await this.notifier.send(user.email, total);
    return total;
  }
}
// src/api/orderRoutes.ts   — HTTP layer (independently deployable)
// src/infra/PgOrderRepo.ts  — DB adapter (swap DB without touching domain)
// src/cli/processCmd.ts    — CLI for ops (shares domain, not HTTP)

💡Conclusión clave

La arquitectura no consiste en hacer que el sistema funcione — consiste en hacer que el sistema sea fácil de trabajar, para siempre. Separa lo que cambia por diferentes razones para que cada fase del ciclo de vida (desarrollo, despliegue, operación, mantenimiento) pueda avanzar sin interferir con las demá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: La buena arquitectura hace que el sistema sea fácil de cambiar en todas las formas en que debe cambiar, sin dificultarlo en las formas en que no debería.

✗ Tu versión

¿Qué es la Arquitectura? Soporte del Ciclo de Vida — CleanKata — CleanKata