Rails sostenible (I): qué es la sostenibilidad y la arquitectura de Rails
Primera entrega de la serie Rails sostenible, un recorrido en diez posts por el libro Sustainable Web Development with Ruby on Rails, de David Bryant Copeland. Tiempo de lectura estimado: 12 minutos.
Llevaba tiempo queriendo sentarme con un libro que no fuera otro tutorial de "monta un blog en Rails en 20 minutos". Copeland propone otra cosa: no enseñarte a empezar un proyecto en Rails, sino a mantenerlo vivo durante años sin que el coste de cambiarlo se dispare. Esa palabra —sostenibilidad— es el hilo que cose todo el libro, y voy a dedicarle diez entradas porque creo que es de los pocos libros de Rails que envejecen bien.
En esta serie mezclo tres cosas: un resumen fiel de lo que dice el libro, mi propia experiencia aplicando (o sufriendo la ausencia de) estas ideas en proyectos reales, y alguna digresión cuando el tema lo pide. Empecemos por los cimientos: qué entiende Copeland por sostenibilidad y por qué la arquitectura por defecto de Rails es, a la vez, su mayor virtud y su trampa más sutil.
Qué es la sostenibilidad del software
La definición de Copeland es deliberadamente sobria. Un sistema es sostenible cuando el equipo puede seguir respondiendo a las necesidades del negocio —arreglar bugs, añadir features, adaptarse a cambios— a un ritmo más o menos constante a lo largo del tiempo. No es velocidad inicial. No es elegancia. Es que el cambio número 500 no cueste diez veces más que el cambio número 5.
Esto suena obvio hasta que recuerdas cuántos proyectos has visto donde tocar cualquier cosa daba miedo. Donde añadir un campo a un formulario implicaba rezar. La insostenibilidad no llega de golpe: se acumula como sedimento, una decisión cómoda detrás de otra, hasta que un día el equipo se pasa el 80% del tiempo peleándose con su propio código y el 20% entregando valor.
Copeland insiste en tres cualidades que hacen sostenible a un sistema:
- Que sea fácil de entender. Alguien que llega nuevo debería poder leer el código y formarse un modelo mental correcto sin arqueología.
- Que sea fácil de cambiar. Modificar un comportamiento no debería obligar a tocar quince sitios ni a entender todo el sistema.
- Que sea fácil de poner a funcionar. Un desarrollador nuevo debería tener el proyecto corriendo en su máquina en minutos, no en días.
Las tres son medibles en la práctica, y las tres se erosionan calladamente si nadie las defiende.
Carrying cost y opportunity cost
Aquí está, para mí, la idea más valiosa del primer capítulo, y la que más uso para argumentar en reuniones. Copeland toma prestado del mundo financiero dos conceptos:
- Opportunity cost (coste de oportunidad): lo que dejas de hacer por dedicarte a otra cosa. Si paso tres semanas montando un sistema de plugins que nadie ha pedido, el coste de oportunidad son las tres features que no entregué.
- Carrying cost (coste de mantenimiento o "de acarreo"): el coste continuo de mantener viva una decisión. Cada dependencia que añades, cada abstracción que introduces, cada microservicio que despliegas tiene un carrying cost: hay que actualizarlo, entenderlo, monitorizarlo y arreglarlo cuando se rompe.
El código no es un activo, es un pasivo. Cada línea que escribes es una línea que alguien tendrá que entender, mantener y, algún día, borrar.
La conclusión práctica es brutal y libera mucho: la decisión sostenible casi nunca es la más sofisticada. Es la que minimiza el carrying cost futuro. Un poco de duplicación honesta puede ser más barata de mantener que una abstracción prematura que nadie entiende seis meses después. Copeland no es dogmático con esto —no predica el "no abstraigas nunca"—, pero te obliga a preguntarte siempre: ¿cuánto me va a costar mantener esto vivo?

Las asunciones del libro
Copeland es honesto sobre el contexto en el que sus consejos tienen sentido. El libro asume que:
- El software tiene un propósito claro. No es un experimento desechable ni un prototipo de fin de semana.
- El software necesita existir durante años. Si tu proyecto va a vivir tres meses, optimizar para la sostenibilidad es tirar el dinero.
- El software va a evolucionar. Los requisitos cambiarán, porque siempre cambian.
- El equipo va a cambiar. Quien escribió el código no será necesariamente quien lo mantenga. El código tiene que sobrevivir a las personas.
Me parece importante subrayar esto porque mucha gente rechaza estos libros con un "para mi caso es overkill". Y a veces tienen razón: un script interno que usan tres personas no necesita una capa de servicios. Pero la mayoría del software profesional cumple esas cuatro asunciones, aunque al principio finjamos que no.
La arquitectura de Rails: su virtud y su trampa
Rails ganó por una razón: las convenciones. No discutes dónde va cada cosa, no configuras cuarenta archivos XML, no eliges entre quince librerías para cada tarea. Rails tiene opiniones fuertes y eso te hace productivo desde el minuto uno. Copeland lo reconoce sin complejos: para un enorme abanico de aplicaciones, Rails sigue siendo la opción más sostenible que existe.
Pero entonces hace una disección incómoda del MVC tal y como Rails lo entiende. Rails te ofrece, esencialmente, tres sitios donde poner cosas:
- Vistas: la capa de presentación (plantillas, helpers).
- Modelos: que en Rails significa, casi siempre, Active Records —objetos atados a una tabla de la base de datos.
- Todo lo demás: controladores, jobs, mailers... las clases "frontera" que conectan Rails con el mundo.
¿Y dónde va la lógica de negocio? Esa es la pregunta del millón, y la respuesta por defecto de Rails es: en ninguna parte concreta. No hay una carpeta app/business_logic. No hay una convención. Así que la lógica de negocio, que es lo que de verdad hace especial a tu aplicación, acaba derramándose en los dos únicos sitios disponibles: los modelos y los controladores.
David Heinemeier Hansson, creador de Ruby on Rails. Foto: CC BY 2.0, Wikimedia Commons.
Por qué eso es un problema
Cuando metes la lógica de negocio dentro de los Active Records pasa algo predecible y dañino. Los modelos son clases muy usadas: el User, el Order, el Product los referencia medio sistema. Y son clases con mucho churn (rotación): cambian constantemente porque el negocio cambia constantemente.
Junta las dos cosas —clases críticas, muy referenciadas, que además cambian a todas horas— y tienes la receta perfecta de la insostenibilidad: un bug en User salpica a media aplicación, y cada nueva regla de negocio engorda una clase que ya pesaba 800 líneas. El famoso fat model no es una virtud, es deuda disfrazada de buena práctica.
Copeland no propone tirar Rails por la ventana ni montar una arquitectura hexagonal con cuatro capas de indirección (eso tendría su propio carrying cost). Propone un ajuste quirúrgico, que será el corazón de toda la serie: darle a la lógica de negocio su propia casa, fuera de los Active Records, en una capa de servicios explícita. Lo veremos en detalle en la tercera entrega.
Mi versión
He vivido las dos caras de esto. En proyectos donde la lógica de negocio vivía dentro de los modelos, el síntoma siempre era el mismo: nadie se atrevía a tocar el modelo User sin convocar una reunión. La clase tenía callbacks que disparaban emails, validaciones que dependían del contexto, métodos de cálculo de precios y hasta lógica de permisos. Tocar una cosa rompía otra a tres saltos de distancia.
Lo de carrying cost me lo he tatuado mentalmente. Cada vez que alguien propone "y montamos esto con una cola de mensajes y dos microservicios", la pregunta no es si se puede —casi todo se puede—, sino quién lo va a mantener despierto a las tres de la mañana dentro de dos años. La mayoría de las veces, la respuesta sensata es un monolito Rails aburrido y bien organizado. Copeland me dio el vocabulario para defender esa postura sin sonar a vago.
Y sobre las asunciones: he aprendido a preguntarlas explícitamente al empezar. "¿Esto va a vivir años o es un experimento?" cambia por completo cuánto esfuerzo merece la pena invertir en estructura. No hay una respuesta universal; hay una respuesta correcta para tu contexto.
Lo que viene
Hemos puesto los cimientos conceptuales: sostenibilidad como capacidad de cambiar a coste constante, el carrying cost como brújula para decidir, y el diagnóstico de que la arquitectura de Rails, siendo magnífica, deja a la lógica de negocio sin hogar.
En el próximo post bajamos al barro práctico: cómo arrancar una app Rails "con buen pie", con un entorno de desarrollo reproducible —bin/setup, bin/run, bin/ci—, configuración por variables de entorno y logging de producción decente desde el día uno. Porque la sostenibilidad empieza, literalmente, por que alguien nuevo pueda clonar el repo y tenerlo funcionando en cinco minutos.