¿Cómo transformar diagramas de clases a una implementación de código? Para mí, esta pregunta esconde el santo grial de la programación.
Luego de adentrarme a la red, para leer la teoría al respecto, o al menos encontrar la opinión pública me encontré con un resultado interesante: Nadie habla específicamente sobre como impelementar código. Lo que hallé en su mayotía, fueron quejas a los diagramas UML y formas alternas para diseñar diagramas fácilmente implementables.
Por ejemplo, propuestas como UMLx y en general, modelos ejecutables. El problema de fondo que encontré fue que solemos pensar en la implementación y luego en el diseño. Pensamos en nuestro diseño en función del lenguaje y el código.
En este post, sin embargo, preferiría hablar de mis propias conclusiones sacadas bajo mi poca experiencia.
En mi opinión, la razón por la que los desarrolladores de software utilicen tan poco diagramas formales y por ende, poco afán tengamos por aprender a modelar desde un inicio utilizando buenas prácticas ( lo que en definitiva, reduciría refactorizaciones e iteraciones a nivel estructural en nuestro producto) es porque no se ha aprendido una técnica formal y estructurada para transformar un (buen) diagrama a código.
Actualmente la implementación la realizamos ad hoc al proyecto, no seguimos una metodología formal para implementar nuestros diagramas, nuestras ideas.
Actualmente, en mi escuela existe un club de programación orientado a problemas de entrevistas de trabajo. Los alumnos se afanan por resolver problemas, uno tras otro, resolviendo situaciones utópicas que se resuelven con la implementación de algún algoritmo específico. Creo que es genial que se promuevan este tipo de movimientos.
Sin embargo, cuando me ha tocado desarrollar si quiera, métodos más complejos, con personas que dedican demasiado tiempo a la algoritmia y no dedican el tiempo suficiente al modelado y diseño simplemente explotan. Ven un problema grande y, a pesar de que sepan implementar código super eficiente, sepan quicksort de memoria y sepan resolver cualquier problema de entrevista por debajo de O(n^2), el resultado queda un código muy sucio y difícil de comprender.
¿Entonces, donde queda toda su habilidad para resolver problemas? Sigue ahí. Sin embargo, para programar es necesario también aprender a diseñar soluciones. Esas habilidades también deberían enseñarse en esos clubs de programación.
Implementar diagramas estructurales.
El primer paso para llevar nuestros diagramas a código es algo obvio. Genera las clases descritas en el código, añade los atributos y define los métodos en cada clase. Además, implementa las interfaces que se indiquen. Existen softwares que realizan esto de forma automática, al menos de UML a Java, por lo que sé. Es más, hay herramientas que generan ingeniería inversa, de código a diagramas. Pero ese es otro tema.
A estas alturas, si nuestro diagrama fue bien diseñado, sabemos que atributos requiere nuestro método y cual es la salida. Tenemos que rellenar dicha caja negra.
Para llenar los métodos con código limpio y que funcione, para mí ha funcionado utilizar el siguiente algoritmo recursivo:
- Un método suele representar una actividad o comando. Si la implementación de este método, es trivial, terminó nuestro sufrimiento. Lo implementamos, ¡Yay!
- Si el método requiere de algún algoritmo específico o bien conocido, se llama la librería pertinente y si esta librería no existe ( o llamar esta librería sería un desperdicio de espacio y recursos) lo implementamos ( siguiendo el libro, sin complicaciones, no estamos en examen de algoritmos). Es más, creamos nuestra propia clase (Utils suelo llamarla) para algoritmos.
- Si existe una iteración, implica que una operación similar se aplicará a distintos objetos. Todo lo que exista dentro de nuestro ciclo, podemos delegarlo a otro método. De esta forma, nuestro código no queda con muchos niveles de tabulación ( demasiado anidado ) y podemos utilizar recursivamente este método ( si fuera necesario).
- Si el método no es suficientemente trivial ( atómico ) implica que dicha operación se puede separar en acciones más pequeñas. En este punto, es posible realizar una serie de diagramas de objetos, para observar la evolución de nuestro objeto, o un diagrama de estados, para evaluarlo de forma secuencial. Como una receta de cocina, sabiendo los ingredientes y el platillo final, podemos discretear en operaciones más pequeñas nuestro método. Aquí está el secreto de la magia.
- Dados los métodos generados ( que, al ser subprocesos internos, son automáticamente privados) se aplica nuestro algoritmo para cada una de estas nuevas operaciones.
- Si se debe implementar una clase anónima, no se hace inline. Se define una variable que contendrá esta clase anónima. A los métodos dentro de esta clase se les aplica el algoritmo.
- Si requerimos en una clase anónima, llamar para alguna operación, algún objeto fuera de dicha clase, la operación se deberá realizar en un método en el objeto receptor.
Luego de seguir este algoritmo, suelo obtener un código limpio e implementado de forma rápida, ya que en todo momento realizo operaciones pequeñas. El testeo de nuestros métodos y la resolución de bugs se vuelve más simple, ya que testeamos siempre métodos cortos y con operaciones atómicas. Los problemas, son fácilmente diagnosticables.
La mayoría de mis proyectos o trabajos, no han requerido otro lenguaje de programación, fuera de Java. Por lo tanto, no he tenido problemas en acoplar los diagramas a la sintaxis o limitantes de otros lenguajes de programación.
Este será un blog corto, pero creo que será el más importante del curso, ¡lo puedo apostar!
Adiós!