Principios SOLID en JavaScript: implementación avanzada y ejemplos de código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: SOLID en el ecosistema JavaScript

SOLID es el acrónimo de cinco principios fundamentales del diseño orientado a objetos, formulados por Robert Martin. En el contexto de JavaScript, especialmente al desarrollar en Node.js con TypeScript y frameworks modernos (NestJS, Express), estos principios se vuelven críticamente importantes para construir aplicaciones escalables y mantenibles. A nivel avanzado, SOLID va más allá de clases e interfaces simples, abordando la arquitectura de módulos, la inyección de dependencias y las pruebas.

En este artículo, analizaremos cada principio SOLID con ejemplos de código para Node.js, centrándonos en los matices prácticos y los errores típicos. Aprenderás cómo aplicar SOLID en proyectos reales utilizando las capacidades de JavaScript (ES6+) y TypeScript.



1. Principio de responsabilidad única (SRP) en JavaScript

Teoría: Una clase o módulo debe tener solo una razón para cambiar. En JavaScript, esto a menudo se viola cuando en un mismo archivo se mezclan la lógica de negocio, el trabajo con la base de datos y el formateo de respuestas.

Práctica (Node.js): Separamos la responsabilidad a nivel de servicios y repositorios.

// ❌ Violación de SRP: la clase procesa solicitudes, valida y guardaclass UserService {    createUser(data) {        if (!data.email) throw new Error('Email requerido');        const db = new Database();        return db.save('users', data);    }}

// ✅ Cumplimiento de SRP: separación en validador, repositorio y servicioclass UserValidator { validate(data) { if (!data.email) throw new Error('Email requerido'); }}

class UserRepository { constructor(db) { this.db = db; } save(data) { return this.db.save('users', data); }}

class UserService { constructor(validator, repository) { this.validator = validator; this.repository = repository; } createUser(data) { this.validator.validate(data); return this.repository.save(data); }}

Utiliza inyección de dependencias (DI) para pasar el validador y el repositorio al servicio. Esto simplifica las pruebas y el reemplazo de componentes.



2. Principio de abierto/cerrado (OCP) a través del polimorfismo

Teoría: Las clases deben estar abiertas para la extensión, pero cerradas para la modificación. En JavaScript, esto se logra mediante herencia, composición o estrategias.

Práctica (Node.js con TypeScript): Usamos clases abstractas o interfaces para definir un contrato.

// Clase abstracta para informesabstract class ReportGenerator {    abstract generate(data: any): string;}

class PDFReport extends ReportGenerator { generate(data: any): string { return `PDF: ${JSON.stringify(data)}`; }}

class CSVReport extends ReportGenerator { generate(data: any): string { return `CSV: ${data.join(',')}`; }}

// El código cliente no cambia al agregar nuevos formatosclass ReportService { constructor(private generator: ReportGenerator) {} createReport(data: any) { return this.generator.generate(data); }}

Para JavaScript puro, utiliza fábricas o estrategias (patrón Strategy) para evitar modificar el código existente.



3. Principio de sustitución de Liskov (LSP) en código asíncrono

Teoría: Los objetos de una clase base deben ser reemplazables por objetos de una clase derivada sin alterar el funcionamiento del programa. En JavaScript, LSP a menudo se viola al sobrescribir métodos con diferentes contratos (por ejemplo, tipos de retorno o excepciones).

Práctica (Node.js con async/await): Asegúrate de que las subclases no debiliten las precondiciones ni refuercen las postcondiciones.

class Database {    async connect() { return 'con                

Blogs

Book Recommendations