Software Design — 2ª edición
Nota a la 2ª edición: el siguiente texto lo redacté en el año 2001 . Puse por escrito algunas de mis nociones de aquella época y envié el texto a un colega quien ese año me preguntó mi opinión sobre cómo diseñar software. Por el momentola primera edición no está disponible en línea. En esta segunda edición me tomé la libertad de disminuir un poco el tufo dogmático de la primera edición . Además, agregué referencias a la fecha de algunas páginas en Internet que cambiaron; aunque mantuve las referencias anteriores , quizá por nostalgia . Esta segunda edición tan sólo contiene pequeñas adaptaciones a la primera edición. Muchos de los puntos requieren actualizaciones mayores.
——
Con respecto al diseño de software, que es el aspecto más fascinante para mí de lo que hacemos como programadores profesionales, permíteme comentarte mis impresiones y conclusiones actuales acerca de esta actividad. Por supuesto, estas conclusiones están sesgadas por mi enturbiado entendimiento, pero después de estudiar la experiencia de algunas luminarias en nuestro campo, e intentar practicar sus lecciones, encuentro que dichas conclusiones tienen sentido para mí.
I. El resultado de la actividad 'diseño'
El resultado material de la actividad de diseño debe ser algo ejecutable. Cualquier cosa menos que eso es pura estimulación mental.
II. Arquitectura de software
Todos los aspectos, de alto y bajo nivel, de nuestro diseño están expresados, implícita o explícitamente, en la arquitectura del software. Aunque “arquitectura de software” todavía es un término difuso, una exposición adecuada de arquitectura de software es la de Philippe Kruchten «The 4+1 View Model of Architecture».
The 4+1 View Model of Architecture
https://www.computer.org/csdl/mags/so/1995/06/s6042-abs.html
IEEE Software November 1995 (Vol. 12, No. 6)
https://www3.software.ibm.com/ibmdl/pub/software/rational/web/whitepapers/2003/Pbk4p1.pdf
https://www.rational.com/media/whitepapers/Pbk4p1.pdf
En resumen, la arquitectura de software considera 5 vistas o categorías, agrupadas por su naturaleza en:
Conceptual:
Vista Lógica (clases, módulos y subsistemas)
Vista Concurrente (procesos y threads)
Física:
Vista de Componentes (medios para empaquetar los elementos de la Vista Lógica: assemblies, DLLs)
Vista Distribuida (comúnmente llamada infraestructura de cómputo: servidores que contienen los elementos de la Vista de Componentes)
Funcional:
Vista de Casos de Uso. Ésta gobierna a todo lo que puede existir en las otras vistas; en otras palabras, nada debe existir si no aporta a soportar la funcionalidad del software
III. El código fuente es el diseño detallado del software
El diseño de alto nivel puede consistir de diagramas que expresen aspectos de las diferentes vistas de Kruchten, pero el diseño detallado es el código fuente. En software, nuestros planos detallados es un documento técnico llamado comúnmente «código fuente». Dichos planos de nuestro producto son entregamos al constructor del producto: el compilador o traductor a código ejecutable.
Philippe Kruchten, Jack W. Reeves y otros tienen algunas ideas al respecto:
What is Software Design? by Jack W. Reeves
https://www.bleading-edge.com/Publications/C++Journal/Cpjour2.htm
The Nature of Software: What's so Special About Software Engineering? by Philippe Kruchten
https://www.therationaledge.com/content/oct_01/toc.html
From Craft to Science: Searching for First Principles of Software Development by Koni Buhrer
https://www.therationaledge.com/content/dec_00/f_craftscience.html
IV. Decidir es diseñar
Diseñar requiere decidir constantemente, diseñar es decidir. Decidir sobre los aspectos del diseño detallado, decidir sobre los aspectos de diseño de alto nivel, e incluso decidir que no vamos a decidir nada todavía sobre alguna propiedad particular del software; es decir, vamos a diferir dicha decisión.
Martin Fowler habla acerca del diseño en:
Is Design Dead?
https://martinfowler.com/articles/designDead.html
What's a Model For?
https://www.martinfowler.com/distributedComputing/purpose.pdf
https://martinfowler.com/articles/purpose.pdf
V. Diseño estable y emergente
Diseñar requiere consideración de los principios que gobiernan y sustentan la arquitectura de software; como dice Bertrand Meyer, los aspectos a gran escala de la arquitectura de software se encomiendan o están sustentados en los aspectos de bajo nivel o escala detallada (código fuente). Si estos aspectos no obedecen a principios coherentes y de estilo, entonces difícilmente se logran los aspectos a gran escala.
Existe un cuerpo de conocimiento importante acerca de diseño orientado a objetos, con reglas que representan esos principios coherentes y de estilo:
Principles Of Object Oriented Design
https://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign
Las recomendaciones del maestro Stroustrup agregan perspectivas importantes:
Bjarne Stroustrup's C++ Style and Technique FAQ
https://www.stroustrup.com/bs_faq2.html
https://www.research.att.com/~bs/bs_faq2.html
Las prácticas básicas son esenciales. Steve McConnell, ex-programador de Microsoft, tiene buen material al respecto:
Code Complete: A Practical Handbook of Software Construction
https://www.stevemcconnell.com/cc.htm
Rapid Development: Taming Wild Software Schedules
https://www.stevemcconnell.com/rd.htm
La técnica de factorización representa una excelente forma para mantener un diseño estable y flexible:
Refactoring
VI. Control empírico del proceso de diseño
Un método de diseño es intrínsecamente iterativo e incremental. Se adhiere a un proceso 'gestalt'; es decir, no puedes terminar de diseñar software si primero no lo programas, y al mismo tiempo no puedes programar software si primero no lo diseñas.
Existen métodos sistemáticos de diseño y programación, Martin Fowler habla acerca de algunos métodos actuales:
The New Methodology
https://martinfowler.com/articles/newMethodology.html
Continuous Integration (no daily build)
https://martinfowler.com/articles/continuousIntegration.html
VII. Método sistemático de diseño
Un método sistemático de programación consiste de al menos tres partes:
a. Una notación — el énfasis aquí es contar con un conjunto de conceptos de diseño que guarden coherencia y que puedan ser expresados por medio de dicha notación. Actualmente está de moda UML y es importante tener mentalmente disponibles sus conceptos para comunicar la arquitectura de software. Pero para el diseño detallado (código fuente) la notación más eficiente y efectiva sigue siendo el lenguaje de programación seleccionado.
En otras palabras, todo lo que se puede expresar en un diagrama de clases en UML se puede expresar en el código fuente; y mientras las herramientas de generación de código carezcan del nivel de abstracción suficiente para eliminar la necesidad de modificar el código generado, el diseño detallado seguirá siendo el código fuente en sintaxis del lenguaje de programación.
En el futuro, seguramente habrá las herramientas para expresar todos los aspectos del diseño detallado en una notación como UML, y entonces eso será nuestra nueva forma de código fuente.
b. Un proceso — actividades, roles y artefactos. Los mejores procesos son los que incluyen un ciclo cerrado de retro-alimentación que se ajusta a la naturaleza 'gestalt' del software.
Los artículos en el siguiente sitio tienen información relevante acerca de los procesos que varios programadores profesionales han sintetizado:
https://www.extremeprogramming.org
¿Qué es «Software craftsmanship»?
https://blogs.msdn.microsoft.com/destreza/2017/03/19/que-es-software-craftsmanship/
El potencial de los métodos ágiles de diseño está en la esencia del desarrollo cooperativo:
-Control empírico del proceso de desarrollo
-Comportamiento emergente o adaptativo
-Auto-organización
c. Herramientas — que soporten el conjunto de conceptos disponibles en la notación.
En la práctica, lo más eficiente y efectivo, si el objetivo es obtener software ejecutable, es usar las herramientas más simples que ayuden con la comunicación entre las personas en el equipo de desarrollo y entre los individuos y la computadora.
En otras palabras, una simple hoja de papel y lápiz, o un pizarrón, son más efectivas que costosas herramientas CASE. No menos importante, el compilador es la mejor herramienta para verificar el aspecto estático de tu diseño detallado, el compilador hará un análisis preciso de tus decisiones de diseño y te dirá invariablemente toda inconsistencia con su sistema de tipos.
Además, para verificar los aspectos dinámicos de tu diseño, un contexto de pruebas unitarias (unit-testing framework) te ayudará a obtener la retroalimentación para evolucionar tu diseño de forma coherente y concreta, satisfaciendo los aspectos de la Vista de Casos de Uso de tu arquitectura.
Kent Beck y Erich Gamma exponen el diseño de un contexto de pruebas aquí:
JUnit Cookbook
https://junit.sourceforge.net/doc/cookbook/cookbook.htm
JUnit A Cook's Tour
https://junit.sourceforge.net/doc/cookstour/cookstour.htm
Como dice Martin Fowler: «Never in the field of software development was so much owed by so many to so few lines of code».
Contextos de pruebas para varios lenguajes de programación están disponibles aquí (incluyendo la versión en C++Builder que hice del CppUnit de Michael Feathers):
https://www.xprogramming.com/software.htm
En general, el material en este sitio provee buen material para el diseño y desarrollo de software:
https://www.objectmentor.com/resources/articles
Los mejores métodos sistemáticos de diseño y programación actuales se derivan del trabajo de las siguientes luminarias:
Profesor Edsger Wybe Dijkstra
https://www.cs.utexas.edu/users/EWD/
Kristen Nygaard
https://www.mn.uio.no/ifi/english/about/kristen-nygaard/
https://www.ifi.uio.no/~kristen/
Ole-Johan Dahl
https://www.mn.uio.no/ifi/english/about/ole-johan-dahl/
https://www.ifi.uio.no/%7Eolejohan/
Alan Turing
https://www.turing.org.uk/turing/
Niklaus Wirth
https://www.inf.ethz.ch/personal/wirth/
https://www.cs.inf.ethz.ch/~wirth/
Donald E. Knuth
https://www-cs-faculty.stanford.edu/~knuth/
Bjarne Stroustrup
https://www.research.att.com/~bs/homepage.html
Barbara Liskov
https://www.pmg.csail.mit.edu/~liskov/
https://www.objectmentor.com/resources/articles/lsp.pdf
David Lorge Parnas
https://www.computer.org/web/awards/mills-david-parnas
https://www.crl.mcmaster.ca/SERG/parnas.homepg
Tom DeMarco
https://www.systemsguild.com/tdm.htm
https://www.atlsysguild.com/GuildSite/TDM/Tom_DeMarco.html
Gerald M. Weinberg
https://www.geraldmweinberg.com
Larry Constantine
https://wiki.c2.com/?LarryConstantine
Edward Yourdon
Meilir Page-Jones
https://www.construx.com/Employees/Meilir_Page-Jones/
Grady Booch
https://researcher.watson.ibm.com/researcher/view.php?person=us-gbooch
James Rumbaugh
https://en.wikipedia.org/wiki/James_Rumbaugh
Ivar Jacobson
Bertrand Meyer
VIII. Dimensiones en desarrollo de software
Los factores para la calidad del diseño y desarrollo de software se pueden agrupar en cuatro dimensiones:
a. Personas - el aspecto más importante y que aporta en general los factores determinantes para la calidad del software
El trabajo de Tom DeMarco y Tim Lister habla de esto desde hace ya muchos años
https://www.systemsguild.com/tdm.htm
First-Order Components in Software Development (People-oriented programming, non-linear response) de Alistair Cockburn
https://crystalmethodologies.org/articles/panlc/peopleasnonlinearcomponents.html
Las personas en el diseño y programación orientada a objetos, de un servidor:
https://sg.com.mx/content/view/338
https://www.rosenblueth.mx/InterFAR/Vol1Num3/doc/Vol1Num3-48.htm
b. Proceso - las secciones VI y VII arriba.
c. Arquitectura de Producto - las secciones II, III, IV y V arriba.
Si un producto de software es correcto y robusto, es porque su código fuente tiene una adecuada administración de dependencias internas y conserva un adecuado sentido de estética y orden entre sus componentes; si un producto de software es modular y extensible es porque su código fuente tiene esas propiedades.
De ninguna otra manera es posible conseguir la calidad externa del software si no se atiende desde el principio la calidad interna. De esto trata el siguiente artículo de Bertrand Meyer:
Factores de la calidad del software
https://www.angelfire.com/dc/marcodorantes/Docs/CalidadDelSoftware.doc
d. Tecnología - aquí va todo el conocimiento específico de una plataforma de cómputo
IX. Pensamiento sistémico
Patrones y la teoría general de sistemas para el futuro (que ya paso) - existe material importante y un cuerpo de conocimiento fundamental que, sin importar lo que diga la mercadotecnia, es indispensable dominar para ser relevante en desarrollo de software ahora y siempre. Se trata de los patrones o mecanismos análogos de la teoría general de sistemas.
Comúnmente se escucha de patrones de diseño; sin embargo, esos pertenecen a una categoría, pero los hay por todos lados: patrones de proceso, patrones organizacionales, patrones arquitectónicos, patrones de implementación (idioms), patrones de análisis. Esto equivale a lo que la teoría general de sistemas estudia como situaciones análogas en relación a los procesos de pensamiento en los seres humanos.
Las herramientas de pensamiento para diseño moderno de software están disponibles y serán las bases para el software que estaremos usando en el cual se utilizan múltiples paradigmas para su diseño.
Algunas referencias al respecto:
•Patrones
Pattern Languages of Programs
https://hillside.net/conferences
https://jerry.cs.uiuc.edu/~plop/
Euro-Plop
https://www.argo.be/europlop/Papers/Final/
Portland Pattern Repository
https://c2.com/cgi/wiki?PortlandPatternRepository
Patrones organizacionales de James Coplien
https://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?CoplienOrganizationPatterns
•Diseño multi-paradigma
Generative Programming
https://www.generative-programming.org/
https://www.prakinf.tu-ilmenau.de/~czarn/generate/engl.html
Aspect-Oriented Programming
https://www2.parc.com/csl/groups/sda/
Intentional Programming
https://www.intentionalsoftware.com
https://www.c2.com/cgi/wiki?IntentionalProgramming
Generic Programming
https://www.lafstern.org/matt/
•Acerca de la teoría general de sistemas
Cybernetics and Systems Theory
https://pespmc1.vub.ac.be/CYBSYSTH.html
«Este no es el final, ni siquiera es el comienzo del final; tal vez, tan sólo es el final del comienzo» —Winston Churchill