Puede que en la industria del desarrollo e ingeniería del software, algunos de los conceptos peor tratados (y peor entendidos), sean los de la arquitectura de un proyecto y el papel de un arquitecto software. En esos campos reina la confusión, las concepciones contrarias y una visión, me temo, poco práctica.

Es más, el mismo concepto de arquitectura software es dado a muchas interpretaciones (tantas como la misma evolución de cómo se afrontan proyectos durante las últimas décadas, me atrevería a decir), viniendo a crear aún más debate y falta de consenso claro la poca literatura que existe al respecto y que se centra más en patrones de arquitectura que en el papel real de un arquitecto dentro de una organización, cuando el trabajo de un reputado autor se contradice con el de otro igualmente alabado.

Para empeorarlo más, también se cree ingenuamente (formentado por la errónea cultura de muchas organizaciones), que ser arquitecto software supone un paso adelante en la escalera corporativa (más prestigio, mejor salario, etc.), de ahí el rechazo visceral de muchos desarrolladores a aceptar que venga alguien con un papel así cuando se entiende como una jerarquía tan pronto como perciben que su trabajo estará más o menos condicionado, definido y encorsetado desde la torre de marfil de un arquitecto.

Pero no tiene por qué ser así.

En El Libro Negro del Programador, dedico un capítulo ligero a este asunto sin profundizar (de título "El Mal Entendido Rol de Arquitecto de Software"), sin entrar demasiado en detalles, claro está, porque para mi mala suerte, una parte importante de mi experiencia con arquitectos ha sido más bien un desastre, y no lo digo con ánimo negativo o de devolver ningún agravio, cuando yo mismo he asumido ese papel en los últimos años en los productos que he dirigido y proyectos en los que he estado al frente.

Es un tema, digamos, delicado y controvertido, puesto que no existe una definición formal (te animo a que la busques, pronto te darás cuenta de que hay tantas como opiniones personales). Tanto es así, que en diferentes organizaciones nos podemos encontrar ese rol, pero con responsabilidades totalmente diferentes, cuando no ciertos equipos que se autodenominan ágiles creen que no hace falta cierta visión de arquitectura de los productos y proyectos que diseñan, o bien te encuentras al desarrollador al que han ascendido y por esa razón cree que sus decisiones van a ser mejores que la de sus antiguos compañeros de departamento (vamos, que se le ha subido el tema a la cabeza, quizá porque suena mejor decir que "eres arquitecto" a "soy programador").

Por otra parte, siento decir que se puede ser ágil, y al mismo tiempo, necesitar una arquitectura definida, y no es una contradicción (al menos en los términos que voy a indicar a continuación).

Para enredar más el asunto, antiguas prácticas sobre cómo a afrontaba el desarrollo de software hace unas décadas, siguen persistiendo en el inconsciente colectivo de los denominados arquitectos, me temo. Para muchos, todo lo que habla de arquitectura tiene que estar relacionado con diagramas UML tan espesos como inútiles que poco aclaran y estructuras en las que necesariamente todo el desarrollo debe encajar necesariamente (tan solo recuerdos de dinosaurio sobre cómo se afrontaba el desarrollo de software hace mucho tiempo pero que aún perduran), siendo más un obstáculo que un inconveniente. En otros equipos (lo digo porque me los he cruzado en algún momento de mi carrera profesional), sencillamente ignoran que exista tan siquiera ese concepto: el software de desarrolla de forma monolítica y se despliega como sea y punto (puff...), cuando no se confunde el diseño con la arquitectura, algo también muy habitual.

Puede que precisamente por todo lo anterior, no haya escrito hasta ahora demasiado sobre esto (ni me haya mojado en el asunto, para ser sincero), por suponer un concepto muy dado a la malinterpretación e incluso susceptible de acumular poder en ciertos entornos corporativos; no obstante, voy a hacer a continuación algunas aclaraciones que confío que ayuden un poco a tener una idea más clara de lo que para mí es un arquitecto software y que, afortunadamente, he visto confirmados en autores seguramente con más experiencia que yo (como Simon Brown y George Fairbanks).

El arquitecto software no es un puesto, sino un rol.

Llevo muchos años diriendo equipos de desarrollo, y siempre les digo lo mismo a mis compañeros: no soy el jefe de nadie, tan solo tengo el rol que me corresponde y mi trabajo consiste en ayudar a que el suyo lo hagan lo mejor posible. Del mismo modo, un arquitecto software no se puede parapetar tras un cargo, sino que asume un rol activo con determinadas funciones y responsabilidades. Tanto es así, que no es mejor profesional por tener ese rol que un desarrollador. Otra cosa es cómo se valore dentro de una compañía, pero en mi opinión lo único cuantificable económicamente debe ser la experiencia y el valor de lo que se aporta.

Un buen arquitecto no vive en su torre de marfil, sino que también programa.

El desarrollo de software no es como otras profesiones; no podemos seguir el símil de arquitecto de edificios / aparejador / albañil, etc., puesto que un arquitecto puede no haber tocado un ladrillo en su vida. No obstante, en software, un arquitecto debe haber desarrollado mucho software a lo largo de su carrera, y, además, en cuantos más proyectos diferentes se haya involucrado, mejor aún.

Es más, abandonar tu papel como desarrollador y dedicarse solo a la arquitectura, lo hace alejarse seguramente de ahí donde es bueno, de modo que para mí un buen arquitecto debe seguir implicado necesariamente a nivel de código en el proyecto.

El arquitecto conoce perfectamente el dominio.

El arquitecto debe conocer perfectamente lo que el cliente necesita o el universo del negocio que se va a modelar con el sistema que se pretende construir, ¿de qué modo si no se van a tomar las decisiones de arquitectura más relevantes?

Gestión de riesgos: no siempre hace falta una arquitectura.

La regla es sencilla: cuanto más grande va a ser un proyecto software y más largo su ciclo de vida (años), más necesario es la perspectiva de la arquitectura que se va a seguir.

Un proyecto pequeño no necesita el papel de un arquitecto.

Esto es, hay una relación directa entre la gestión del riesgo, tamaño del proyecto y su proyección a largo plazo.

Se confunde arquitectura de despliegue IT con la arquitectura de un producto/proyecto.

En ciertos entornos, he visto cómo se confundía una cosa con la otra. La arquitectura de un sistema software no es lo mismo que la arquitectura IT de despliegue final del sistema a desarrollar, pero están relacionados, obviamente. Si sabemos que el despliegue se va a realizar en una infraestructura IT cloud, o bien en un único servidor, la arquitectura propuesta puede cambiar.

Una mala arquitectura (o ausencia de ella) puede costar mucho dinero.

Lo he visto: un sistema que tenía que evolucionar pero cuyos desarrolladores trabajaban sin ese horizonte temporal y orden que pudiese proveer una arquitectura correcta para ese proyecto. El resultado era que esa falta de perspectiva (o inexperiencia) más muchos déficits de diseño, se cubría con muchos euros en hardware.

No hay conflicto entre lo ágil y definir una arquitectura al comienzo.

Así es, léelo de nuevo por si esta afirmación a estas alturas te choca. Como siempre me digo a mí mismo, la virtud está en el término medio.

Por alguna razón, quizá por el abuso en tiempos pasados de todo lo que huela a arquitectura, a los equipos que defienden lo ágil dogmáticamente, les parece una aberración plantearla, creyendo erróneamente que ésta emergerá. No se comprende que lo que emerge es, en el mejor caso, el diseño, y que la arquitectura va mucho más allá que definir cajas, trazar líneas e interacciones entre partes funcionales del proyecto, como veremos más adelante.

Algunos puntos del movimiento ágil se han malinterpretado, me temo; desde un punto de vista del concepto de arquitectura como visión y estructura de un sistema software, lo que emerge es el diseño de los componentes o piezas de software que lo componen, no ese marco más general. De nuevo, se pierde la perspectiva cuando uno cree que un proyecto de 10 KLOCs se debe gestionar y debe crecer igual que uno de 100 KLOCs.

La arquitectura consiste también en identificar riesgos.

Un arquitecto guía, documenta, propone, ayuda al resto del equipo, etc., pero también es capaz de identificar los riesgos que pueden presentar ciertas decisiones (elección de tecnología, licencias de terceros, puntos únicos de fallo, etc.).

No es imprescindible UML para documentar una arquitectura.

Best Practices

Artículo disponible en epub y pdf:

Cómo usar repositorios de datosCómo usar repositorios de datos epub

 

 

Me llama mucho la atención cómo a lo largo de los años puedo haber trabajado en aplicaciones con .NET en C#, con javascript utilizando Angular y NodeJS, y también con PHP cuando estaba más centrado a hacer módulos en Drupal, y cómo con todos esos lenguajes con sus respectivos entornos de desarrollo se pueden aplicar las mismas buenas prácticas.

Hay veces que éstas se refieren a procedimientos de trabajo o al modo de estructurar un proyecto, otras hacen referencia a aplicar patrones de diseño e incluso antipatrones para detectar precisamente lo que no se hace bien. En otras ocasiones, son sencillamente prácticas habituales que hace la mayoría de la gente que usa una tecnología en particular (de ahí, por ejemplo, los proyectos de scaffolding).

Un buen proyecto software debe oler a buenas prácticas, de principio a fin, desde la arquitectura del mismo hasta la evolución de las funcionalidades que se le van añadiendo poco a poco.

Nada peor que una aplicación, proyecto o sistema en el que no se pueda ver claramente cómo están implementadas esas buenas prácticas.

Y es que además tienen algo en común: la mayoría de ellas son fáciles de implementar.

Y como me gusta escribir... pues voy a ir hablando de ellas, de aquellas con las que yo directamente he visto que tienen más impacto en la mejora de la calidad de un proyecto software.

Un aviso a navegantes: en muchas ocasiones los beneficios de estas recomendaciones no se ven claramente, ni siquiera en el corto plazo, y su impacto positivo a medio y largo plazo es más una cuestión sutil que sólo se aprende cuando has cometido todos los errores posibles y entonces se hace la luz y dices algo como, "ahora sí que lo entiendo".

Para mí la implementación de repositorios de datos es una de las prácticas más útiles en cualquier proyecto software.

El principio general de implementar un repositorio de datos vendría a ser el siguiente:

Todos los accesos a los datos que utiliza una aplicación (vengan de bases de datos, entidades de datos del mundo cloud, datos en caché, etc.) deben realizarse desde un único punto.

Dependiendo de la tecnología y del tipo de aplicación que se esté desarrollando, ese único punto se entiende por un módulo con sus clases, una librería, una API, un servicio REST, etc. Lo importante es que todos esos accesos estén centralizados y bien localizados en el proyecto.

¿Qué beneficios se obtiene de esto? Son muchos, muchísimos, algunos de ellos no fáciles de ver en un principio.

Por resumir, centralizando el acceso a los datos conseguimos:

  • Cumplimos con el principio SoC, (separation of concerns separación se intereses), básico en el desarrollo ágil. De este modo tenemos una parte muy concreta y localizada del proyecto especializada en acceder a los datos que utiliza.
  • Se evitan duplicar código repitiendo los mismos accesos a los mismos datos a lo largo de la solución. En lugar de ejecutar algo como un "select * from dbo.users where userId = 20" cada vez que se necesita la información de un usuario, tenemos algo mucho más general como "data.getUserById(20)" (esto es un sencillo ejemplo en pseudocódigo, eh!).
  • Se simplifica la solución y se reduce el número de líneas de código. Al estar encapsulado el acceso a los datos en métodos muy concretos, no necesitamos ensuciar u ofuscar la lógica de negocio de la aplicación con detalles de acceso a los datos (tales como abrir una conexión a la base de datos, cerrarla, etc.), y ni hablar cuando esos accesos con más complejos y necesitamos transacciones o joins anidados.
  • Es más fácil ejecutar un análisis sencillo de profiling: tan sólo repasando en el objeto repositorio a qué datos se accede y cómo, podemos determinar qué índices hacen falta, en el caso de bases de datos relacionales e implementar tests de rendimiento que se puedan ejecutar continuamente.
  • Conseguimos desacoplar la solución de cómo ésta accede a los datos. ¿Y si mañana cambiamos de motor de base de datos? ¿Y si por escalabilidad se decide distribuir los datos en diversas bases de datos incluso con diversas tecnologías? Nada peor que empañar todas las partes de la solución con los detalles de acceso a los datos. Puesto que todo está encapsulado en el repositorio, tan sólo hay que tocar éste. El resto de la aplicación, ni se entera del cambio.
  • Con la implementación del repositorio, al estar éste desacoplado, se pueden crear tests específicos, unitarios y de rendimiento.
  • Es trivial también crear mocks. ¿Qué pasará cuando la tabla "usuarios" tenga cien mil registros? ¿Aguantará el front-end? Con un repositorio de datos es fácil simular diversas situaciones en previsión de problemas de escalabilidad pero sobre todo, que esas situaciones pueden estar respaldadas por pruebas.
  • Al estar todos los accesos centralizados, es más fácil para la persona encargada del desarrollo de la base de datos y su acceso trabajar en esa área especializada.
  • Al no estar dispersos por la solución todos los accesos al repositorio de datos, las migraciones del mismo no terminan en pesadilla...

Hace un tiempo se hablaba en ciertas tecnologías de la capa DAL (data access layer), que vendría a ser el mismo concepto pero más ligado a bases de datos relacionales.

Si se utiliza algún tipo de ORM que crea objetos alrededor de las entidades de datos, ¿deberían esos objetos viajar a lo largo de la lógica de negocio? Esta pregunta me la encuentro recurrentemente, y mi opinión es que no, puesto que de ese modo la aplicacíon tiene una dependencia clara de la tecnología ORM utilizada. Los objetos que se deberían distribuir a lo largo de la lógica de negocio serán similares pero no ligados a la tecnología ORM usada (son los que se llaman los data transfers objects o DTOs).

A ver, al final hay que aplicar el sentido común (con un poco de experiencia y hasta de suerte...): si trabajamos en un proyecto cuyo ciclo de vida es muy claro y sabemos que se terminará y que no va a evolucionar, pues nos podemos tomar cierto tipo de licencias, pero si tenemos entre manos un producto o proyecto que crecerá y evolucionará en funcionalidad a lo largo de muchos años, entonces sí hay que cuidar mucho este tipo de decisiones y dependencias, así como aplicar con mayor rigor aún todas las buenas prácticas posibles.

Sí, ya sé, es que a veces no hay tiempo, el proyecto viene muy cerrado en horas, etc. De acuerdo, razón de más para aplicar este tipo de buenas prácticas desde el principio, porque sólo así se podrá avanzar en el proyecto con productividad y mayor rapidez.

Todo esto es más fácil de implementar que de describir; sin embargo, un buen proyecto software que necesita de cualquier mecanismo para persistir datos, tiene que acceder a ellos a través de un objeto / módulo / librería que implemente esta buena práctica.

Algunos enlaces de interés:

The Repository Pattern

Repository Pattern Done Right

Desde hace unos años participo en cierta medida en asuntos comerciales además de mi dedicación casi completa a dirigir un equipo de desarrollo, involucrándome, cómo no, en todo tipo de tareas técnicas, decisiones de diseño y arquitectura, toma de feedback de clientes, etc.

En este tiempo me ha llamado mucho la atención cómo bastantes clientes pontenciales de los productos que comercializamos se interesan por conocer el motor de base de datos que usa nuestro software. Los hay quienes le dan todas las bendiciones a SQL Server, otros que no cambiarían Oracle por SQL Server y unos pocos que nos han preguntado si el sistema podría funcionar con Cassandra (...). Nada que objetar, salvo su percepción completamente errónea de que el producto va a ser rápido y eficiente o lento y poco escalable según la base de datos que use, nada más.

Esta suposición, entendible para cierto perfil no técnico, la he visto también en otro tipo de perfiles muy técnicos y entendidos en software, para mi asombro.

La escalabilidad de un producto software no depende necesariamente de la base de datos que use, ni mucho menos: ésta es un elemento más de la larga lista de características que se le deben exigir a un producto software escalable.

No sólo he tenido que sufrir este tipo de polémicas en el eterno debate que si SQL Server  / Oracle, sino que además, todo lo que huela ahora mismo a volúmenes grandes de información rápidamente se asocia a la necesidad de una solución big data con Hadoop o MongoDB, confundiendo necesidades de almacenamiento con necesidades de análisis y procesamiento de la información.

Pero, ¿qué entendemos por escalabilidad? Esto va a depender el tipo de productos del que estemos hablando: para un portal web es sin duda el soportar un número alto de usuarios simultáneos, para una aplicación de análisis de datos, el poder captar y procesar cierto volumen de información; para un sistema de gestión de dispositivos físicos, como contadores digitales, por citar algo más ligado a mi actividad, no es lo mismo gestionar mil que cien mil dispostivos en un mismo sistema, con cinco o con cien operadores simultáneos.

Si un producto software usa una base de datos, de cualquier tipo que sea esta (relacional, no-sql, documental, etc), ésta por sí misma no va determinar el rendimiento del producto.

Esto que parece una perogrullada lo he tenido que explicar más de una vez a personas que se dedican a desarrollar software...

¿Qué determina un buen uso de una base de datos?

Este es un tema extraordinariamente amplio, pero para dar una idea de que el buen uso de una base de datos no es del todo trivial, podemos decir que no puede haber deficiencias en el diseño, sin redundancias innecesarias, las consultas a la base de datos deben ser sencillas y eficientes, se debe minimizar el número de consultas, cada consulta debe traerse la información estrictamente necesaria, las transacciones se deben dejar para las operaciones imprescindibles, debe hacerse un estudio concienzudo de los índices necesarios según la naturaleza de las consultas a realizar, según los casos habría que optar por las estructuras eficientes que ofreza el mismo gestor de bases de datos (particionado horizontal y vertical, por ejemplo), no mezclar una base de datos pensada para almacenamiento histórico con la base de datos de trabajo, dejar, si se puede según la idiosincrasia del producto, los procesamientos masivos de información para momentos que no interfieran en las ventanas de operación de los usurios clientes, y un largo etcétera .

Si este tipo de cosas no están bien resueltas, de nada nos servirá el mejor motor de base de datos.

En mi experiencia he visto claramente cómo la forma de almacenar la información determina lo sencillo o complejo que puede ser gestionarla por el software cliente de alto nivel. En ocasiones no falla cómo accedemos a la información, sino cómo esta información se encuentra almacenada en el repositorio de datos.

La forma en que necesitamos la información y cómo ésta se encuentra almacenada van de la mano.

Podemos incidir y hacer un buen trabajo a ese nivel mejorando el modo con el que nuestra aplicación accede a la base de datos, pero me temo que no queda la cosa resuelta del todo.

¿Qué ocurre con la arquitectura del propio sistema?

En cierto sentido, esta arquitectura va emergiendo a medida que intentamos que admita más y más dispositivos, usuarios o las entidades que representen la escalabilidad para nuestro producto.

Sin embargo, cuando hablamos de sistemas con grandes volumenes de procesamiento de información, tareas, procesos, etc. la arquitectura del sistema software es fundamental. Aquí ya hablamos de desarrollar software a otro nivel, con otro tipo de estrategias de diseño y desacoplamiento entre subsistemas para que cada uno haga su tarea de manera muy eficiente.

No hay estrategias generales que resuelvan cada caso concreto, pero sí buenas prácticas arquitecturales.

El poder distribuir estos subsistemas entre servidores distintos es todo un reto también de diseño para que todas las instancias puedan realizar su trabajo concurrentemente balanceando el trabajo, tanto si nos apoyamos en terceros sistemas para este propósito como si no.

Una aplicación que funciona bien para diez usuarios concurrentes no tiene nada que ver en diseño, arquitectura y diseño de repositorios de datos para la misma aplicación que tenga que dar servicio a 10k usuarios, por poner un ejemplo. La arquitectura no tendrá nada que ver, el diseño general y los microdiseños serán muy diferentes de un sistema a otro y el diseño y uso de la base de datos también serán extraordinariamente distintos.

La cuestión es que pocas veces comenzamos a desarrollar un nuevo producto sabiendo a ciencia cierta lo escalable que tiene que llegar a ser y en qué momento de su tiempo de vida deberá admitir más usuarios, dispositivos, etc. Hace falta mucha experiencia para prever esta arquitectura y los diseños adecuados. ¿Y entonces?

No existen soluciones mágicas para casi nada, pero lo que sí puedo asegurar es que si se comienza haciendo diseños limpios, con mucho esfuerzo en generar código desacoplado y de calidad, con una batería de pruebas suficientemente amplia, exhaustiva y mantenible, si nos esforzamos en cada fase del desarrollo del producto en identificar qué partes presentan cuellos de botella mediante análisis de rendimiento, etc. podremos tener un sistema para el que poder escalarlo no se convierta en algo dramático.

En ciertos sistemas complejos y más o menos grandes, todo, absolutamente todo cuenta: una iteración simple entre los elementos de una lista parece algo inocuo, pero cuando se ejecuta en un servidor cientos de miles de veces en un día, puede presentar un problema de rendimiento cuyo efecto se acumula desastrosamente a otros, presentando finalmente un problema global de rendimiento. Los detalles sí que importan.

Escribir código que funcione es nuestro trabajo, también es escribirlo de manera que funcione y que sea lo más limpio y simple posible, pero también que esa eficiente, lo que ya no es tan trivial en algunas ocasiones.

De hecho, existen libros dedicados a este asunto, como uno al que recurro habitualmente: Pro .NET Performance, por poner un ejemplo.

Otro recurso que uso confrecuencia (ligado a las tecnologías que más uso), es Improving :NET Application Performance And Scalability.

Por último, nada peor que encontrar problemas de rendimiento cuando el producto ya está en producción, si eso ocurre es que no se ha hecho un trabajo del todo bueno probando el sistema con anterioridad. No sólo hay que realizar tests unitarios, de validación e integración, también de rendimiento.

Así las cosas, cada vez que un cliente potencial con el que seguramente tenga media hora sólo para hablar, me pregunta qué base de datos usa el sistema, comprenderéis lo complicado que a veces resulta defender una respuesta cuando el cliente está más predispuesto hacia otro tipo de gestor de bases de datos que la que usamos.

Mis libros en todas las tiendas:

Amazon
Google Play
Apple
Kobo
Barnes and Noble
Scribd
Smashwords
Payhip
Gumroad

Rafael Gómez Blanes Rafael Gómez Blanes
¿Hablamos?

 

Trabajo en...

Archivo

Mis novelas...