Mostrando entradas con la etiqueta programación. Mostrar todas las entradas
Mostrando entradas con la etiqueta programación. Mostrar todas las entradas

El Catálogo Completo: Los 11 Patrones de Arquitectura que debes conocer

Si pensabas que solo existían los microservicios o los monolitos, prepárate. El mundo de la arquitectura de software es gigante. Aquí tienes el mapa definitivo con todos los patrones arquitectónicos principales explicados de forma breve y sin rodeos.

El Catálogo Completo: Los 11 Patrones de Arquitectura que debes conocer


1. Monolithic Architecture (Arquitectura Monolítica)

  • En pocas palabras: Todo el sistema (interfaz, lógica y datos) se compila y ejecuta como una única unidad.

  • Ideal para: Proyectos pequeños, startups, MVPs o equipos pequeños que necesitan velocidad de lanzamiento.

2. Microservices Architecture (Microservicios)

  • En pocas palabras: El sistema se divide en una colección de pequeños servicios autónomos, donde cada uno corre su propio proceso y maneja su propia base de datos.

  • Ideal para: Aplicaciones gigantescas con múltiples equipos de desarrollo que necesitan escalar partes del negocio de forma independiente.

3. Layered / N-Tier Architecture (Arquitectura en Capas)

  • En pocas palabras: Organiza el código en componentes horizontales (Presentación, Negocio, Datos). Cada capa tiene una responsabilidad única y solo puede comunicarse con la capa que tiene inmediatamente abajo.

  • Ideal para: Aplicaciones empresariales estándar y monolitos que buscan un orden básico y limpio.

4. Event-Driven Architecture (Orientada a Eventos)

  • En pocas palabras: Los componentes no se llaman entre sí directamente; en su lugar, reaccionan a "eventos" (acciones que pasaron en el sistema) publicados en un intermediario (como Kafka o RabbitMQ).

  • Ideal para: Sistemas altamente asincrónicos, procesamiento de datos en tiempo real o plataformas de e-commerce complejas.

5. Hexagonal / Onion / Clean Architecture (Puertos y Adaptadores)

  • En pocas palabras: Coloca las reglas del negocio en el centro absoluto del universo. Todo lo demás (bases de datos, frameworks, APIs externas) son detalles externos que se conectan mediante "puertos" (interfaces) para no contaminar el núcleo.

  • Ideal para: Proyectos a largo plazo que necesitan cambiar de tecnologías o librerías con frecuencia sin romper las reglas del negocio.

6. Service-Oriented Architecture - SOA (Arquitectura Orientada a Servicios)

  • En pocas palabras: El ancestro de los microservicios. Expone las funciones del negocio como servicios independientes pero conectados obligatoriamente por un bus central de datos gigante (ESB - Enterprise Service Bus).

  • Ideal para: Integrar sistemas gigantescos y viejos (legacy) dentro de corporaciones o bancos.

7. Serverless Architecture / FaaS (Arquitectura Sin Servidor)

  • En pocas palabras: Descompones tu aplicación en funciones puras que se ejecutan en la nube (como AWS Lambda) solo cuando alguien las necesita. No gestionas servidores; solo pagas por milisegundo de ejecución.

  • Ideal para: Tareas que se ejecutan de vez en cuando (como procesar una imagen que sube un usuario) o APIs con tráfico muy variable.

8. Microkernel / Plug-in Architecture (Micronúcleo)

  • En pocas palabras: Tienes un sistema central con las funciones mínimas obligatorias para que la app funcione, y todo lo demás se le añade mediante extensiones o "plug-ins" independientes.

  • Ideal para: Aplicaciones de escritorio (como VS Code o navegadores web) y plataformas e-learning o CMS (como Moodle o WordPress) que dependen de plugins para crecer.

9. CQRS (Command Query Responsibility Segregation)

  • En pocas palabras: Separa por completo el camino que toma el código para escribir/modificar datos (Commands) del camino que toma para leer datos (Queries). Incluso pueden usar bases de datos distintas (una rápida para guardar y otra optimizada para buscar).

  • Ideal para: Aplicaciones con un volumen brutal de lecturas y escrituras donde las bases de datos tradicionales se quedan cortas.

10. Peer-to-Peer - P2P (Red de Pares)

  • En pocas palabras: No hay un servidor central. Todos los nodos de la red actúan tanto como clientes como servidores, compartiendo la carga y la información entre ellos.

  • Ideal para: Redes de intercambio de archivos (como BitTorrent) o tecnologías basadas en Blockchain.

11. Master-Slave / Broker Architecture (Maestro-Esclavo / Intermediario)

  • En pocas palabras: Un componente principal ("Maestro") distribuye el trabajo y coordina a varios componentes idénticos ("Esclavos") que hacen la tarea pesada. En su variante Broker, un intermediario coordina la comunicación entre ellos.

  • Ideal para: Sistemas distribuidos, bases de datos que necesitan réplicas para no perder información o procesamiento de renderizado masivo.

 Con este mapa en la mano, ya tienes el vocabulario técnico para entender cualquier discusión de arquitectura en la industria. No los uses todos a la vez; el verdadero arte está en elegir el adecuado para el problema correcto.

Artículo relacionado Arquitectura de Software: Buenas prácticas para que tu app no sea un "castillo de naipes"

Arquitectura de Software: Buenas prácticas para que tu app no sea un "castillo de naipes"

Cuando empezamos a programar, nuestra única preocupación es que el código compile y la aplicación corra. "Si funciona, no lo toque", decimos molestando. El problema es que cuando el proyecto crece, entran más usuarios y el negocio cambia, ese código que funcionaba se convierte en un castillo de naipes: tocas una esquina y se cae todo el sistema.

Ahí es donde entra la Arquitectura de Software. No es más que el conjunto de decisiones estratégicas que tomamos para que una aplicación sea estable, segura y, sobre todo, fácil de mantener en el futuro.

Para que tu próximo proyecto no se vuelva un dolor de cabeza, aquí tienes las mejores prácticas de arquitectura explicadas sin tanta palabrería técnica.

Arquitectura de Software: Buenas prácticas para que tu app no sea un "castillo de naipes"


1. Divide y vencerás: Arquitectura en Capas (Layered Architecture)

El error más común en proyectos primerizos es mezclar todo en el mismo archivo: la validación de los datos, la lógica del negocio (las reglas de la empresa) y las consultas a la base de datos. A esto en el mundo del software le llamamos el Antipatrón de la Gran Bola de Lodo.

La mejor práctica es separar tu aplicación en capas independientes:

  • Capa de Presentación (Frontend / API): Es la cara externa. Solo se encarga de recibir los datos del usuario y mostrar las respuestas. No sabe cómo se procesan las cosas.

  • Capa de Negocio (Dominio): El cerebro de la operación. Aquí se programan las reglas del negocio (por ejemplo: "Si el cliente compra más de $200.000, aplique un 10% de descuento").

  • Capa de Datos (Persistencia): La encargada de hablar con la base de datos o servicios externos.

💡 La regla de oro: Las capas superiores pueden hablar con las inferiores, pero nunca al revés. La base de datos no tiene por qué saber cómo se muestra un botón en la pantalla.

2. No te cases con las herramientas (Desacoplamiento)

Un error clásico es construir toda la lógica de tu aplicación alrededor de una herramienta específica. Por ejemplo, estructurar todo tu código pensando únicamente en que usas una base de datos MySQL o una librería específica para enviar correos.

¿Qué pasa si mañana el proyecto crece y MySQL se queda corto y toca pasar a PostgreSQL? O peor, ¿qué pasa si el servicio que usas para enviar mensajes de texto se cae y te toca cambiar de proveedor a mitad de la noche?

  • La buena práctica: Diseña tu arquitectura usando interfaces o abstracciones (como vimos en el principio SOLID de Inversión de Dependencias). Tu lógica de negocio debe decir: "Necesito guardar un usuario", y no "Necesito hacer un INSERT en esta tabla de MySQL". Así, cambiar la base de datos o el proveedor de correos se vuelve tan fácil como cambiar un bombillo.

3. Mantén las cosas simples: El principio KISS (Keep It Simple, Stupid)

A los desarrolladores nos encanta complicarnos la vida. Apenas aprendemos sobre patrones de diseño o arquitecturas avanzadas (como Clean Architecture o Microservicios), queremos metérselas al proyecto de la panadería de la esquina. Esto se llama sobreingeniería.

  • La realidad: Montar una arquitectura de microservicios para un proyecto que apenas está empezando y tiene 100 usuarios es como comprar un tractocamión para ir a comprar el pan a la tienda. Lo único que vas a lograr es aumentar los costos en la nube (como AWS o Azure) y hacer que el desarrollo sea lentísimo.

  • La buena práctica: Empieza con un Monolito Modular. Es decir, una sola aplicación, pero muy bien organizada por carpetas y módulos limpios. Si el día de mañana un módulo se vuelve gigante y necesita procesar millones de datos solo, entonces lo separas. Mientras tanto, manténlo simple.

4. Diseña pensando en fallos (Resiliencia)

En local (en tu computador) todo funciona perfecto. Pero en producción, en el mundo real, todo lo que puede fallar, va a fallar. El internet se cae, el servidor de la base de datos se satura, o la API del proveedor de facturación electrónica deja de responder por media hora.

Una buena arquitectura no es la que nunca falla, sino la que sabe cómo recuperarse del fallo sin arruinarle la experiencia al usuario.

  • ¿Cómo aplicarlo? * Usa mecanismos de reintento (Retries): Si una API externa no responde, no saques un error de inmediato; programa el sistema para que lo intente 3 veces más con unos segundos de diferencia.

    • Implementa Circuit Breakers (Disyuntores): Si un servicio externo está totalmente caído, apaga esa funcionalidad temporalmente y muestra un mensaje amigable al usuario en vez de dejar la pantalla cargando al infinito.

En conclusión: La arquitectura se mide en el tiempo

Una buena arquitectura de software no se nota el primer día que lanzas la aplicación; se nota seis meses después, cuando el cliente te pide un cambio grande y tú puedes implementarlo en un par de horas, relajado y sin miedo a romper el sistema.

No construyas software para el "ahorita", organízalo pensando en el desarrollador del futuro (que muy probablemente serás tú mismo lidiando con tu propio código).

Recomiendo leer El Mapa Completo: Las 3 familias de Patrones de Diseño de software

El Mapa Completo: Las 3 familias de Patrones de Diseño de software

Si entras a portales especializados como Refactoring Guru, vas a ver que existen 22 patrones clásicos (los del famoso grupo Gang of Four). Aprenderse todos de memoria es una locura. La clave está en entender que se dividen en tres grandes categorías, según el "chicharrón" que vienen a resolver:

El Mapa Completo: Las 3 familias de Patrones de Diseño de software




1. Patrones Creacionales: ¿Cómo creamos los objetos?

Estos patrones se encargan de definir el mecanismo para crear objetos en el sistema. Su meta es que tu código no dependa de cómo se crean, componen o representan esos objetos, evitando llenar todo de new Clase() de forma desordenada.

  • ¿Cuándo se usan? Cuando la creación de un objeto es compleja, depende de configuraciones externas o necesitas controlar cuántas instancias se crean.

  • Los más famosos de este grupo:

    • Singleton: Una única instancia para toda la app (ej. la conexión a la base de datos).

    • Factory Method: Una fábrica que decide qué objeto crear por ti según la situación.

    • Abstract Factory: Una super-fábrica que crea otras fábricas (para cuando manejas familias de productos).

    • Builder: Ideal para crear objetos gigantes paso a paso (ej. un constructor de consultas SQL complejas).

2. Patrones Estructurales: ¿Cómo armamos el rompecabezas?

Estos patrones se enfocan en cómo se unen las clases y objetos para formar estructuras más grandes y eficientes, sin perder flexibilidad ni volverse una estructura rígida.

  • ¿Cuándo se usan? Cuando tienes muchas clases que necesitan trabajar juntas, o cuando necesitas que código viejo (legacy) se entienda con código nuevo sin cambiarlo todo.

  • Los más famosos de este grupo:

    • Adapter: Funciona como un transformador de corriente. Permite que dos interfaces que no tienen nada que ver puedan trabajar juntas (ej. conectar una librería externa vieja a tu backend moderno).

    • Decorator: Te permite añadirle superpoderes o funciones a un objeto en tiempo de ejecución sin alterar su clase original.

    • Facade (Fachada): Te da una interfaz simple para esconder un sistema supercomplejo que hay detrás. El usuario solo ve un botón, pero por dentro se mueven mil engranajes.

3. Patrones de Comportamiento: ¿Cómo se hablan entre sí?

Aquí no nos importa tanto cómo se crean las clases o cómo se estructuran, sino cómo se comunican y qué responsabilidades tiene cada una al ejecutar algoritmos o procesos del negocio.

  • ¿Cuándo se usan? Cuando necesitas gestionar flujos de datos complejos, eventos, estados o cadenas de decisiones entre muchos objetos.

  • Los más famosos de este grupo:

    • Observer: El sistema de suscripción/notificaciones que vimos antes.

    • Strategy: Te permite cambiar el algoritmo o la lógica que usa una clase en tiempo de ejecución (ej. cambiar la estrategia de envío de "Efecty" a "Nequi" con un solo clic).

    • State: Permite que un objeto cambie su comportamiento dependiendo del estado en el que esté (ej. un pedido no hace lo mismo si está en estado "Pendiente" que en estado "Enviado").

Tabla Resumen para Guardar en Favoritos

Para que tus lectores no se pierdan, les puedes dejar este "machete" (tarjeta de referencia rápida):

Familia¿Cuál es su objetivo principal?Ejemplo de la vida real
CreacionalesControlar e independizar la creación de objetos.El mesero que te trae la comida de la cocina sin que sepas la receta.
EstructuralesOrganizar clases para que encajen de forma flexible.El adaptador que usas para conectar tu celular en un avión.
De ComportamientoGestionar la comunicación y lógica entre objetos.Un grupo de WhatsApp donde el administrador manda un mensaje y todos reaccionan.
Recomiendo leer Arquitectura de Software: Buenas prácticas para que tu app no sea un "castillo de naipes"
Para ver todos los patrones de diseño ingresa a https://refactoring.guru/es/design-patterns

¿Tu código es un "camello" de mantener? Organízalo con los Principios SOLID Básicos

Si llevas un tiempo echando código, seguro te has encontrado con ese temido momento: te piden un cambio pequeño en una función y, de la nada, se daña la mitad de la aplicación. Te toca quedarte hasta tarde resolviendo un chicharrón que ni sabías de dónde salió.

Para que el desarrollo no se vuelva un "camello" indomable, la comunidad de software utiliza una guía clave: los principios SOLID. Aunque suenan muy teóricos, hoy vamos a bajarlos a la tierra con plastilina y ejemplos claros para que empieces a aplicarlos desde ya.

¿Tu código es un "camello" de mantener? Organízalo con los Principios SOLID Básicos


¿Qué es SOLID?

SOLID es un acrónimo inventado por Robert C. Martin ("Uncle Bob") que reúne cinco buenas prácticas de la programación orientada a objetos. Su objetivo principal es ayudarnos a escribir código limpio, fácil de entender y, sobre todo, fácil de cambiar en el futuro.

Vamos a ver los tres primeros principios, que son el mejor punto de partida para cualquier desarrollador.

1. S: Principio de Responsabilidad Única (Single Responsibility Principle)

La regla de oro: Una clase o módulo debería tener una sola razón para cambiar.

En Colombia nos encanta el "todero" (el que arregla la luz, pinta, sabe de plomería y arregla el carro), pero en el código, los toderos son un peligro. Si tienes una clase que se encarga de calcular un reporte, darle formato a un PDF y además guardarlo en la base de datos, estás rompiendo este principio.

  • El problema: Si mañana cambia la forma de conectar la base de datos, podrías dañar sin querer la lógica que calcula el reporte.

  • La solución: Divide y vencerás. Crea una clase para el cálculo, otra para generar el PDF y otra para la base de datos. Cada una a lo suyo.

2. O: Principio de Abierto/Cerrado (Open/Closed Principle)

La regla de oro: El software debe estar abierto para la extensión, pero cerrado para la modificación.

Imagina que estás construyendo una pasarela de pagos para un e-commerce y configuras todo para recibir pagos con Efecty. Semanas después, el cliente te dice: "Oiga, ahora necesitamos recibir Nequi y Daviplata".

Si para meter Nequi te toca abrir el archivo original y meter un montón de condicionales (if/else), estás rompiendo el principio.

  • La solución: Diseña tu código usando interfaces o clases abstractas. Creas una estructura general para "PasarelaDePago". Cuando llegue Nequi, simplemente creas un archivo nuevo que extienda de esa estructura. El código viejo no se toca (cerrado a modificación), pero la aplicación crece sin problema (abierta a extensión).

3. L: Principio de Sustitución de Liskov (Liskov Substitution Principle)

La regla de oro: Si tienes una clase hijo, deberías poder usarla en lugar de la clase padre sin que todo se rompa.

Este principio nos dice que la herencia debe ser real y lógica. Piensa en esto: una empresa de envíos tiene una clase padre llamada VehiculoDeReparto. De ahí heredan Camion y Motocicleta. Ambos pueden acelerar, frenar y llevar paquetes. Todo bien.

Pero si creas una clase Dron De Reparto y resulta que no implementa el método encenderMotor() igual porque funciona con batería digital o no usa la misma lógica de rutas terrestres, podrías generar un error cuando el sistema intente manejar el dron como si fuera un camión.

  • En cristiano: Las clases hijas no deben decepcionar las expectativas que dejó la clase padre. Tienen que ser capaces de hacer lo mismo que el padre promete.

4. I: Principio de Segregación de Interfaces (Interface Segregation Principle)

La regla de oro: Es mejor tener muchas interfaces específicas que una sola interfaz general "todera". Nadie debería estar obligado a depender de métodos que no usa.

Imagina que creas una interfaz llamada Trabajador. Como estás pensando en un equipo grande, le pones los métodos programar(), disenarInterface() y venderProyecto().

Si creas una clase para un desarrollador backend y le implementas esa interfaz, el sistema lo va a obligar a escribir código para disenarInterface() y venderProyecto(). ¿Qué va a terminar pasando? Que el desarrollador va a dejar esos métodos vacíos o sacando un error porque esa no es su labor.

  • La solución: Segmenta. En lugar de una interfaz gigante, crea tres pequeñas: Programable, Disenable y Vendible. Así, cada clase implementa solo lo que realmente sabe y necesita hacer. No pongas a tu código a cargar con obligaciones ajenas.

5. D: Principio de Inversión de Dependencias (Dependency Inversion Principle)

La regla de oro: Los módulos de alto nivel no deben depender de módulos de bajo nivel; ambos deben depender de abstracciones. Además, las abstracciones no deben depender de los detalles.

Este suena como un trabalenguas, pero se entiende muy fácil con un ejemplo del mundo real. Piensa en los tomacorrientes de las paredes de tu casa. La empresa de energía te da una abstracción (el enchufe estándar). A ti no te importa si detrás de la pared hay cables de cobre, de aluminio, o si la luz viene de una hidroeléctrica o de paneles solares (esos son los detalles de bajo nivel). Tú solo conectas tu cargador y funciona.

En el software es igual. Si tienes una clase de alto nivel como ProcesarPedido, esta no debería depender directamente de una clase de bajo nivel llamada EnviarCorreoConMailgun.

  • El problema: Si el día de mañana Mailgun sube los precios y te toca cambiar a Amazon SES, vas a tener que modificar la lógica de los pedidos, arriesgándote a dañar el negocio por un cambio de proveedor.

  • La solución: Haz que ProcesarPedido dependa de una interfaz genérica llamada ServicioDeCorreo. Así, cambias el proveedor abajo (en el detalle) las veces que quieras, y tu lógica principal (el pedido) ni se entera ni se rompe.

¿Por qué deberías empezar a usarlos?

Al principio, aplicar SOLID puede dar la impresión de que estás escribiendo más archivos de la cuenta o dando muchas vueltas. Sin embargo, la recompensa llega muy rápido:

  • Menos dolores de cabeza: Encontrar un bug es mil veces más fácil cuando cada archivo hace una sola cosa.

  • Trabajo en equipo fluido: Tus compañeros de equipo entenderán tu código a la primera, sin necesidad de que les des una exposición de dos horas.

  • Código que escala: Tu proyecto puede crecer de un MVP básico a una plataforma robusta sin que sientas que la estructura se va a caer en cualquier momento.

Escribir código que funcione lo hace cualquiera; escribir código que dure y sea un gusto mantener, eso es lo que define a un verdadero profesional.

¡A ponerlos en práctica en los proyectos de esta semana!