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 Limpia70 XP7 min

OCP: El Principio Abierto/Cerrado

Los artefactos de software deben estar abiertos para extensión pero cerrados para modificación — añadir nuevo comportamiento debe añadir código, no cambiarlo.

Por qué importa

El OCP, formulado originalmente por Bertrand Meyer, está en el corazón del pensamiento arquitectónico. Martin lo ilustra con un sistema de informes financieros que debe migrar de una vista web a una vista de impresión. Si el sistema está estructurado de modo que las responsabilidades están separadas y las dependencias fluyen hacia la política de alto nivel, el componente de cálculo financiero nunca necesita cambiar — solo se agrega un nuevo componente de renderizado.

La clave es la protección: los componentes de alto nivel deben protegerse de los cambios en los de bajo nivel. Cuando agregas una nueva funcionalidad añadiendo una nueva clase en lugar de modificar una existente, proteges todas las pruebas existentes y todo el comportamiento existente. La sentencia if/switch que crece con cada nuevo caso es el enemigo más común del OCP — cada nuevo caso es una modificación del código existente, probado y desplegado.

✗El problema

Cada nuevo formato de salida requiere editar la misma función — modificando código probado y desplegado, arriesgando regresiones.

Bad

def generate_report(data: list, output_type: str) -> str:
    if output_type == "web":
        return "<html>" + render_html(data) + "</html>"
    elif output_type == "pdf":
        return render_pdf(data)
    # Adding "excel" means touching existing, tested code — violation!
function generateReport(data: Row[], outputType: string): string {
  if (outputType === "web") {
    return "<html>" + renderHtml(data) + "</html>";
  } else if (outputType === "pdf") {
    return renderPdf(data);
  }
  throw new Error("Unknown output type");
  // Adding "excel" means editing here — closed to extension!
}

✓La solución

An abstract renderer interface lets each format live in its own class. Adding Excel support means writing a new class — existing code is never touched.

Good

from abc import ABC, abstractmethod

class ReportRenderer(ABC):
    @abstractmethod
    def render(self, data: list) -> str: ...

class WebRenderer(ReportRenderer):
    def render(self, data: list) -> str:
        return "<html>" + render_html(data) + "</html>"

class PDFRenderer(ReportRenderer):
    def render(self, data: list) -> str:
        return render_pdf(data)

class ExcelRenderer(ReportRenderer):   # added without touching any existing code
    def render(self, data: list) -> str:
        return render_excel(data)

def generate_report(data: list, renderer: ReportRenderer) -> str:
    return renderer.render(data)
interface ReportRenderer {
  render(data: Row[]): string;
}

class WebRenderer implements ReportRenderer {
  render(data: Row[]): string {
    return "<html>" + renderHtml(data) + "</html>";
  }
}

class PDFRenderer implements ReportRenderer {
  render(data: Row[]): string { return renderPdf(data); }
}

class ExcelRenderer implements ReportRenderer { // new class, zero edits elsewhere
  render(data: Row[]): string { return renderExcel(data); }
}

function generateReport(data: Row[], renderer: ReportRenderer): string {
  return renderer.render(data);
}

💡Conclusión clave

Cada nuevo caso añadido a un if/switch es una modificación del código existente — un riesgo de regresión. El OCP dice: diseña de modo que el nuevo comportamiento llegue como código nuevo, nunca como ediciones a código que ya funciona.

🔧 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: Cada vez que añades un nuevo caso a un if/switch, estás violando el OCP. Una nueva clase es más segura.

✗ Tu versión

OCP: El Principio Abierto/Cerrado — CleanKata — CleanKata