20. Diseño de software: responsabilidades, módulos e interfaces

20.1 Introducción

El diseño de software consiste en decidir cómo se organizará una solución antes y durante su construcción. No se limita a elegir tecnologías ni a dibujar pantallas. Diseñar implica asignar responsabilidades, separar partes del sistema, definir relaciones entre módulos y establecer interfaces claras.

Un buen diseño facilita entender, probar, modificar y mantener el software. Un mal diseño puede hacer que cada cambio sea costoso, riesgoso y difícil de explicar.

En este tema veremos tres ideas centrales del diseño: responsabilidades, módulos e interfaces.

20.2 ¿Qué significa diseñar software?

Diseñar software significa tomar decisiones sobre la estructura interna y externa de una solución. Estas decisiones indican qué partes existirán, qué hará cada una, cómo se comunicarán y qué reglas deberán respetar.

Durante el diseño se responden preguntas como:

  • ¿Qué responsabilidades tendrá cada parte del sistema?
  • ¿Cómo dividiremos el sistema en módulos?
  • ¿Qué datos manejará cada módulo?
  • ¿Qué interfaces expondrá cada componente?
  • ¿Qué partes deben conocer detalles de otras?
  • ¿Dónde ubicaremos reglas de negocio?
  • ¿Cómo evitaremos duplicación y dependencias innecesarias?
  • ¿Cómo facilitaremos pruebas y cambios futuros?
Idea clave: diseñar software es organizar decisiones para que el sistema pueda crecer sin volverse incomprensible.

20.3 Del análisis al diseño

El análisis se centra en comprender el problema. El diseño se centra en organizar la solución. Ambos están relacionados, pero no son lo mismo.

Análisis Diseño
Comprende necesidades, reglas y conceptos del negocio. Decide cómo se estructurará el sistema para responder a esas necesidades.
Usa lenguaje del dominio. Puede usar lenguaje técnico y decisiones de implementación.
Pregunta qué ocurre y qué se necesita. Pregunta cómo se organizará la solución.
Ejemplo: un pedido puede estar pendiente, pagado o enviado. Ejemplo: habrá un módulo de pedidos que validará transiciones de estado.

20.4 Responsabilidades

Una responsabilidad es algo que una parte del sistema debe saber, hacer o controlar. Asignar responsabilidades correctamente es una de las decisiones más importantes del diseño.

Ejemplos de responsabilidades:

  • Validar si un usuario tiene permiso para realizar una acción.
  • Calcular el total de un pedido.
  • Registrar una operación de auditoría.
  • Enviar una notificación.
  • Consultar disponibilidad de turnos.
  • Persistir datos en una base de datos.
  • Mostrar información en una pantalla.

El diseño debe decidir dónde vive cada responsabilidad. Si se ubica en el lugar equivocado, el sistema puede volverse confuso y difícil de cambiar.

20.5 Responsabilidades bien ubicadas

Una responsabilidad está bien ubicada cuando la parte que la realiza tiene la información necesaria y es razonable que se encargue de esa tarea.

Por ejemplo, en un sistema de pedidos:

  • La pantalla puede capturar los datos ingresados por el usuario.
  • El módulo de pedidos puede validar reglas de negocio del pedido.
  • El módulo de pagos puede comunicarse con la pasarela de pagos.
  • El módulo de notificaciones puede enviar correos o mensajes.
  • El módulo de auditoría puede registrar acciones importantes.

Si una pantalla calcula reglas de negocio complejas, o si el módulo de pagos conoce detalles de presentación, probablemente hay responsabilidades mezcladas.

20.6 Módulos

Un módulo es una parte del sistema que agrupa responsabilidades relacionadas. Puede ser un paquete, componente, servicio, capa, biblioteca, clase o conjunto de archivos, según la tecnología y la arquitectura.

La modularidad busca dividir el sistema para que cada parte tenga un propósito claro. Esto ayuda a:

  • Comprender el sistema por partes.
  • Reducir dependencias innecesarias.
  • Facilitar pruebas.
  • Permitir trabajo en equipo.
  • Reutilizar partes cuando tiene sentido.
  • Modificar una parte con menor impacto en otras.
  • Ubicar errores más fácilmente.

20.7 Ejemplos de módulos

Los módulos pueden definirse según funcionalidades, responsabilidades técnicas o áreas del dominio.

Sistema Módulos posibles
Comercio electrónico Catálogo, carrito, pedidos, pagos, envíos, clientes, promociones.
Biblioteca Catálogo, socios, préstamos, reservas, multas, reportes.
Turnos médicos Pacientes, profesionales, agenda, reservas, notificaciones, administración.
Plataforma educativa Cursos, inscripciones, clases, evaluaciones, certificados, pagos.

No existe una división única correcta. La división debe responder al dominio, los cambios esperados, el equipo, la tecnología y los atributos de calidad.

20.8 Interfaces

Una interfaz define cómo una parte del sistema se comunica con otra. Indica qué operaciones están disponibles, qué datos se reciben, qué resultados se devuelven y qué condiciones deben cumplirse.

Una interfaz puede ser:

  • Una API entre sistemas.
  • Un conjunto de métodos públicos de una clase.
  • Un contrato entre módulos.
  • Un formulario usado por una persona.
  • Un mensaje enviado a una cola.
  • Un archivo de intercambio.

Las interfaces son importantes porque permiten que las partes colaboren sin conocer todos los detalles internos de las demás.

20.9 Contratos de una interfaz

Una interfaz funciona como un contrato. Debe dejar claro qué puede esperar quien la usa y qué debe cumplir quien la implementa.

Un buen contrato puede definir:

  • Operaciones disponibles.
  • Datos requeridos.
  • Formato de entrada y salida.
  • Validaciones importantes.
  • Errores posibles.
  • Permisos necesarios.
  • Condiciones de rendimiento o disponibilidad.
  • Versiones compatibles.

Cuando una interfaz está mal definida, los módulos quedan acoplados a supuestos informales y los cambios se vuelven riesgosos.

20.10 Separación de responsabilidades

Separar responsabilidades significa evitar que una misma parte del sistema haga demasiadas cosas diferentes. Cuando una parte concentra demasiadas responsabilidades, se vuelve difícil de entender, probar y modificar.

Ejemplo de mezcla de responsabilidades:

Una pantalla de checkout valida reglas de descuento, calcula impuestos, procesa pagos, actualiza stock, envía correos y genera facturas.

Una separación más clara podría distribuir esas tareas:

  • La interfaz captura y muestra información.
  • El módulo de pedidos coordina la operación.
  • El módulo de descuentos calcula promociones.
  • El módulo de pagos procesa el pago.
  • El módulo de stock actualiza disponibilidad.
  • El módulo de facturación genera comprobantes.
  • El módulo de notificaciones informa al cliente.

20.11 Capas

Una forma común de organizar responsabilidades es separar el sistema en capas. Cada capa tiene un propósito general y se comunica con otras mediante interfaces definidas.

Capa Responsabilidad Ejemplo
Presentación Interactuar con usuarios o sistemas externos. Pantallas, formularios, controladores o endpoints.
Aplicación Coordinar casos de uso y flujo de operaciones. Crear pedido, cancelar reserva, registrar préstamo.
Dominio Representar reglas y conceptos del negocio. Pedido, Reserva, Préstamo, políticas de descuento.
Infraestructura Resolver detalles técnicos externos. Base de datos, correo, archivos, APIs externas.

No todos los sistemas necesitan estas capas formalmente, pero la idea ayuda a evitar mezclas confusas.

20.12 Encapsulamiento

Encapsular significa ocultar detalles internos y exponer solo lo necesario mediante una interfaz. Esto permite cambiar la implementación interna sin afectar a quienes usan el módulo, siempre que el contrato se mantenga.

Ejemplo:

  • Un módulo de notificaciones expone la operación "enviar confirmación".
  • Quien lo usa no necesita saber si se envía por correo, SMS o una API externa.
  • Si luego cambia el proveedor de correo, el impacto puede quedar dentro del módulo.

El encapsulamiento reduce dependencias y protege al sistema de cambios innecesarios.

20.13 Diseño para el cambio

El software cambia. Por eso, el diseño debe considerar qué partes podrían evolucionar. No se trata de anticipar todos los futuros posibles, sino de reconocer puntos de variación razonables.

Preguntas útiles:

  • ¿Qué reglas de negocio cambian con frecuencia?
  • ¿Qué integración externa podría reemplazarse?
  • ¿Qué funcionalidad puede crecer en versiones futuras?
  • ¿Qué decisiones técnicas son difíciles de revertir?
  • ¿Qué partes deben probarse con facilidad?
  • ¿Qué módulos deberían conocer menos detalles de otros?

Diseñar para el cambio no significa crear abstracciones innecesarias. Significa ubicar responsabilidades para que los cambios esperados no rompan todo el sistema.

20.14 Ejemplo: sistema de biblioteca

En un sistema de biblioteca, podríamos identificar módulos y responsabilidades así:

Módulo Responsabilidades Interfaces posibles
Catálogo Gestionar libros, autores, categorías y ejemplares. Buscar libros, consultar disponibilidad, registrar ejemplar.
Socios Gestionar datos, estado y condiciones de socios. Consultar socio, validar si puede retirar libros.
Préstamos Registrar préstamos, devoluciones y vencimientos. Crear préstamo, registrar devolución, consultar vencidos.
Reservas Gestionar solicitudes de reserva y disponibilidad futura. Crear reserva, cancelar reserva, notificar disponibilidad.
Notificaciones Enviar avisos a socios. Enviar aviso de vencimiento o confirmación.

20.15 Ejemplo: comercio electrónico

En una tienda en línea, una compra puede involucrar varios módulos:

  • Catálogo muestra productos disponibles.
  • Carrito conserva productos seleccionados.
  • Pedidos confirma la compra y registra el estado.
  • Pagos procesa el cobro.
  • Inventario descuenta stock.
  • Facturación emite comprobantes.
  • Envíos calcula opciones de entrega.
  • Notificaciones informa al cliente.

Si estas responsabilidades están mezcladas en un único bloque, cualquier cambio será difícil. Si están separadas con interfaces claras, el sistema será más comprensible y mantenible.

20.16 Errores comunes

Al diseñar software suelen aparecer errores como:

  • Empezar a programar sin decidir responsabilidades básicas.
  • Crear módulos con nombres claros pero responsabilidades mezcladas.
  • Duplicar reglas de negocio en varias partes.
  • Hacer que la interfaz de usuario contenga lógica crítica del negocio.
  • Exponer demasiados detalles internos entre módulos.
  • Crear abstracciones antes de tener una necesidad real.
  • Diseñar pensando solo en la primera versión y no en mantenimiento.
  • No documentar interfaces importantes.

20.17 Buenas prácticas iniciales

Algunas prácticas útiles para diseñar mejor son:

  • Asignar responsabilidades de forma explícita.
  • Agrupar responsabilidades relacionadas en módulos coherentes.
  • Definir interfaces claras entre partes.
  • Evitar que una parte conozca detalles innecesarios de otra.
  • Ubicar reglas de negocio en lugares consistentes.
  • Separar presentación, aplicación, dominio e infraestructura cuando aporte claridad.
  • Diseñar pensando en pruebas y mantenimiento.
  • Revisar el diseño cuando aparecen cambios repetidos o duplicación.

20.18 Qué debes recordar de este tema

  • El diseño de software decide cómo se organizará la solución.
  • Una responsabilidad es algo que una parte del sistema debe saber, hacer o controlar.
  • Un módulo agrupa responsabilidades relacionadas.
  • Una interfaz define cómo una parte se comunica con otra.
  • Separar responsabilidades mejora comprensión, pruebas y mantenimiento.
  • El encapsulamiento permite ocultar detalles internos y reducir impacto de cambios.
  • Un buen diseño debe facilitar la evolución sin agregar complejidad innecesaria.

20.19 Conclusión

Diseñar software es organizar responsabilidades, módulos e interfaces para que el sistema pueda construirse, comprenderse y modificarse de forma razonable. Un buen diseño no se nota solo cuando el sistema funciona, sino cuando puede cambiar sin volverse inmanejable.

Para quien comienza, la idea principal es esta: el diseño convierte un problema entendido en una solución organizada, donde cada parte tiene un propósito claro y se comunica mediante acuerdos definidos.

En el próximo tema veremos principios básicos de diseño como cohesión, acoplamiento y abstracción, que ayudan a evaluar si esa organización es adecuada.