Introducción al desarrollo web¶
Evolución de la arquitectura de software y la web¶
Cuando abrimos un navegador y escribimos una dirección, ocurre en menos de un segundo algo que tardó casi un siglo en construirse. Detrás de esa acción cotidiana hay una máquina imaginada en los años treinta, un módem de 1958, una red militar de 1969, un protocolo escrito en 1989 y una acumulación de decisiones de diseño que hoy damos por evidentes. Nada de eso era obvio en su momento.
Esta sección recorre esa línea de tiempo. No es un anexo cultural ni una curiosidad: es la explicación de por qué el software se construye como se construye. Cada arquitectura que veremos en el curso —el modelo en capas de Spring Boot, los servicios REST, los componentes de Angular, los contenedores de Docker— es la respuesta a un problema concreto que alguien enfrentó antes. Conocer el problema hace que la solución deje de ser una convención arbitraria y pase a ser una decisión comprensible.
A lo largo del recorrido aparecerá una y otra vez la misma idea, formulada de maneras distintas en cada época:
Idea transversal
Separar responsabilidades reduce el impacto del cambio.
Esa frase resume el hipertexto, el modelo cliente–servidor, la arquitectura por capas, los componentes, los servicios, los microservicios, el patrón MVC y la inyección de dependencias. Cambian el nombre, la escala y la tecnología; el principio es el mismo.
Cada tema cierra con una pregunta de reflexión. No buscan una respuesta única ni memorizable: sirven para detenerse un momento y entender qué estaba en juego cuando apareció cada solución. Vale la pena intentar responderlas antes de seguir leyendo.
📎 Material de apoyo: IntroduccionDesarrolloWeb.pptx
1. Memex: navegación no lineal del conocimiento (1930s–1945)¶
La historia no empieza con una computadora, sino con un problema de biblioteca.
A finales de los años treinta, Vannevar Bush —ingeniero, director de la Oficina de Investigación y Desarrollo Científico de Estados Unidos durante la Segunda Guerra Mundial— observó algo que hoy nos resulta familiar: la producción científica crecía mucho más rápido que la capacidad humana de consultarla. Había más conocimiento disponible del que cualquier investigador podía encontrar. El problema no era la escasez de información, sino la imposibilidad de recuperarla.
En 1945 publicó ese diagnóstico y su propuesta en el ensayo "As We May Think", aparecido en The Atlantic Monthly. Allí describió el Memex: un escritorio con pantallas, microfilmes y un mecanismo que permitiría a una persona almacenar todos sus libros, documentos y notas, y —esto es lo decisivo— recorrerlos mediante asociaciones.
Bush señalaba que los sistemas de clasificación de la época obligaban a buscar por índices alfabéticos o jerarquías rígidas: un documento vivía en una sola gaveta, bajo una sola categoría. La mente, en cambio, no funciona así. Salta de una idea a otra por afinidad, por contraste, por recuerdo. El Memex debía imitar ese comportamiento permitiendo crear rutas de lectura que enlazaran documentos entre sí, guardarlas y compartirlas con otros.
Ahí está la idea que nos importa: la navegación no lineal del conocimiento. El texto deja de tener un único orden correcto. El lector no recibe una secuencia impuesta, sino que construye su propia ruta al decidir qué enlace seguir.
El Memex nunca se construyó —la tecnología de microfilm no daba para tanto—, pero el ensayo circuló ampliamente. Veinte años después, en 1965, Ted Nelson acuñó la palabra hipertexto para nombrar exactamente esa idea, y en 1968 Douglas Engelbart la demostró funcionando en un sistema real. Cuando en 1989 se diseñe la World Wide Web, el enlace será su pieza central. Todo eso nace de un artículo escrito para explicar por qué era tan difícil encontrar un paper.
Pregunta de reflexión
¿Qué cambia cuando la información se organiza por asociaciones y no por una secuencia fija?
2. Mirar, seleccionar, conectar (1954–1994)¶
Aquí conviene hacer una pausa, porque la no linealidad no es un invento de la informática. Cuando Bush escribía sobre rutas de lectura, la literatura y el cine llevaban tiempo explorando el mismo terreno: qué pasa con una historia cuando el orden deja de estar fijo.
Dos obras separadas por cuarenta años permiten ver el mecanismo con claridad.
La ventana indiscreta · Alfred Hitchcock, 1954¶
Un fotógrafo con una pierna enyesada pasa sus días mirando por la ventana el patio interior de su edificio. No puede moverse. Solo puede observar.
La película mantiene una cronología principalmente lineal —los días transcurren en orden—, pero organiza la experiencia de forma espacial y fragmentaria. En cada ventana del edificio de enfrente ocurre una microhistoria distinta, y todas suceden al mismo tiempo. La cámara no puede contarlas todas; el espectador tampoco puede mirarlas todas.
Lo interesante es lo que eso obliga a hacer. El protagonista —y con él quien mira la película— selecciona indicios en distintas ventanas y construye conexiones entre ellos. La sospecha del crimen no está en ninguna escena aislada: está en la relación que el observador establece entre fragmentos que, por separado, no significan nada.
"Bart of Darkness" · Los Simpson, 1994¶
Cuarenta años después, un capítulo de Los Simpson repite la estructura pieza por pieza: Bart se rompe una pierna, queda inmovilizado en su cuarto con un telescopio, observa a los vecinos, interpreta fragmentos y sospecha un crimen.
La parodia conserva el dispositivo y cambia el tono. Y ese es justamente su valor para nosotros: la repetición permite reconocer cómo una forma narrativa viaja entre obras, se vuelve reconocible y funciona como un lenguaje compartido. Quien nunca vio la película de Hitchcock entiende el capítulo; quien la vio, entiende además el guiño. La misma estructura sostiene dos lecturas distintas.
En ambos casos el recorrido de la lectura es idéntico:
Un lector de la web hace exactamente eso. Llega a una página, recoge fragmentos, sigue enlaces, descarta rutas y arma un sentido que ningún autor escribió completo.
No linealidad, con matiz
Conviene ser precisos: no se trata de una ruptura radical del tiempo narrativo, como sí ocurre en obras que desordenan la cronología. Es una lectura no lineal del espacio y de la información. El tiempo avanza; lo que está fragmentado es el campo de lo observable.
Pregunta de reflexión
¿El relato está en lo que ocurre frente a las ventanas o en las conexiones que construye quien mira?
3. El dispositivo de la mirada¶
Vale la pena detenerse en la ventana misma, porque es una metáfora sorprendentemente exacta de lo que hacemos al diseñar software.
Una ventana organiza la atención: limita, selecciona y conecta. Recorta un fragmento del mundo y lo presenta como si fuera la totalidad de lo relevante. Y aquí está la parte que suele pasarse por alto: la ventana no solo muestra, también oculta. Precisamente esa restricción es la que vuelve activa la mirada del espectador. Si viéramos todo, no habría nada que inferir; el suspenso vive en lo que queda fuera del encuadre.
Observar, entonces, nunca es un acto pasivo. Es un proceso en tres momentos:
Es exactamente el problema que resuelve una interfaz. Un sistema real tiene decenas de entidades, cientos de campos y miles de registros: un espacio con múltiples focos. La interfaz decide qué se ve primero, qué queda a un clic de distancia y qué permanece oculto. Cuando en el proyecto tengamos que diseñar la pantalla del visor de procesos, la pregunta no será "cómo muestro todo", sino qué merece estar en el encuadre.
La parodia agrega una lección más: conserva el mecanismo y cambia el tono, y el reconocimiento depende de que el público conecte la nueva escena con la obra anterior. En software ocurre lo mismo con las convenciones de interfaz. Un ícono de engranaje significa "configuración" porque todos hemos visto ese ícono antes. Diseñar es, en buena medida, apoyarse en lo que el usuario ya sabe leer.
Pregunta de reflexión
¿Qué información deja fuera del relato el encuadre y cómo esa ausencia produce suspenso?
4. Actividad: diseñar una narrativa sin una sola ruta¶
En parejas · 12 minutos
Objetivo: experimentar cómo el orden o la bifurcación modifican la construcción de sentido.
Antes de programar una sola línea, vamos a diseñar una estructura no lineal a mano. Cada pareja escoge una de las dos tarjetas. Ambas parten de referentes literarios que se anticiparon décadas al hipertexto: Rayuela de Julio Cortázar (1963), una novela que propone al lector dos órdenes de lectura posibles, y El jardín de senderos que se bifurcan de Jorge Luis Borges (1941), donde un relato imagina un tiempo en el que todos los desenlaces coexisten.
| Tarjeta A · Opción Rayuela | Tarjeta B · Opción Borges | |
|---|---|---|
| Enfoque | Orden elegido | Tiempo bifurcado |
| Instrucción | Inventen una historia de 6 escenas. Escriban dos recorridos distintos con las mismas escenas: uno lineal y otro reordenado. | Partan de una decisión y dibujen un mapa con 3 bifurcaciones. Imaginen que varios desenlaces pueden coexistir. |
| Pregunta guía | ¿Qué cambia en la interpretación al cambiar el orden? | ¿Cómo cambia el relato si ninguna posibilidad elimina a las demás? |
- Entregable: mapa de la estructura + justificación de 3 frases.
- Puesta en común: 1 minuto por pareja.
Al terminar, conviene notar algo: el mapa que acaban de dibujar es, estructuralmente, un grafo de navegación. Los nodos son escenas y las aristas son enlaces. Es el mismo diagrama que dibujaremos más adelante cuando definamos las rutas de la aplicación en Angular.
Pregunta de cierre
¿Quién controla el sentido final: quien diseña las rutas o quien las recorre?
5. El primer módem comercial (1958)¶
Volvamos a las máquinas. En los años cincuenta, una computadora era un objeto radicalmente solitario: ocupaba una sala entera, costaba una fortuna y no tenía forma de hablar con ninguna otra. Los datos se movían físicamente, en cintas o tarjetas perforadas que alguien transportaba de un edificio a otro.
El problema era que ya existía una red que conectaba prácticamente todo el país —la red telefónica—, pero estaba diseñada para transportar voz, es decir, señales analógicas continuas. Una computadora, en cambio, habla en pulsos discretos de ceros y unos. Ambos mundos eran incompatibles.
En 1958, AT&T presentó el Bell 101 Data Set, el primer módem comercial para computadoras. Su función era resolver esa incompatibilidad, y su propio nombre lo explica:
Módem = modulador–demodulador
En el extremo emisor, modula: convierte la señal digital en tonos audibles que la línea telefónica puede transportar. En el extremo receptor, demodula: reconstruye a partir de esos tonos la secuencia original de ceros y unos.
Las velocidades eran modestísimas para los estándares actuales —del orden de cien bits por segundo, lo que hoy sería insuficiente incluso para cargar el texto de esta página—, pero el salto conceptual fue enorme: la red telefónica se convirtió en un canal para comunicar computadoras. Por primera vez, dos máquinas separadas por cientos de kilómetros podían intercambiar datos sin que nadie moviera una cinta.
El principio sigue vigente. Cada vez que una petición HTTP viaja desde un navegador hasta un servidor, en algún punto del camino la información se transforma para adaptarse al medio que la transporta —fibra, cobre, radio— y se reconstruye al llegar. Cambió la tecnología; el problema de fondo es el mismo.
Antecedente teórico
El trabajo de Ralph Hartley sobre la transmisión de información, publicado en 1928, es uno de los antecedentes de la teoría de la información que sustenta estos desarrollos y que Claude Shannon formalizaría en 1948. Antes de poder transmitir información de manera confiable, hubo que responder una pregunta previa: ¿qué es, exactamente, la información, y cuánta cabe en un canal?
Pregunta de reflexión
¿Cómo se transforma una señal digital para viajar por una infraestructura analógica?
6. ARPANET conecta sus primeros nodos (1969)¶
Conectar dos computadoras ya era posible. El siguiente problema era conectar muchas, y hacerlo de manera que la red siguiera funcionando aunque algunas de sus partes fallaran.
ARPANET, financiada por ARPA (la agencia de proyectos de investigación avanzada del Departamento de Defensa de Estados Unidos), abordó ese problema con una idea que hoy sostiene a Internet entera: la conmutación de paquetes.
Hasta entonces, la comunicación funcionaba por conmutación de circuitos, el modelo de la telefonía tradicional: para hablar con alguien se establecía un camino físico dedicado que permanecía reservado durante toda la conversación, aunque nadie dijera nada. Es simple, pero frágil y derrochador. Si un tramo del circuito se cae, la comunicación se pierde por completo.
La conmutación de paquetes invierte el planteamiento. El mensaje se parte en fragmentos pequeños, cada uno con la dirección de destino, y cada fragmento viaja por su cuenta, tomando la ruta que esté disponible en ese momento. Los paquetes pueden llegar desordenados y por caminos distintos; el destinatario los reordena. Ningún camino está reservado y ninguno es imprescindible.
En 1969, ARPANET enlazó sus primeros cuatro nodos universitarios:
- UCLA — Universidad de California, Los Ángeles
- Stanford Research Institute
- UC Santa Barbara — Universidad de California, Santa Bárbara
- University of Utah
El primer mensaje enviado entre dos de esos nodos, en octubre de ese año, fue un intento de escribir la palabra LOGIN. El sistema se cayó después de las dos primeras letras. El mensaje inaugural de la red que se convertiría en Internet fue, literalmente, LO.
El salto conceptual es lo importante: de una máquina aislada a una red distribuida, en la que la información encuentra rutas alternativas si un enlace falla. Esa es la propiedad que hace que hoy podamos desplegar una aplicación en un servidor remoto y confiar en que será alcanzable desde cualquier parte.
Pregunta de reflexión
¿Por qué una red distribuida resulta más robusta que una conexión punto a punto?
7. Tiempo compartido: el precursor del cliente–servidor (1960s–1970s)¶
Mientras las redes crecían hacia afuera, dentro de cada institución había otro problema: la computadora central era carísima y una sola, y decenas de investigadores necesitaban usarla.
El modelo original era el procesamiento por lotes: cada usuario entregaba su programa en tarjetas perforadas, esperaba su turno —a veces horas, a veces días— y recibía de vuelta un listado impreso. Si había un error de sintaxis, el ciclo entero volvía a empezar. La máquina se aprovechaba bien; el tiempo de las personas, pésimamente.
Los sistemas de tiempo compartido invirtieron esa prioridad. La idea era repartir el procesador entre varios usuarios en intervalos tan breves que cada uno tuviera la ilusión de estar usando la máquina en exclusiva. Cada persona trabajaba desde una terminal —un teclado y una pantalla sin capacidad de cómputo propia— conectada a la computadora central, e interactuaba en tiempo real con sus programas.
Aquí aparece, por primera vez, la estructura que reconoceremos durante todo el curso: de un lado la interfaz con la que trabaja el usuario, del otro el procesamiento. Es el precursor directo del modelo cliente–servidor, aunque en esta etapa el "cliente" no tuviera todavía inteligencia propia.
| Avance | Límite |
|---|---|
| Acceso simultáneo de múltiples usuarios y mejor aprovechamiento de los recursos de la máquina central. | Dependencia del sistema central, con menor escalabilidad y flexibilidad. |
Con el tiempo compartido aparece también la tensión que atraviesa toda la historia de la arquitectura de software y que seguiremos encontrando hasta los microservicios: centralizar simplifica, pero concentra el riesgo. Un único punto de control es más fácil de administrar, de asegurar y de mantener coherente. También es un único punto de falla, y un techo de crecimiento: cuando la máquina central se queda corta, no hay a dónde repartir la carga.
Pregunta de reflexión
¿Qué ocurre con todo el sistema si falla el nodo central?
8. HTTP y la World Wide Web (1989)¶
Para finales de los ochenta ya existían las redes, los protocolos de transporte y millones de documentos digitales. Lo que no existía era una forma estándar y sencilla de pedir un documento a una máquina cualquiera y recibirlo. Cada sistema tenía su propio mecanismo, y consultar información ajena exigía aprender el procedimiento particular de cada servidor.
En 1989, en el CERN, Tim Berners-Lee propuso una solución que combinaba tres piezas: un lenguaje para escribir documentos con enlaces (HTML), una forma universal de nombrar recursos (la URL) y un protocolo para pedirlos y entregarlos (HTTP). El hipertexto que Bush había imaginado cuarenta y cuatro años antes se volvía, por fin, operativo y global.
HTTP define cómo se formatean y transmiten los mensajes entre un cliente y un servidor en la Web. Su enorme virtud fue la simplicidad: cualquiera podía implementarlo, y eso hizo posible que la Web creciera sin que ninguna autoridad central lo coordinara.
Funciona con un modelo de petición–respuesta de tres pasos:
- El cliente solicita. El navegador envía una petición que identifica el recurso deseado y la acción sobre él.
- El servidor procesa. Interpreta la petición, ejecuta la lógica necesaria y consulta los datos que hagan falta.
- El servidor responde. Devuelve el resultado junto con un código que indica qué ocurrió: éxito, error del cliente, error del servidor.
Hay un detalle de diseño que conviene subrayar desde ahora, porque explicará muchas decisiones más adelante: HTTP no recuerda nada entre una petición y la siguiente. Cada solicitud llega al servidor como si fuera la primera. Esa amnesia deliberada es lo que permite que un servidor atienda a millones de usuarios sin guardar el estado de cada conversación, y es también la razón por la que necesitaremos mecanismos explícitos —sesiones, tokens— cuando lleguemos al módulo de seguridad.
Este ciclo, aparentemente simple, es la base de todo lo que construiremos: cada llamada a un servicio REST desde Angular hacia Spring Boot es una petición HTTP.
Pregunta de reflexión
¿Qué información necesita una solicitud para que el servidor pueda responder?
9. CORBA e interoperabilidad (1991)¶
La Web resolvió cómo un navegador pide documentos a un servidor. Pero las empresas tenían un problema distinto y más incómodo: cómo lograr que sus aplicaciones —no sus documentos— se hablaran entre sí.
El panorama típico de una organización grande era un archipiélago. Un sistema contable escrito en COBOL sobre un mainframe, un sistema de inventario en C sobre Unix, una aplicación nueva en C++ sobre Windows. Todos manejaban información relacionada y ninguno podía invocar directamente al otro: lenguajes distintos, hardware distinto, sistemas operativos distintos. Cada integración se resolvía a mano, con archivos intermedios y procesos nocturnos, y se rompía con cualquier cambio.
CORBA (Common Object Request Broker Architecture), publicada en 1991 por el Object Management Group, estandarizó la comunicación entre objetos distribuidos en sistemas heterogéneos. Su apuesta fue introducir una capa intermedia que se encargara de toda la traducción:
Aplicación A ORB Aplicación B
(lenguaje/sistema 1) → intermediario → (lenguaje/sistema 2)
de solicitudes
(middleware)
El ORB (Object Request Broker) actúa como intermediario. Cada aplicación describe las operaciones que ofrece en un lenguaje de interfaces neutral, independiente de la tecnología con que esté implementada, y el ORB se encarga del resto: localizar el objeto remoto, traducir los datos al formato de destino, transportarlos por la red y devolver la respuesta.
El resultado es que el middleware oculta parte de la complejidad de la red. Para el programador, invocar un objeto que vive en otra máquina, escrito en otro lenguaje, se parece a llamar a un método local. Una aplicación puede invocar a otra sin conocer sus detalles de implementación ni su ubicación.
CORBA terminó siendo desplazada por alternativas más livianas —los servicios web primero, REST después—, en buena medida porque su complejidad resultó difícil de sostener. Pero la idea que introdujo no solo sobrevivió: es la base de todo lo que vino después. Cada vez que definimos un contrato de API y dejamos que cliente y servidor evolucionen por separado, estamos aplicando el principio que CORBA formuló primero.
Pregunta de reflexión
¿Qué problema resuelve una capa intermedia entre aplicaciones incompatibles?
10. Arquitectura por componentes (1990s)¶
En paralelo a la comunicación entre sistemas, había que resolver un problema de escala interna. Las aplicaciones crecían hasta volverse imposibles de mantener: bases de código donde cambiar una función rompía otras tres en lugares imprevisibles, y donde nadie se atrevía a tocar nada por miedo a lo que pudiera fallar.
La arquitectura por componentes propuso una salida: un sistema se construye a partir de módulos independientes que encapsulan funciones específicas y se conectan mediante interfaces definidas.
La palabra decisiva es encapsular. Un componente expone qué hace, no cómo lo hace. Quien lo usa depende únicamente de su interfaz —la lista de operaciones disponibles, con sus datos de entrada y salida— y no de su implementación interna. Mientras la interfaz se mantenga estable, lo que ocurre dentro del componente puede reescribirse por completo sin que nadie afuera se entere.
De ahí se desprenden sus tres propiedades centrales:
- Reutilización. Un componente bien delimitado sirve en más de un sistema, porque no arrastra suposiciones sobre el contexto en que se usa.
- Modularidad. El sistema se entiende y se prueba por partes, en lugar de tener que sostenerlo entero en la cabeza.
- Flexibilidad. Las piezas se reemplazan por otras que cumplan el mismo contrato.
El beneficio práctico se resume en una frase: cambiar una pieza sin reconstruir todo el sistema. Es exactamente lo que haremos al construir componentes de Angular y fragmentos reutilizables de Thymeleaf, y la razón por la que insistiremos tanto en que la lógica de negocio no se filtre hacia las vistas.
Pregunta de reflexión
¿Qué debe exponer un componente para integrarse sin revelar su implementación interna?
11. SOA: Arquitectura Orientada a Servicios (finales de 1990s–2000s)¶
Si un componente puede vivir dentro de una aplicación, la pregunta siguiente era inevitable: ¿por qué no puede vivir fuera de ella, y ser usado por varias?
La Arquitectura Orientada a Servicios (SOA) llevó el principio de la modularidad al plano de la organización completa. Estructura los sistemas como servicios independientes e interoperables que pueden descubrirse, combinarse y reutilizarse.
El cambio de mentalidad es más profundo de lo que parece: la capacidad se ofrece como servicio, no como aplicación monolítica. En lugar de que cada sistema implemente su propia validación de clientes, su propio cálculo de impuestos o su propia consulta de inventario, esas capacidades se publican una sola vez como servicios que cualquier aplicación autorizada puede consumir. La empresa deja de pensar en términos de aplicaciones aisladas y pasa a pensar en capacidades compartidas.
Vale la pena marcar una diferencia que suele confundirse. Una función interna vive dentro de un programa, se invoca en el mismo proceso y su contrato puede cambiar cuando el equipo lo decida. Un servicio, en cambio, es autónomo: se ejecuta por su cuenta, se invoca a través de la red mediante un protocolo estándar, y su contrato es un compromiso público con consumidores que el equipo probablemente ni conoce. Esa diferencia obliga a diseñar con mucho más cuidado la interfaz, el versionamiento y el manejo de errores.
SOA sentó las bases de las arquitecturas actuales basadas en APIs. Cuando en el proyecto publiquemos servicios REST que el frontend Angular consumirá, estaremos aplicando este enfoque en pequeño: el backend no sabrá quién lo llama, y esa ignorancia deliberada es precisamente lo que le permite servir a varios clientes distintos.
Pregunta de reflexión
¿Qué diferencia un servicio reutilizable de una función interna de una aplicación?
12. Arquitectura N-Tier (1990s)¶
Dentro de cada aplicación hacía falta también un criterio de organización. La arquitectura N-Tier propone uno muy concreto: la aplicación se divide en capas con responsabilidades específicas y dependencias controladas.
La división clásica tiene tres niveles:
- Presentación. Recibe la interacción del usuario y muestra los resultados. No decide reglas de negocio ni sabe cómo se guardan los datos.
- Lógica de negocio. Concentra las reglas del dominio: qué operaciones son válidas, qué condiciones deben cumplirse, qué significa cada concepto del problema. No sabe si la interfaz es una página web, una app móvil o una API.
- Acceso a datos. Traduce entre el modelo de la aplicación y el almacenamiento. No conoce las reglas de negocio.
La regla que hace funcionar el esquema es la de dependencias controladas: cada capa conoce únicamente a la que tiene debajo, y nunca al revés. La presentación llama a la lógica de negocio; la lógica de negocio nunca llama a la presentación.
Los beneficios que se buscan son tres: separación de responsabilidades, facilidad de mantenimiento y escalabilidad. Pero la razón de fondo, la que explica por qué este modelo sigue vigente treinta años después, es más sutil: cada capa cambia a un ritmo diferente. La interfaz se rediseña cada pocos meses porque cambian las modas visuales y las necesidades de los usuarios. Las reglas de negocio cambian cuando cambia el negocio. El modelo de datos, si se diseñó bien, apenas se toca. Separar por capas es, en el fondo, agrupar lo que cambia junto y aislarlo de lo que cambia a otro ritmo.
Esta es exactamente la estructura que aplicaremos en el proyecto con Spring Boot: controladores → servicios → repositorios. Cuando insistamos en que un controlador no debe contener lógica de negocio, o en que un repositorio no debe decidir reglas, estaremos defendiendo esta separación.
Pregunta de reflexión
¿Qué riesgo aparece cuando una capa conoce demasiados detalles de las demás?
13. Microservicios (2010s)¶
Durante los años 2010, con la consolidación de la nube y de los despliegues frecuentes, la escala volvió a cambiar. Aplicaciones enormes, mantenidas por decenas de equipos, chocaban con un límite práctico: aunque estuvieran bien organizadas en capas, seguían siendo una sola unidad de despliegue. Un cambio de una línea obligaba a desplegar el sistema completo, y cualquier equipo podía bloquear a todos los demás.
Los microservicios llevaron la separación un paso más allá: la aplicación se construye como un conjunto de servicios pequeños y autónomos, cada uno enfocado en una capacidad específica y comunicado con los demás a través de APIs. Cada servicio tiene su propio código, su propio ciclo de vida y, con frecuencia, su propia base de datos.
Las ventajas son directas:
- Despliegue independiente. Cada servicio se actualiza sin coordinar una liberación general.
- Escalado selectivo. Si el módulo de reportes es el que recibe carga, se replica solo ese, en lugar de duplicar la aplicación entera.
- Equipos autónomos. Cada equipo es dueño de sus servicios y puede avanzar a su propio ritmo.
El costo de la autonomía
Más autonomía implica también más coordinación distribuida. Lo que antes era una llamada a un método dentro del mismo proceso ahora es una llamada por red que puede fallar, demorarse o responder a medias. Aparecen problemas que simplemente no existían: latencia, consistencia de datos entre servicios, trazabilidad de una operación que atraviesa cinco sistemas, y una infraestructura de despliegue y monitoreo mucho más compleja.
Por eso la pregunta relevante nunca es "¿son mejores los microservicios?", sino ¿este sistema, con este tamaño y este equipo, justifica el costo de distribuirlo?. Para el proyecto del curso la respuesta es claramente que no: una aplicación bien estructurada en capas es la decisión correcta. Pero conviene entender el razonamiento, porque es el mismo tipo de análisis que se hace en la industria.
Pregunta de reflexión
¿Cuándo vale la pena distribuir una aplicación y cuándo añade complejidad innecesaria?
14. MVC: separar responsabilidades¶
Hasta aquí hemos hablado de separar sistemas, servicios y capas. MVC aplica la misma idea a la escala más pequeña y más cotidiana: la organización interna de una aplicación.
El patrón fue formulado a finales de los setenta por Trygve Reenskaug en el entorno Smalltalk de Xerox PARC, y su objetivo era evitar un problema que sigue siendo el más común en el código de principiantes: que la interfaz, la lógica y los datos queden mezclados en el mismo lugar. Un archivo donde se consulta la base de datos, se calculan reglas de negocio y se arma el HTML es fácil de escribir y muy difícil de cambiar.
MVC organiza la aplicación en tres responsabilidades:
- Modelo. Representa los datos y las reglas del dominio. No sabe nada de cómo se muestran.
- Vista. Presenta la información al usuario. No decide nada; solo muestra lo que recibe.
- Controlador. Recibe la interacción del usuario, coordina al modelo y decide qué vista responde.
El flujo es circular:
Es un patrón agnóstico al lenguaje, común tanto en aplicaciones web como de escritorio, y su beneficio se nota sobre todo en dos momentos. Al cambiar: rediseñar la presentación no obliga a tocar las reglas de negocio. Y al probar: la lógica puede verificarse con pruebas automatizadas sin necesidad de abrir un navegador ni simular clics, porque no está enredada con la interfaz.
Lo aplicaremos de manera directa al trabajar con Spring MVC y Thymeleaf, donde cada pieza tiene un lugar explícito en el proyecto, y volveremos a encontrarlo —con otro nombre y otra forma— en la separación entre componentes, plantillas y servicios de Angular.
Pregunta de reflexión
¿Qué componente debería cambiar si solo cambia la forma de presentar la información?
15. Inyección de dependencias: del acoplamiento a la flexibilidad¶
Llegamos al último eslabón, y es el más pequeño de todos: ya no se trata de arquitecturas ni de sistemas, sino de cómo una clase obtiene las otras clases que necesita. Aunque parezca un detalle menor, es la diferencia entre un diseño rígido y uno flexible.
Sin inyección de dependencias, una clase crea directamente lo que necesita:
DataProcessor crea directamente XMLPersistence. El resultado es acoplamiento fuerte, y sus consecuencias son concretas: si mañana hay que guardar en una base de datos en lugar de un archivo XML, hay que modificar el código de DataProcessor, aunque su lógica no haya cambiado en absoluto. Y si queremos escribir una prueba automatizada, no hay manera de evitar que se cree un XMLPersistence real, con archivos reales, lento y frágil.
Con inyección de dependencias, la clase recibe una abstracción en lugar de construirla:
class DataProcessor {
private final Persistence persistence;
DataProcessor(Persistence persistence) {
this.persistence = persistence;
}
}
// Ejemplo de uso
DataProcessor proc = new DataProcessor(new XMLPersistence());
proc.execute();
DataProcessor ahora depende de la abstracción Persistence, no de una implementación concreta. Ya no decide cuál mecanismo de persistencia se usa; solo declara que necesita alguno. Quien lo construye es quien decide. El resultado es acoplamiento débil y sustitución sencilla.
El cambio es pequeño en código y grande en consecuencias. Cambiar de XML a base de datos ya no toca a DataProcessor. Y probarlo se vuelve trivial: basta con pasarle una implementación falsa de Persistence que guarde los datos en memoria.
A esto se le llama también inversión de control, porque se invierte quién decide: la clase deja de controlar sus propias dependencias y ese control se delega hacia afuera. En Spring, ese "afuera" es el contenedor: nosotros declaramos los componentes con anotaciones y el framework se encarga de construirlos y entregárselos a quien los necesite. Es el mecanismo que veremos desde la primera clase de Spring Boot, cuando hablemos de beans e inyección de dependencias.
Idea transversal
Separar responsabilidades reduce el impacto del cambio. Es la misma idea que ya apareció en el hipertexto (separar el contenido de su orden de lectura), en el cliente–servidor (separar la interacción del procesamiento), en la arquitectura por componentes, en N-Tier, en SOA, en los microservicios y en MVC. Cambia la escala —desde una red mundial hasta un constructor de tres líneas—; el principio no cambia.
Pregunta final
¿Qué dependencia sustituirías para probar DataProcessor sin acceder a una base de datos real?
16. Relación con el curso¶
Vale la pena cerrar volviendo al punto de partida. Las tecnologías que usaremos —Spring Boot, Thymeleaf, JPA, Angular, REST, Docker y Spring Security— no son un conjunto arbitrario de herramientas de moda: son la aplicación práctica de esta evolución. Cada una responde a un problema que alguien enfrentó antes.
| Concepto histórico | Cómo lo veremos en el curso |
|---|---|
| Hipertexto y navegación no lineal | HTML, enrutamiento y navegación entre vistas |
| Petición–respuesta HTTP | Servicios REST y su consumo desde Angular |
| Cliente–servidor | Separación entre el frontend Angular y el backend Spring Boot |
| Interoperabilidad y contratos | Documentación de la API con Swagger/OpenAPI |
| Arquitectura N-Tier | Modelo en capas: controladores, servicios y repositorios |
| MVC | Spring MVC y Thymeleaf |
| Inyección de dependencias | Beans e inyección de dependencias en Spring |
| Componentes y reutilización | Componentes de Angular y fragmentos de Thymeleaf |
| Empaquetamiento y distribución | Docker y despliegue de la aplicación |
| Seguridad en sistemas distribuidos | Autenticación y autorización con Spring Security |
Durante el semestre habrá momentos en que una convención parezca innecesaria: ¿por qué separar el DTO de la entidad?, ¿por qué el controlador no puede consultar la base de datos directamente?, ¿por qué documentar un endpoint que solo usa nuestro propio frontend?. Cuando eso ocurra, la respuesta casi siempre está en esta línea de tiempo. Alguien ya construyó el sistema sin esa separación y descubrió, unos años después, lo que costaba mantenerlo.
Comprender esta historia permite entender por qué existen estas herramientas y a qué problema responde cada una. Esa es la diferencia entre seguir un tutorial y tomar decisiones de diseño.