Tinselcity

Vale, llevamos 7 capítulos y… ¡¿ni una sola línea de código todavía?! Bueno, como ya dejamos claro, la intención es centrarnos mucho más en pensar que en escribir código. Pero es lógico suponer que el objetivo final de todo esto no puede ser solo pensar. El objetivo, por supuesto, es llegar a producir una solución. Algo que realmente resuelva el problema, no solo una idea abstracta sino su implementación.

El Primer Código

Abrimos nuestro entorno de trabajo, con nuestro editor, nuestra consola de comandos, explorador de ficheros, lo que sea que usemos. Y ahora ¿qué?

Propuestas

Existen diferentes aproximaciones y propuestas para desarrollar un proyecto. En general, la idea es seguir un determinado orden y que eso sea lo que guíe el desarrollo. Cada propuesta -más o menos- expresa en cierta medida cuál es el punto del que arranca. Veamos algunas así generales.

Empecemos por la Interfaz de Usuario

Existe quien propone, por ejemplo, UI-First development, o lo que es lo mismo: comenzar por el interfaz de usuario y que sea esto lo que defina el programa. Es una forma de desarrollo que, quizá no de forma del todo consciente, se ha hecho relativamente popular en el desarrollo web. O por lo menos en ciertos equipos y entornos de desarrollo web. Se parte de un diseño, de ahí se va sacando el HTML y CSS para implementarlo y se van descubriendo posibles servicios (locales o remotos) que es necesario desarrollar para ir implementando cada parte de la funcionalidad. Todo determinado siempre por ese diseño inicial, por lo que el usuario va a ver y manejar. No es solo aplicable a desarrollo web, por supuesto. El interfaz de usuario puede ser una página web, igual que puede ser una pantalla de una aplicación de escritorio, o la sintaxis del comando de una aplicación en línea de comandos, una pantalla táctil, o, por qué no, un panel de botones e interruptores.

Esta propuesta tiene algunas cosas positivas. Lo principal es que pone en primer plano la experiencia del usuario, hace que lo que determina cualquier parte de la aplicación, sean las acciones que el usuario va a realizar o los resultados que va a recibir. Esto, en cierta medida, ayuda a conseguir que el programa, cuando esté terminado, se adapte a las expectativas de interacción del usuario.

Sin embargo, es una propuesta arriesgada. En la mayoría de ocasiones la forma específica que tenga el interfaz de usuario puede ser bastante variable; fijar desde el comienzo lo que va a guiar todo el resto cuando puede aún cambiar mucho no parece una gran ayuda para un desarrollo ordenado. También es habitual que, buscando una interfaz sencilla y cómoda la experiencia del usuario quede bien reflejada, pero los detalles y mecanismos propios del problema original no tengan ninguna representación. Así la guía que nos puede proporcionar el interfaz es, como mínimo, limitada.

Interface-driven design

Hay una extensión, por decirlo de alguna forma, de la idea anterior. En cualquier parte o pieza de un sistema puede entenderse que tenemos un interfaz, la parte que interactúa con otras piezas del sistema, y un “mecanismo interno”, lo que sería el funcionamiento propio de esa parte que no se ve desde fuera. Partiendo de esto, la idea se extiende proponiendo que cuando comenzamos el desarrollo lo hagamos definiendo esos interfaces entre las diferentes partes. Luego, cada “parte interna” se desarrolla manteniendo esos interfaces como un contrato que debemos obedecer.

Esta es una técnica interesante, pero en realidad tiene poco que ver con el diseño general de la aplicación o con la pregunta de ¿por dónde empezamos?. Es más una técnica a aplicar a lo largo de todo el desarrollo para garantizar que todas las piezas siguen encajando unas con otras.

Empecemos por las Estructuras de Datos

Esta es casi la visión opuesta a la anterior. Propone comenzar definiendo las estructuras y tipos de datos que vamos a utilizar, dejando el comportamiento o las acciones que vayamos a realizar sobre esos datos para después. Es una técnica que está algo en desuso, sobre todo en ese sentido de arrancar el proyecto por ahí.

La ventaja principal que tiene es que nos permite identificar rápidamente los datos y las relaciones entre ellos y eso nos puede dejar ver formas de estructurarlos y gestionarlos que terminan siendo bastante eficientes en rendimiento. Esto ayuda mucho en aplicaciones que manejan volúmenes de datos muy grandes. Como desventaja, demasiadas veces el diseño de los datos termina produciendo que sea relativamente sencillo hacer operaciones sencillas, pero mucho menos acciones que son algo más complejas.

Es bastante útil para aplicaciones que encajen en esa idea. Existen bastantes así. Aplicaciones de consulta y gestión de catálogos, de clientes… En general aplicaciones con muchos formularios simples, que requieren no demasiada lógica y sí mantener la consistencia y el orden de todos los datos.

Empecemos por los Tests

Aquí la idea es que si tenemos unos requisitos muy claros y marcados, dejemos que sean estos los que guíen el desarrollo. Es decir, que comenzamos por transformar esos requisitos en una serie de contratos, cláusulas que debemos cumplir con nuestro programa, y a partir de ahí vayamos escribiendo el código que cumpla esos contratos. Generalmente los requisitos se escriben en forma de tests con herramientas que nos permiten rápidamente ejecutar el código y ver cuáles tests se están cumpliendo correctamente y cuáles no.

En general, los requisitos generales se van descomponiendo en diferentes tareas más pequeñas cada una con sus tests cada vez más específicos.

La ventaja de esta aproximación es que nos garantiza que el programa se comporta como debe. O que si no lo hace, lo detectamos inmediatamente porque nos lo indican los tests. Como herramienta, la idea de tener tests es una buena idea. Nos ayuda. Sin embargo, como aproximación general al desarrollo, tiene también bastantes limitaciones. Por una parte solo nos sirve para asegurar que tenemos una solución, pero esta no tiene por qué ser la mejor solución… ni siquiera tiene por qué ser una buena solución. Por otro lado, como guía también deja un poco que desear: tan solo nos señala a dónde debemos llegar, pero no cómo llegamos hasta ahí. Hay técnicas más específicas que sí, intentan ocuparse de eso, pero incluso con eso, no se preocupa tampoco demasiado por decirnos por dónde empezar.

Empecemos con una Plantilla o Herramienta

Esta es una solución aparentemente práctica. Muchos programas, en el fondo, son bastante parecidos si miramos desde lejos. Igual podemos encontrar diez, veinte, los que sean, una cantidad limitada de “tipos de programas”, que cubren la gran mayoría de los programas que se desarrollan. Los detalles luego serán diferentes, claro, pero así en un primer vistazo, un programa de agenda de teléfonos y un programa de catálogo de cómics, se parecen bastante. Incluso muchos programas que no lo aparentan, en el fondo son bastante similares si se dejan a un lado los detalles.

Pensando en esto, lo que se propone es utilizar quizá una herramienta -o quizá un catálogo de plantillas- con la que de un solo paso tengamos no solo el camino marcado, sino de hecho el desarrollo ya en marcha. Podemos, por ejemplo, tomar una plantilla para un programa que lea datos de un fichero, nos deje un hueco en el que el programador escriba el código que necesita para procesar ese fichero y luego escriba el resultado en otro fichero. Todo lo que no es el proceso específico que queremos hacer, es bastante igual.

La ventaja es bastante evidente: Ahorramos tiempo, ahorramos esfuerzo y encima no necesitamos preocuparnos por resolver muchos detalles que, en el fondo no nos importan tanto en nuestro problema. Detalles que son genéricos y ya han sido resueltos por otros. Es, aparentemente, una solución muy práctica y, si está bien hecha, nos marca el camino a seguir de forma muy clara.

Tiene dos pegas, en mi opinión. La más evidente es que dependemos de lo apropiada que sea esa herramienta o plantilla. ¿Cuánto encaja con nuestro programa específico? Y también ¿cómo de bien hecha está la plantilla o herramienta? Esto es una pega evidente. Puede solucionarse buscando mejores plantillas o herramientas, claro, pero es complicado porque generalmente requiere una cierta experiencia para poder evaluar cómo de buena es o para saber si es lo que necesitamos o no.

La segunda desventaja está muy relacionada con lo que estás haciendo ahora mismo y el público al que está orientado esto: Si estamos aquí es porque estamos aprendiendo, porque estamos, en buena medida, descubriendo cómo hacer las cosas. Es muy práctico que nos las den ya hechas, pero a la vez nos quita la oportunidad de investigarlo y aprenderlo nosotros mismos. Por eso no es que no recomiende el uso de estas herramientas en general, pero sí creo que sería muy poco útil usar algo así para aprender.

Empecemos por el Modelo o Dominio del problema

Finalmente hay quienes proponen que, bueno, ya que hemos analizado el problema, hemos trazado una solución, los hemos dividido en partes, hemos identificado cuáles son las partes esenciales y cuáles las auxiliares… En definitiva, si hemos establecido cuál es el dominio de nuestro problema / solución, empecemos por ahí precisamente.

Personalmente, aunque cada propuesta tiene sus ventajas, esta me gusta particularmente y es la que yo suelo recomendar. Más incluso cuando estamos buscando aprender a programar o a programar bien. Las otras propuestas de un modo u otro buscan un resultado práctico, un uso eficiente de los recursos. Son soluciones que funcionan bien en determinados entornos, principalmente porque son metodologías, por decirlo de alguna forma, de gestión.

Comenzar por modelar el dominio del problema deja claro que lo que buscamos es solucionar la esencia del problema. Y que una vez solucionado de la mejor forma posible, desarrollaremos el resto de piezas auxiliares para que sea cómodo de utilizar, para que sea rápido, para que cumpla cualquiera otros criterios que queramos.

Además tiene algo que considero muy positivo precisamente en las fases iniciales. Veamos más en general qué es esto que necesitamos en las fases iniciales.

La naturaleza exploratoria de la programación

Hemos dedicado un tiempo bastante razonable a estudiar y comprender el problema. Hemos dedicado más tiempo para plantear una solución. Podríamos pensar que efectivamente, siguiendo la cita que mostraba en la introducción -“Primero resuelve el problema. Luego escribe el código.”- ahora deberíamos poder ponernos a escribir el código de manera bastante directa y ligera. En parte es así. Cuando empecemos a escribir el código, deberíamos tener la mayor parte del problema ya resuelto. Escribir el código debería seguirse de forma bastante directa de esa solución.

Sin embargo, hay algo de lo que no he hablado hasta ahora y que hace que esto no sea tan directo como querríamos. En ocasiones puede serlo, pero es habitual que no sea tanto como nos gustaría.

Ese algo del que no he hablado es la naturaleza en buena medida exploratoria de la programación. No solo de la programación, ojo. Muchas otras disciplinas comparten en mayor o menor medida esta naturaleza. Por ejemplo, una buena parte de la ingeniería, sobre todo en las áreas de desarrollo o investigación.

De lo que se trata es de ser conscientes de que la solución que tenemos existe en nuestra cabeza. Si hemos dedicado el esfuerzo y habilidad necesarias, es probable que la solución sea correcta y adecuada. Pero incluso así, la solución no está validada hasta que la construimos. Y así, existe una probabilidad no despreciable de que aún necesitemos ajustar, adaptar, modificar en parte, variar… la solución ligeramente a medida que vamos explorando la implementación de la solución. A menudo surgen pequeños detalles, cosas que habíamos pasado por alto o a las que no habíamos dado suficiente importancia. Si nuestra solución es buena y la hemos planteado bien, generalmente esto solo implicará que habrá que hacer ajustes aquí y allá, pequeñas adaptaciones. Si descubriéramos algo que nos obligara a replantear la solución por completo, entonces es que no habíamos pensado suficiente la solución.

Por esto mismo me gusta empezar por el modelo del dominio: Es la parte fundamental del problema y en las fases iniciales de la implementación -cuando empezamos a escribir código- esa exploración, esos descubrimientos y detalles que encontremos seguramente será aquí donde más importantes sean y a más partes afecten. Si son detalles que se refieren a la esencia del problema está claro que es interesante encontrarlos pronto. Nos aportan más información sobre el problema que podemos usar para refinar tanto nuestra solución como la comprensión del problema original.

Técnicas y metodologías

Todo lo anterior está en parte relacionado con diferentes técnicas y metodologías. Pero estas por lo general van bastante más allá. Una metodología como el desarrollo guiado por tests (en cualquiera de sus variantes) es algo que se aplica desde el principio del proyecto hasta el final. También existen variadas metodologías que empiezan el desarrollo por el mismo punto y sin embargo son relativamente distintas.

No quiero meterme aquí a explicar este tipo de metodologías. En general porque cada una ya tiene sus defensores y sus narradores que las explican con mucho más detalle y corrección de lo que podría hacerlo yo. Pero además porque la idea básica que me guía aquí, creo que es bastante general e independiente de todas esas metodologías. Finalmente, no tengo demasiado cariño a seguir una única metodología estricta como una guía universal que aplicar en todos u cada uno de los desarrollos. Creo que es bueno investigarlas y conocerlas todas -o todas las que podamos- y creo que es bueno saber aplicar una, otra, varias o una mezcla de ellas, según las circunstancias.


¡¿Un nuevo capítulo sin ver código aún?! ¿Mentí al empezar? Bueno, no, nunca prometí que habría código todavía. Pero ahora por lo menos ya tenemos claro por dónde vamos a empezar.

También es que para ver algo de código es necesario utilizar algún ejemplo concreto. Y eso es lo que voy a hacer en el próximo capítulo.


Discusión

Escribe el comentario. Se permite la sintaxis wiki: