CodeSimplicity Español
CodeSimplicity Español
Tabla de contenido
Consecuencias imprevisibles 17
iii
Machine Translated by Google
IV | Tabla de contenido
Machine Translated by Google
Prefacio
Hace muchos años, me dieron una oportunidad única. Empecé a trabajar como voluntario en el
desarrollo de software para un proyecto de código abierto llamado "Bugzilla" que tenía un código
desordenado. Había llegado a lo que generalmente se considera el "punto de no retorno" en el desarrollo
de software: debido a la complejidad del sistema, era tan difícil de modificar que todo el trabajo de
funciones nuevas se había ralentizado. La mayoría de los desarrolladores estaban levantando las
manos en el aire y alejándose del proyecto con frustración. Después de todo, eran voluntarios: no
tenían que lidiar con un código incorrecto si no querían.
Sin embargo, Bugzilla había existido durante seis años en ese momento y tenía millones de usuarios.
Era una de las columnas vertebrales del desarrollo de código abierto en la Web: casi todos los proyectos
importantes de código abierto lo usaban para realizar un seguimiento de los errores que necesitaban
corregir en su software. Algunas empresas, como Mozilla, los creadores de Firefox, usaban Bugzilla
para realizar un seguimiento de todas las tareas que realizaban todos los empleados de la empresa. Si
Bugzilla muriera como proyecto, habría sido un duro golpe para el mundo del desarrollo de código
abierto y, en menor medida, para la industria del software en general.
Entonces, obviamente, tenía que sobrevivir. Pero, ¿cómo podríamos hacer eso? Normalmente, en este
punto del ciclo de vida del desarrollo de software, las organizaciones tienden a reescribir su software.
Pero debido al desgaste de los desarrolladores, no teníamos los recursos para volver a escribir. ¡Apenas
teníamos los recursos para mantener el código existente!
Nacido en parte por necesidad, pero más aún por un idealismo que detesta tirar un sistema completo
solo para reescribir uno idéntico, emprendí una cruzada para arreglar el código existente de Bugzilla en
lugar de reescribirlo. Yo y un pequeño grupo de nuevos desarrolladores en el proyecto rediseñamos el
sistema existente pieza por pieza y enviamos nuevas versiones ligeramente mejoradas cada pocos
meses. Todavía estábamos escribiendo nuevas funciones mientras hacíamos esto, pero siempre de
una manera que hacía que el código fuera mejor, no más desordenado.
Y funcionó. Chico, funcionó. Después de tres años de arreglar el código de esta manera, estábamos
bombeando funciones al doble de la velocidad que solíamos con 1/4 de los desarrolladores que solía
tener el proyecto (antes de que todos abandonaran el antiguo código desordenado). Con un equipo de
voluntarios a tiempo parcial, sin ningún presupuesto y sin ningún tipo de marketing, seguimos siendo
uno de los mejores productos en nuestro campo frente a competidores con un gran personal de
desarrolladores y flujos de ingresos multimillonarios.
v
Machine Translated by Google
Entonces, ¿cómo logramos hacer esto? Bueno, durante muchos años antes de comenzar a
trabajar en el Proyecto Bugzilla, había estado desarrollando las semillas de una filosofía de
desarrollo de software que no era solo un nuevo método para administrar a los desarrolladores,
sino que consistía en una serie de leyes universales: ideas que podrían aplicarse a cada
proyecto de software, en cada idioma, que resolvería cualquier situación en la que los
desarrolladores pudieran encontrarse. El problema, pensé, era que había demasiadas opiniones
en el mundo del software y no suficientes hechos. Si pudiera descubrir cuáles son los hechos
más universales y fundamentales sobre el desarrollo de software, entonces muchos otros problemas desaparecerían
El Proyecto Bugzilla fue mi principal banco de pruebas para descubrir estos hechos y, una vez
determinados, marcaron una diferencia increíble en la calidad del código y el éxito del producto.
Sin embargo, no es suficiente probar una idea en un producto y llamarlo un hecho, sin importar
cuán exitoso sea. Entonces, una vez que tuve una buena idea de cuáles eran estos hechos,
comencé proyectos personales completamente nuevos para ver la diferencia que harían allí, y
funcionaron igual de bien. Luego comencé a entrevistar a programadores sobre las situaciones
en sus organizaciones y la historia de su software. Quería ver si podía encontrar contraejemplos
a estos hechos, y no encontré ninguno. En cambio, aprendí que podía predecir el final de casi
todas las historias de desarrollo de software simplemente escuchándolas a la mitad, usando los
hechos que había descubierto.
Todo esto todavía no es suficiente, por supuesto. Probé las ideas en varios otros proyectos del
mundo real y las encontré igualmente verdaderas allí como lo fueron en Bugzilla. Presenté mis
ideas a miles de desarrolladores para ver si a alguien se le ocurría un contraejemplo a partir de
su experiencia, y nadie lo hizo nunca. Busqué numerosos experimentos que se habían hecho
con el desarrollo de software, no para ver las conclusiones, que a menudo eran erróneas, sino
simplemente para ver si los datos que los investigadores habían rastreado respaldaban estas
ideas, y así fue. Estudié la historia del desarrollo de software y las trayectorias de proyectos de
software famosos para ver si coincidían con estas ideas, y así fue. No hay, que yo sepa, ninguna
experiencia o dato en ninguna parte de la historia del desarrollo de software que contradiga lo
que voy a contarles en este libro.
Ahora, por supuesto, no estoy diciendo que lo que hay en este libro sea perfecto. Solo digo que
funciona. Hasta donde he podido, he comprobado que cada una de las ideas aquí contenidas
mejorará cualquier proyecto de software al que se apliquen. Ahora que las ideas están
formalizadas, me encantaría hacer ciencia más sólida sobre ellas en experimentos mejor
elaborados, pero hasta entonces creo que son lo suficientemente prácticas como para
entregárselas tal como son. Realmente creo que son las leyes universales del desarrollo de
software, que representan los funcionamientos naturales reales del universo en el que vivimos
y que tienen el potencial de ayudar a que cada proyecto de software sea más simple, más sensato y más exitoso.
Lo más extraño de estas ideas es que son increíblemente simples. De hecho, cuando lee
algunos de ellos, puede pensar que son tan simples como para ser estúpidos. No es que la
gente no haya conocido muchas de estas ideas, es que no sabían que eran
vi | Prefacio
Machine Translated by Google
leyes Una vez que comienza a pensar con estas ideas como la base fundamental para todas las buenas
decisiones de desarrollo de software, como verdades inquebrantables de las que se derivan todas las
mejores prácticas, es cuando comienza a darse cuenta de su verdadero valor.
E incluso si conociera estas ideas, tal vez cada una de las ideas de este libro, piénselo de esta manera:
¿qué pasaría si todos los programadores nuevos pudieran aprender todas estas ideas sin tener que pasar
por todas las experiencias difíciles que tuvo que tener? Hay tantos programadores nuevos entrando en el
campo en este momento que algunas empresas están en una confusión continua de malas prácticas como
resultado de la inexperiencia. ¿Qué pasaría si los nuevos desarrolladores no necesitaran tener todas esas
malas experiencias solo para aprender los fundamentos de la ingeniería práctica de software? Bueno,
espero que eso sea lo que representa este libro: la oportunidad para todos los desarrolladores, tanto los
más experimentados como los nuevos, de obtener los conocimientos más importantes sobre el software
que hay que tener. Porque aquí está el primer dato que les voy a dar, uno de los últimos que descubrí:
Es decir, los malos programadores no entienden lo que están haciendo y los buenos programadores sí. Lo
creas o no, realmente es así de simple. Cuanto más entiendas lo que estás haciendo, mejor podrás hacerlo.
Se aplica a la programación de la misma manera que cualquier otro campo en el mundo, excepto que es
más importante en la programación porque escribir software es casi una actividad puramente mental donde
la comprensión lo es todo.
Ahora bien, no estoy diciendo que todas las ideas de este libro vayan a resolver instantáneamente sus
problemas o le digan exactamente qué hacer en su situación específica. En cambio, este libro le dará
nuevas formas de pensar sobre el desarrollo de software. Depende de usted usar esas formas de pensar
para resolver sus propios problemas en función de lo que sea mejor para su situación. Solo usted puede
saber lo suficiente sobre lo que está pasando con su software para tomar decisiones específicas correctas
al respecto. Este libro solo contiene principios generales para ayudarlo a guiarlo en la toma de esas
decisiones.
Incluso si no es un programador, puede encontrar este libro útil por varias razones:
Le permitirá comprender de manera más efectiva por qué los ingenieros de software quieren hacer ciertas
cosas o por qué el software debe desarrollarse de cierta manera. • Puede ayudarlo a comunicar sus
ideas de manera efectiva a los ingenieros de software, ayudándolo a comprender los principios
fundamentales en los que los buenos ingenieros de software basan sus decisiones.
Idealmente, todos los que trabajan en la industria del software deberían poder leer y comprender este libro,
incluso si no tienen mucha experiencia en programación, o incluso si el inglés no es su idioma nativo. Tener
una comprensión más técnica ayudará a comprender algunos de los conceptos, pero la mayoría no requiere
experiencia en programación para comprenderlos.
Prefacio | viii
Machine Translated by Google
Notará, de hecho, que aunque este libro trata sobre el desarrollo de software, casi no contiene código de programa.
¿Como puede ser? Bueno, la idea es que estos principios se apliquen a cualquier proyecto de software, en cualquier
lenguaje de programación. No debería tener que saber algún lenguaje de programación específico solo para
comprender las cosas que se aplican a toda la programación, en todas partes. En cambio, se utilizan ejemplos y
analogías del mundo real a lo largo del libro para ayudarlo a obtener una mejor comprensión de cada principio, tal
como se presenta.
Sobre todo, espero que este libro lo ayude, ayude a su software y ayude a traer cordura, orden y simplicidad al campo
del desarrollo de software.
• Las definiciones te dicen qué es algo y cómo lo usarías. • Los hechos son solo afirmaciones
• Las reglas son declaraciones que le brindan un verdadero consejo, cubren algo específico y ayudan a guiar las
decisiones, pero no necesariamente lo ayudan a predecir lo que sucederá en el futuro o descubrir otras verdades.
Por lo general, le dicen si debe o no tomar alguna acción.
• Las leyes son hechos que siempre serán ciertos y que abarcan una amplia área de conocimiento.
Te ayudan a descubrir otras verdades importantes y te permiten predecir lo que sucederá en el futuro.
De todos estos, las leyes son las más importantes. En este libro, sabrás que algo es una ley porque el texto lo dirá
explícitamente. Si no está seguro de en qué categoría cae alguna información, el Apéndice B enumera cada pieza
importante de información en el libro y la etiqueta claramente como una ley, una regla, una definición o simplemente
un hecho antiguo.
Cursiva
Indica nuevos términos, URL, direcciones de correo electrónico, nombres de archivo y extensiones de archivo.
Ancho constante
Se utiliza para las listas de programas, así como dentro de los párrafos para hacer referencia a elementos del
programa, como nombres de variables o funciones.
viii | Prefacio
Machine Translated by Google
Atribución y permisos
Este libro está aquí para ayudarle a hacer su trabajo. Si hace referencia a partes limitadas de él en
su trabajo o escritos, apreciamos, pero no requerimos, la atribución. Una atribución generalmente
indica el título, el autor, el editor y el ISBN. Por ejemplo: “Simplicidad de código: los fundamentos
del software por Max Kanat-Alexander (O'Reilly). Copyright 2012 Max Kanat-Alexander,
978-1-4493-1389-0.”
Tengo un blog y un sitio web en [Link] donde puede ver mis últimos
pensamientos sobre el desarrollo de software, hacer contribuciones, ponerse en contacto conmigo
para participar en charlas, enviar comentarios y correcciones, o simplemente enviarme sus
pensamientos sobre el software. desarrollo en general.
Prefacio | ix
Machine Translated by Google
illymedia
Expresiones de gratitud
Mis editores, Andy Oram y Jolie Kanat, han sido un recurso invaluable. Los comentarios de Andy
fueron perspicaces y brillantes. La insistencia y el apoyo de Jolie fueron, en última instancia, lo
que logró que se publicara este libro, y se agradeció su trabajo de edición en los primeros
borradores.
Mi correctora, Rachel Head, tiene un talento notable para aclarar y mejorar todo.
Todos los programadores con los que he trabajado y con los que he hablado en la comunidad de código
abierto también merecen mi agradecimiento, en particular mis compañeros desarrolladores en el Proyecto
Bugzilla que me ayudaron a probar todas las ideas de este libro en un sistema de software real y en vivo
durante el curso de muchos años.
x | Prefacio
Machine Translated by Google
Los comentarios y la retroalimentación que he recibido en mi blog a lo largo de los años me han
ayudado a dar forma a la forma y el contenido de este libro. Todos los que han participado allí
merecen un agradecimiento, incluso aquellos que simplemente me animaron o me hicieron saber
que leerían un artículo.
A nivel personal, estoy tremendamente agradecido con Jevon Milan, Cathy Weaver y todos los que
trabajan con ellos. En un sentido muy real, ellos son los responsables de que yo sea capaz de escribir
este libro. Y, por último, me quito el sombrero ante mi amigo Ron, sin el cual este libro no habría sido
posible.
Actualizaciones de contenido
13 de junio de 2012
Prefacio | xi
Machine Translated by Google
Machine Translated by Google
CAPÍTULO 1
Introducción
A todos nos han enseñado que el software es “una serie de instrucciones dadas a la computadora”,
y esto es cierto. Sin embargo, no hay campo en el que un conjunto de instrucciones y el resultado
de esas instrucciones estén tan estrechamente vinculados como en el campo del desarrollo de
software. En otros campos, la gente escribe instrucciones y luego se las entrega a otros, a menudo
esperando mucho tiempo para ver cómo se llevan a cabo. Pero cuando escribimos código, no hay
nadie entre nosotros y la computadora. El resultado es exactamente lo que dicen las instrucciones,
sin lugar a dudas. La calidad del resultado final depende completamente de la calidad de la máquina,
la calidad de nuestras ideas y la calidad de nuestro código.
De estos tres factores, la calidad del código es el mayor problema al que se enfrentan los proyectos
de software en la actualidad. Como resultado, la mayor parte de este libro se centra en mejorar la
calidad del código. También toco ideas y máquinas en algunos lugares, pero la atención se centra
principalmente en mejorar la estructura y la calidad de las instrucciones que le estamos dando a la
máquina.
Sin embargo, es importante recordar que lo hacemos simplemente porque deseamos un mejor
resultado. Nada en este libro perdona un mal resultado: la única razón por la que nos enfocamos
en mejorar el código es porque mejorar el código es el problema más importante que debemos
resolver para mejorar el resultado.
Pero nada de esto es inevitable. La inestabilidad, la hinchazón y varios otros problemas de código
no surgen de alguna ley natural del universo que requiera que todo el software apeste.
1
Machine Translated by Google
Cuando comenzamos, nuestros sistemas de software son pequeños y fáciles de mantener. Pero todos
crecen, con el tiempo. El sistema de software promedio se vuelve lo suficientemente grande como para
que ningún ser humano pueda esperar tener todo su código en su mente a la vez. Esto no es bueno o
malo, es solo un hecho. Los sistemas de software eficaces son, en su conjunto, inherentemente
complejos. La única esperanza que tenemos para trabajar con estos sistemas es mantener las piezas
individuales simples, para que cuando las veamos, podamos comprenderlas. La programación, en
esencia, debe convertirse en el acto de reducir la complejidad a la simplicidad.
Si los desarrolladores individuales no simplifican las partes del código en las que trabajan, esas partes
se vuelven difíciles de entender. Eso los hace difíciles de depurar, difíciles de modificar y difíciles de
agregar funciones. Si demasiadas piezas del sistema se vuelven complejas, el sistema como un todo
ya no se puede mantener. Aquí es donde surgen casi todos los problemas del desarrollo de software
moderno: los desarrolladores individuales agregan complejidad al sistema en lugar de quitarla.
Un buen programador debe hacer todo lo que esté a su alcance para hacer que lo que escribe
sea simple para que otros programadores lo usen y comprendan.
A veces, esta idea de simplicidad se malinterpreta como que los programas no deben tener
mucho código o no deben usar tecnologías avanzadas. Pero eso no es cierto. Algunas veces,
una gran cantidad de código en realidad conduce a la simplicidad; solo significa más escritura y
más lectura, lo cual está bien. Y, por lo general, las tecnologías avanzadas conducen a una
mayor simplicidad, aunque aprenderlas lleva tiempo.
Algunas personas creen que escribir código simple toma más tiempo que escribir
rápidamente algo que “hace el trabajo”. No hay datos de los que tenga conocimiento que
validen esta idea. El desarrollo de software serio casi siempre tiene plazos largos, semanas
o meses como mínimo. Cuando agrega complejidad a su programa, se está desacelerando
mañana. Todos los estudios que he leído (y toda mi experiencia personal) concluyen que
escribir código simple en última instancia hace que el trabajo se haga más rápido, incluso
cuando piensas que la complejidad es un atajo.
parte de este libro trata sobre el diseño de software, el proceso de planificación de la estructura de su
código.
Cada vez que vea la palabra "diseño" en este libro, se refiere al diseño de
software, no al diseño visual, al diseño de la interfaz de usuario o a algún otro
tipo de diseño.
2 | Capítulo 1 Introducción
Machine Translated by Google
Siempre hay una cierta cantidad de diseño involucrado en el software, incluso si es solo una decisión
rápida antes de que sus dedos toquen el teclado. En un equipo de programadores, cada persona
está involucrada en el diseño. El desarrollador principal está a cargo de diseñar la arquitectura general
de todo el programa. Los programadores senior están a cargo de diseñar sus propias áreas grandes.
Y los programadores junior están a cargo de diseñar sus partes del programa, incluso si son tan
simples como una parte de un archivo. Incluso hay una cierta cantidad de diseño involucrada en
escribir una sola línea de código.
Cada persona en un equipo de software es responsable de asegurarse de que su propio código esté
bien diseñado. Nadie que esté escribiendo código para un proyecto de software puede ignorar el
diseño de software, en cualquier nivel.
Sin embargo, esto no significa que el diseño sea una democracia. No debe diseñar por comité. El
resultado será un mal diseño activo, que hará las cosas más complejas en lugar de simplificarlas.
En cambio, todos los desarrolladores deberían tener la autoridad para tomar buenas decisiones de
diseño en sus propias áreas. Si toman decisiones malas o mediocres, estas deben ser anuladas por
un desarrollador senior o el programador líder, quien debe tener poder de veto sobre los diseñadores
debajo de ellos.1 Pero de lo contrario, la responsabilidad del diseño del código debe recaer en las
personas que realmente están trabajando en ello.
Un diseñador siempre debe estar dispuesto a escuchar sugerencias y comentarios, porque los
programadores suelen ser personas inteligentes que tienen buenas ideas. Pero después de considerar
todos los datos, cualquier decisión debe ser tomada por un individuo, no por un grupo de personas.
1. Si usted es quien anula una decisión, intente educar al otro programador cuando lo haga. Muestra cómo o por qué
tu decisión es mejor que la de ella. Si hace esto, con el tiempo tendrá que anular cada vez menos a ese programador.
Sin embargo, algunos programadores nunca aprenden; si después de varios meses o años de tal educación, un
programador continúa tomando muchas malas decisiones, debe ser eliminado de su equipo. Sin embargo, la
mayoría de los programadores son personas muy inteligentes que captan las cosas rápidamente, por lo que esto
rara vez es una preocupación.
Diseño de software | 3
Machine Translated by Google
Machine Translated by Google
CAPITULO 2
Antes de que podamos sumergirnos en las leyes del desarrollo de software, debemos entender en qué dirección nos
dirigimos con ellas. ¿Cuál es el criterio para determinar si funcionan o no? Bueno, idealmente tendríamos algún propósito
en mente. Entonces podríamos decir que nuestras ideas son válidas en la medida en que cumplan con ese propósito.
Por lo tanto, lo que necesitamos es una declaración del propósito del software en sí. No los propósitos personales de los
desarrolladores que lo escriben, o las razones que tiene la organización para contratar programadores, sino el propósito
real del software como un todo. Entonces podemos ver si nuestras leyes y reglas ayudan a lograr ese propósito.
¿Es posible derivar una sola declaración de propósito que se ajuste a todo el software? Bueno, creo que tengo.
Podemos dividir esto en un propósito más específico para piezas de software individuales.
Por ejemplo, existe un procesador de textos para ayudar a las personas a escribir cosas, y existe un navegador web para
ayudar a las personas a navegar por la Web.
Algunas piezas de software existen solo para ayudar a grupos específicos de personas. Por ejemplo, hay muchas piezas
de software de contabilidad que existen para ayudar a los contadores; estos se dirigen solo a ese grupo específico de
personas.
¿Qué pasa con el software que ayuda a los animales o las plantas? Bueno, su propósito es realmente ayudar a las
personas a ayudar a los animales o las plantas.
Lo importante aquí es que el software nunca está ahí para ayudar a los objetos inanimados.
El software no existe para ayudar a la computadora, siempre existe para ayudar a las personas. Incluso cuando estás
escribiendo bibliotecas, estás escribiendo para ayudar a los programadores, que son personas. Nunca estás escribiendo
para ayudar a la computadora.
1. Este hecho (el propósito de todo software) es más importante que una ley. En inglés, no existe una palabra simple
para este tipo de hechos. Quizá podríamos llamarlo una “ley superior”, aunque no se ajusta del todo a los criterios de
una ley (por ejemplo, no predice el futuro). En aras de la simplicidad, los apéndices al final de este libro enumeran
este hecho como una ley y, de lo contrario, simplemente nos referiremos a él como "el propósito del software".
5
Machine Translated by Google
Ahora bien, ¿qué significa “ayuda”? En cierto modo, es subjetivo: lo que ayuda a una persona puede no
ayudar a otra. Pero la palabra tiene una definición de diccionario, por lo que no depende completamente
de cada individuo lo que significa la palabra en sí. El New World Dictionary of the American Language de
Webster define "ayuda" como:
para que sea más fácil para (una persona) hacer algo; ayuda; asistir. Específicamente...para hacer parte
del trabajo de; facilitar o compartir el trabajo de.
Hay muchas cosas en las que podrías ayudar: organizar un horario, escribir un libro, planificar una dieta,
cualquier cosa. En qué ayudas depende de ti, pero el propósito siempre es ayudar.
software malo, es decir, su software no ayudará mucho a la gente. De hecho, podría teorizarse (como
suposición, basada en la observación de muchos programadores a lo largo del tiempo) que su capacidad
potencial para escribir un buen software está limitada solo por su capacidad para concebir ayudar a otros.
En general, cuando tomamos decisiones sobre el software, nuestro principio rector puede ser cómo
podemos ayudar. (Y recuerde, hay varios grados de ayuda: uno puede ayudar mucho o poco, a muchas
personas o solo a unas pocas). Incluso puede priorizar las solicitudes de funciones de esta manera. ¿Qué
función ayudará más a las personas? A esa característica se le debe dar la máxima prioridad. Hay más
que saber sobre la priorización de funciones, pero "¿Cuánto ayuda a nuestros usuarios?" es una buena
pregunta básica para hacer sobre cualquier cambio propuesto en su sistema de software.
En general, este propósito, ayudar a las personas, es lo más importante a tener en cuenta al diseñar
software, y definirlo nos permite ahora crear y comprender leyes reales para el diseño de software.
2. Tenga en cuenta que “ganar dinero” ciertamente puede ser uno de sus propósitos personales o un propósito de su
organización; no hay nada de malo en ganar dinero. Simplemente no debería ser el propósito de su software. En
cualquier caso, es probable que la cantidad de dinero que gane esté directamente relacionada con cuánto ayuda
su software a las personas. De hecho, los dos factores principales que determinan los ingresos de una empresa de
software son probablemente la habilidad empresarial de su organización (incluida la administración, la gestión, el
marketing y las ventas) y cuánto ayuda su software a las personas.
"para ayudar a los programadores a editar texto". Está bien ser más específico que eso, ya veces es
útil, pero si el grupo no puede ponerse de acuerdo sobre un propósito específico, al menos proponga
uno simple como este.
Ahora que tenemos el propósito, veamos todas nuestras solicitudes de funciones. Para cada uno
podemos preguntarnos: "¿Cómo ayudaría esta característica a los programadores a editar texto?" Si la
respuesta es "No lo haría", podemos tachar inmediatamente esa característica de nuestra lista. Luego,
para cada una de las características restantes, podemos escribir la respuesta como una oración corta.
Por ejemplo, supongamos que alguien nos pide que agreguemos atajos de teclado para acciones comunes.
Podríamos decir: "Esto ayuda a los programadores a editar texto porque les permite interactuar con el
programa más rápidamente sin tomarse un largo descanso de escribir". (En realidad, no tiene que
escribir estas cosas, si eso no parece práctico para su situación; solo tener una idea de la respuesta
por sí mismo es suficiente).
También hay varias otras razones útiles para hacer esta pregunta:
• Ayuda a resolver dudas sobre la descripción de la característica o cómo se debe implementar. Por
ejemplo, la respuesta anterior sobre los atajos de teclado nos dice que la implementación debe
ser rápida, porque ese es el valor que obtienen los usuarios. • Ayuda al equipo a llegar a un
acuerdo sobre el valor de una característica. Es posible que a algunas personas no les guste la idea
de los atajos de teclado, pero todos deberían estar de acuerdo en que la respuesta anterior
explica por qué son valiosos. De hecho, algunos desarrolladores pueden incluso tener una mejor
idea de cómo satisfacer la necesidad de ese usuario (interactuar con el editor de texto más
rápidamente) sin atajos de teclado. ¡Está bien! Si la respuesta nos lleva a una mejor idea de
característica, deberíamos implementarla en su lugar. La respuesta nos dice lo que realmente se
necesita, no solo lo que el usuario pensó que quería.
• Responder a la pregunta hará evidente que algunas características son más importantes
que otros. Esto ayuda a los líderes del proyecto a priorizar el trabajo.
• En el peor de los casos, si nuestro editor de texto se ha inflado con demasiadas funciones con el
tiempo, la respuesta puede ayudarnos a decidir qué funciones deben eliminarse.
También podríamos hacer una lista de errores, que podríamos revisar y hacer la pregunta opuesta:
"¿Cómo dificulta este error la edición de texto de los programadores?" A veces, la respuesta es obvia,
por lo que realmente no es necesario escribirla. Por ejemplo, si el programa falla cuando intenta
guardar un archivo, no necesita explicar por qué está mal.
Hay muchas otras formas de aplicar el propósito del software en el trabajo diario; Estos son solo
algunos ejemplos.
CAPÍTULO 3
El futuro
La pregunta principal que enfrentan los diseñadores de software es "¿Cómo tomo decisiones sobre
mi software?" Cuando te enfrentas a muchas direcciones posibles en las que podrías ir, ¿cuál es
la mejor opción? Nunca se trata de qué decisión sería absolutamente correcta versus qué decisión
sería absolutamente incorrecta. En cambio, lo que queremos saber es: "Dadas muchas decisiones
posibles, ¿cuáles de esas decisiones son mejores que otras?" Es una cuestión de clasificar las
decisiones y luego elegir la mejor decisión entre todas las posibilidades.
Por ejemplo, un diseñador podría preguntarse: “Hay 100 características diferentes en las que
podríamos trabajar hoy, pero solo tenemos la mano de obra para trabajar en dos. ¿En cuáles
deberíamos trabajar primero?”.
dónde:
D
Representa la conveniencia de un cambio. ¿Cuánto queremos hacer algo?
V
Representa el valor de un cambio. ¿Qué tan valioso es este cambio? Por lo general,
determinaría esto preguntando "¿Cuánto ayuda esto a nuestros usuarios?" aunque también
existen otros métodos para determinar el valor.
mi
Representa el esfuerzo que implica realizar el cambio. ¿Cuánto trabajo requerirá el cambio?
9
Machine Translated by Google
No dice si un cambio es absolutamente correcto o incorrecto; en cambio, le dice cómo clasificar sus
opciones. Los cambios que traerán mucho valor y requerirán poco esfuerzo son “mejores” que aquellos
que traerán poco valor y requerirán mucho esfuerzo.
Valor
¿Qué queremos decir con "valor" en la ecuación? La definición más simple de valor sería:
Las personas más importantes para ayudar son sus usuarios. Sin embargo, escribir características que
lo ayudarán a mantenerse financieramente también es una forma de valor: es valioso para usted.
De hecho, hay muchas maneras en que un cambio puede tener valor; estos son solo dos ejemplos.
A veces, es difícil determinar el valor numérico real y preciso de cualquier cambio en particular. Por
ejemplo, digamos que su software ayuda a las personas a perder peso. ¿Cómo se mide el valor exacto
de ayudar a alguien a perder peso? No puedes, de verdad. Pero puede saber con precisión que
algunas funciones del software ayudarán a las personas a perder mucho peso y algunas funciones no
ayudarán a las personas a perder peso en absoluto. Por lo tanto, aún puede clasificar los cambios por
su valor.
El valor en realidad se compone de dos factores: la probabilidad de valor (cuán probable es que este
cambio ayude a un usuario) y el valor potencial (cuánto ayudará este cambio a un usuario durante los
momentos en que ayuda a esa persona).
Por ejemplo:
• Una función que podría salvar la vida de alguien, incluso si solo hay una posibilidad entre un millón
de que se necesite, sigue siendo una función muy valiosa. Tiene un alto valor potencial (salvar
una vida), aunque tiene una baja probabilidad de valor.
10 | Capítulo 3: El futuro
Machine Translated by Google
Como otro ejemplo, en un programa de hoja de cálculo puede agregar una función que ayude a
las personas ciegas a ingresar números en el sistema. Solo un pequeño porcentaje de personas
son ciegas, pero sin esta función, no podrían usar su software en absoluto. Nuevamente, esta
característica es valiosa porque tiene un valor potencial muy alto, a pesar de que afecta solo a un
pequeño grupo de usuarios (una probabilidad de valor baja).
• Si hay una característica que hará sonreír al 100% de sus usuarios, esa también es una característica
valiosa. Tiene un valor potencial muy pequeño (hacer sonreír a la gente), pero afecta a una gran
cantidad de usuarios, por lo que tiene una alta probabilidad de valor.
• Por otro lado, si implementa una característica que tiene solo una probabilidad entre un millón de
hacer sonreír a alguien, eso no es muy valioso. Esa es una característica con un valor potencial
bajo y una probabilidad de valor baja.
• ¿Para cuántos usuarios (qué porcentaje) será valioso este cambio? • ¿Cuál es la
probabilidad de que esta característica sea valiosa para un usuario? O, dijo otro
manera: ¿con qué frecuencia será valiosa esta
función? • Cuando es valioso, ¿cuán valioso será?
Equilibrio de daño
Algunos cambios pueden causar algún daño además de la ayuda que brindan. Por ejemplo, algunos
usuarios pueden molestarse si su software les muestra anuncios, incluso si esos anuncios lo ayudan a
usted como desarrollador.
Calcular el valor de un cambio incluye considerar cuánto daño puede causar y equilibrarlo con la
ayuda que brinda.
Esto también significa que, en la mayoría de los casos, debe lanzar su software para que sea valioso.
Un cambio que toma demasiado tiempo puede terminar teniendo un valor cero, porque no se lanza a
tiempo para ayudar a las personas de manera efectiva. Puede ser importante tener en cuenta los
cronogramas de lanzamiento al determinar la conveniencia de los cambios.
Esfuerzo
El esfuerzo es un poco más fácil de poner en números que el valor. Por lo general, puede describir el
esfuerzo como "una cierta cantidad de horas de trabajo de una cierta cantidad de personas". "Cien
años-persona" es un ejemplo de una medida numérica comúnmente escuchada para el esfuerzo,
representando 100 años de trabajo de 1 persona, 1 año de trabajo de 100 personas, 2 años de trabajo de
50 personas, etc.
Sin embargo, aunque el esfuerzo se puede poner en números, medirlo en situaciones prácticas es muy
complicado, tal vez imposible. Los cambios pueden tener muchos costos ocultos que pueden ser difíciles
de predecir, como el tiempo que dedicará en el futuro a corregir cualquier error que introduzcan los cambios.
Pero si usted es un desarrollador de software experimentado, aún puede clasificar los cambios según el
esfuerzo que probablemente requerirán, incluso si no conoce los números exactos para cada uno.
Al considerar el esfuerzo que implica un cambio, es importante tener en cuenta todo el esfuerzo que podría
implicar, no solo el tiempo que va a dedicar a la programación. ¿Cuánta investigación tomará? ¿Cuánta
comunicación tendrán que ver todos los desarrolladores entre sí? ¿Cuánto tiempo pasará pensando en el
cambio?
En resumen, cada pieza de tiempo relacionada con un cambio es parte del costo del esfuerzo.
Mantenimiento
La ecuación que tenemos hasta ahora es muy simple, pero le falta un elemento importante: el tiempo. No
solo hay que implementar un cambio, sino que también hay que mantenerlo en el tiempo. Todos los cambios
requieren mantenimiento. Esto es muy obvio con algunos cambios: si está escribiendo un programa para
hacer los impuestos de las personas, tendrá que actualizarlo para las nuevas leyes fiscales cada año. Pero
incluso los cambios que no parecen tener un costo de mantenimiento a largo plazo de inmediato lo tendrán,
incluso si es solo el costo de tener que asegurarse de que ese código aún funcione cuando lo esté probando
el próximo año.
También debemos considerar el valor tanto ahora como en el futuro. Cuando implementamos algún cambio
en nuestro sistema, ayudará a nuestros usuarios actuales, pero también puede ayudar a todos nuestros
usuarios futuros. Incluso puede afectar el número total de usuarios futuros, cambiando así cuánto nuestro
software en su conjunto ayuda a las personas.
Algunas características incluso cambian de valor con el tiempo. Por ejemplo, tener un programa fiscal que
comprenda las leyes fiscales del año 2009 es valioso en 2009 y 2010, pero no tanto una vez que llega el
2011. Esa es una característica que se vuelve menos valiosa con el tiempo. Algunas características también
se vuelven más valiosas con el tiempo.
Entonces, al mirar esto de manera realista, vemos que el esfuerzo en realidad involucra tanto el esfuerzo
de implementación como el esfuerzo de mantenimiento, y el valor involucra tanto el valor ahora como el
valor en el futuro. En forma de ecuación, esto se ve así:
dónde:
12 | Capítulo 3: El futuro
Machine Translated by Google
ei
Representa el esfuerzo de implementación.
Em
Representa el esfuerzo de mantenimiento.
vn
Representa valor ahora.
v.f.
Representa el valor futuro.
La ecuación completa
O, en inglés:
Esta es la ley principal del diseño de software. Sin embargo, hay un poco más que saber al respecto.
Reducción de la ecuación El
"valor futuro" y el "esfuerzo de mantenimiento" dependen del tiempo, lo que hace que sucedan cosas
interesantes con la ecuación cuando la aplicamos a una situación del mundo real.
Para demostrar esto, supongamos que podemos usar dinero para resolver la ecuación tanto del valor
como del esfuerzo. El “valor” se medirá por cuánto dinero nos generará el cambio. El “esfuerzo” se
medirá en términos de cuánto dinero nos costará implementar el cambio. No deberías usar la ecuación
de esta manera en el mundo real, pero por el bien de nuestro ejemplo, simplificará las cosas.
Entonces, digamos que tenemos un cambio que queremos hacer donde la ecuación se ve así:
Después de 10 días, el valor futuro acumulado asciende a $10 000 y el esfuerzo de mantenimiento asciende a $1
000. Eso es igual al “valor actual” original y al costo de implementación, después de solo 10 días.
Después de 100 días, el valor futuro asciende a $100 000 y el esfuerzo de mantenimiento llega a
$10,000.
Después de 1000 días, el valor futuro total llega a $1 000 000 y el esfuerzo de mantenimiento asciende a $100 000.
En este punto, el “valor actual” original y el costo de implementación parecen bastante pequeños en comparación.
A medida que pasa el tiempo, serán aún menos
significativo, eventualmente desapareciendo de importancia por completo. Así, a medida que pasa el tiempo
nuestra ecuación se reduce a esto: 1
Y, de hecho, casi todas las decisiones en el diseño de software se reducen por completo a medir la
valor futuro de un cambio frente a su esfuerzo de mantenimiento. Hay situaciones en las que
el valor presente y el esfuerzo de implementación son lo suficientemente grandes como para ser significativos en un
decisión, pero son extremadamente raros. En general, los sistemas de software se mantienen para
siempre que el valor ahora y el esfuerzo de implementación estén garantizados para convertirse
insignificante en casi todos los casos en comparación con el valor y el esfuerzo futuros a largo plazo
de mantenimiento
1 $10 $1,000
2 $100 $100
3 $1,000 $10
4 $10,000 $1
5 $100,000 $0.10
1. Nota opcional para matemáticos: si has estudiado cálculo, te habrás dado cuenta de que estamos empezando
para analizar el límite de la ecuación cuando el tiempo se acerca al infinito. En general, usted debe estar pensando en el
Ecuación de Diseño de Software como si fuera una serie infinita con un límite, no solo una ecuación estática.
Sin embargo, por motivos de simplicidad, se escribe aquí como una ecuación estática.
14 | Capítulo 3: El futuro
Machine Translated by Google
Claramente, ese es un cambio terrible, terrible que nunca deberías haber hecho. si las cosas
Si continúa a ese ritmo, no podrá mantener el sistema en absoluto, se volverá
infinitamente caro y el valor que está ganando cada día se convertirá en $0.
Cualquier situación en la que el esfuerzo de mantenimiento aumenta más rápido que el valor va
para meterte en problemas, incluso si parece estar bien al principio:
1 $1000 $1000
2 $2000 $2000
3 $4000 $3000
4 $8000 $4000
1 $1,000 $0
2 $100 $10
3 $10 $100
4 $0 $1,000
5 $0 $10,000
1 $20 $10
2 $10 $10
3 $5 $10
4 $1 $10
5 $0 $10
Los cambios con un valor futuro más alto son aún más deseables, pero siempre que cada decisión
tiene un costo de mantenimiento que se aproxima a cero con el tiempo, no puede meterse en un
situación futura peligrosa.
Teóricamente, mientras el valor futuro sea siempre mayor que el esfuerzo de mantenimiento,
el cambio sigue siendo deseable. Entonces, podría hacer algún cambio donde el mantenimiento
tanto el esfuerzo como el valor futuro aumentaron, siempre y cuando el valor futuro siguiera siendo
lo suficientemente grande como para compensar el esfuerzo de mantenimiento:
1 $1 $0
2 $2 $2
3 $3 $4
4 $4 $6
5 $5 $8
Tal cambio no es malo, pero es más conveniente hacer un cambio cuyo mantenimiento
el esfuerzo disminuye, incluso si tiene un mayor esfuerzo de implementación. Si el esfuerzo de
mantenimiento disminuye, el cambio se vuelve cada vez más deseable con el tiempo. Que
hace que sea una mejor opción que otras posibilidades.
Esa es una de las cosas más importantes que hay que saber sobre el diseño de software.
Pero, ¿qué causa el esfuerzo de mantenimiento? ¿Cómo diseñamos sistemas cuyo mantenimiento
el esfuerzo disminuye con el tiempo? Ese es el tema de la mayor parte del resto de este libro.
Pero antes de llegar a eso, tenemos que examinar el futuro un poco más.
La respuesta es que habrá mucho más trabajo de programación por hacer, y mucho más
usuarios para ayudar, en el futuro que en el presente. Tu software tendrá que competir
y existen en el futuro, y el esfuerzo de mantenimiento y el número de usuarios crecerán.
16 | Capítulo 3: El futuro
Machine Translated by Google
Cuando ignoramos el hecho de que hay un futuro y hacemos cosas que “simplemente funcionan” en el
presente, nuestro software se vuelve difícil de mantener en el futuro. Cuando el software es difícil de
mantener, es difícil hacer que continúe ayudando a las personas (uno de nuestros objetivos en el diseño
de software). Si no puede agregar nuevas funciones y no puede solucionar los problemas, eventualmente
terminará con un "software incorrecto". Deja de ayudar a sus usuarios y está lleno de errores.
El nivel de calidad de su diseño debe ser proporcional al tiempo futuro en el que su sistema seguirá
ayudando a las personas.
Si está escribiendo un software que se usará solo durante las próximas horas, no tiene que esforzarse
demasiado en su diseño. Pero si su software puede usarse durante los próximos 10 años (y esto sucede
con mucha más frecuencia de lo que podría esperar, incluso si cree que solo se usará durante los
próximos 6 meses), entonces tiene que poner mucho trabajo en el diseño. En caso de duda, diseñe su
software como si fuera a usarse durante mucho, mucho tiempo: no se encierre en ningún método para
hacer las cosas, manténgalo flexible, no tome decisiones que nunca pueda cambiar, y poner mucha
atención en el diseño.
Consecuencias imprevisibles
Entonces, cuando diseñamos software, el futuro debe ser nuestro enfoque principal. Sin embargo, una
de las cosas más importantes que debe saber sobre cualquier tipo de ingeniería es la siguiente:
De hecho, cuando se trata de diseño de software, no se puede saber la mayoría de las cosas sobre el
futuro.
El error más común y desastroso que cometen los programadores es predecir algo sobre el futuro
cuando en realidad no pueden saberlo.
Por ejemplo, imagine que un programador escribió una pieza de software en 1985 que repara los
disquetes rotos. No podía arreglar nada más: cada pieza dependía totalmente de cómo funcionaban
exactamente los disquetes. Ese software ahora sería obsoleto, porque la gente ya no usa disquetes. Ese
programador predijo que "la gente siempre usará disquetes", algo que en realidad no podía saber.
Puede ser posible predecir el futuro a corto plazo, pero el futuro a largo plazo es en gran parte
desconocido. El largo plazo también es más importante para nosotros que el corto plazo, porque nuestras
decisiones de diseño tendrán más consecuencias en ese período más largo.
Consecuencias imprevisibles | 17
Machine Translated by Google
Ahora, eso puede parecer exactamente lo contrario de lo que hemos estado diciendo hasta ahora
en este capítulo, pero no lo es. El futuro es lo más importante a considerar al tomar decisiones de
diseño. Pero hay una diferencia entre diseñar de una manera que permita cambios futuros e
intentar predecir el futuro.
Como analogía, digamos que tienes una simple elección entre comer o morirte de hambre. No
tienes que predecir el futuro para tomar esa decisión, sabes que comer es la mejor decisión. ¿Por
qué? Porque te mantendrá con vida en este momento, y estar vivo hace que el futuro sea mejor
que estar muerto. El futuro es importante y queremos tenerlo en cuenta en nuestras decisiones.
Elegimos comer ahora porque contribuye a un futuro mejor. Pero el futuro no tiene que ser
predicho, no tenemos que decir algo específico como “Estoy comiendo ahora porque mañana
tendré que salvar la vida de un bebé”. Pase lo que pase mañana, será un mejor mañana si comes
ahora en lugar de morirte de hambre.
Hay excepciones limitadas: a veces sabe exactamente lo que sucederá en el futuro a corto plazo
y puede tomar decisiones basadas en eso. Pero si vas a hacer eso, debes estar muy seguro de
ese futuro, y debe estar muy cerca.
No importa cuán inteligente seas, simplemente no hay forma posible de predecir con precisión
futuros a largo plazo.
Tomemos un ejemplo fuera del ámbito de la programación: los CD, que fueron diseñados en 1979
para reemplazar las cintas de casete como método principal para escuchar música. ¿Quién podría
haber predicho que 20 años después, los DVD se fabricarían con el mismo tamaño y forma para
que los fabricantes pudieran fabricar unidades de CD/DVD para computadoras? ¿Y quién podría
haber imaginado los problemas de hacer girar un CD 50 veces más rápido de lo que se supone
que debe girar, cuando se lee en una unidad de CD-ROM?
Por eso, en cualquier tipo de ingeniería, incluido el campo del desarrollo de software, tenemos
"principios rectores". Estas son ciertas reglas que, cuando las seguimos, hacen que las cosas
funcionen bien sin importar lo que suceda en el futuro. Eso es lo que son las leyes y reglas del
diseño de software: nuestros "principios rectores" como diseñadores.
Así que sí, es importante recordar que habrá un futuro. Pero eso no significa que tengas que
predecir ese futuro. En cambio, explica por qué debe tomar decisiones de acuerdo con las leyes
y reglas de este libro, porque conducen a un buen software futuro, sin importar lo que traiga ese
futuro.
Ni siquiera es posible predecir todas las formas en que una ley o regla en particular puede
ayudarlo en el futuro, pero lo ayudará y se alegrará de haberlo aplicado en su trabajo.
Le invitamos a estar en desacuerdo con las leyes, reglas y hechos que lea aquí. Por favor, saque
sus propias conclusiones sobre ellos. Pero se le debe advertir que si no lo hace
18 | Capítulo 3: El futuro
Machine Translated by Google
Consecuencias imprevisibles | 19
Machine Translated by Google
Machine Translated by Google
CAPÍTULO 4
Cambio
Ahora que entendemos la importancia del futuro y que hay algunas cosas que no sabemos ni podemos
saber al respecto, ¿qué podemos saber al respecto?
Bueno, una cosa de la que puede estar seguro es que, a medida que pasa el tiempo, el entorno en
torno a su software cambiará. Nada permanece igual para siempre. Esto significa que su software
tendrá que cambiar para adaptarse al entorno que lo rodea.
Cuanto más tiempo exista su programa, más probable es que alguna parte de él tenga que
cambiar.
A medida que avanza hacia un futuro infinito, comienza a tender hacia un 100% de probabilidad de que
cada pieza de su programa tenga que cambiar. En los próximos cinco minutos, probablemente ninguna
parte de su programa tendrá que cambiar. En los próximos 10 días, una pequeña parte de ella podría.
En los próximos 20 años, probablemente la mayoría (si no todo) tendrá que cambiar.
Es difícil predecir exactamente qué cambiará y por qué. Tal vez escribiste un programa para autos de
4 ruedas, pero en el futuro todos conducirán camiones de 18 ruedas. Tal vez escribiste un programa
para estudiantes de secundaria, pero la educación secundaria se volverá tan mala que los estudiantes
ya no podrán entenderla.
El punto es que no tienes que tratar de predecir qué cambiará; solo necesitas saber que las cosas
cambiarán. Escriba su software de manera que sea lo más flexible posible y podrá adaptarse a cualquier
cambio futuro que surja.
21
Machine Translated by Google
Período analizado 5 años, 2 meses 8 años, 3 meses 13 años, 3 meses 13 años, 4 meses
En esta tabla:
Período analizado
El período de tiempo durante el cual existió el archivo.
Líneas originalmente
Cuántas líneas había en el archivo cuando se escribió originalmente.
creció por
La diferencia entre "Líneas ahora" y "Líneas originalmente".
El número total de veces que un programador realizó algún conjunto de cambios en el archivo
(donde un conjunto de cambios implica cambios en muchas líneas). Por lo general, un conjunto de
los cambios representarán una corrección de errores, una nueva función, etc.
Líneas añadidas
Cuántas veces, a lo largo del historial del archivo, se agregó una nueva línea.
Líneas eliminadas
Cuántas veces, a lo largo del historial del archivo, se eliminó una línea existente.
Líneas modificadas
¿Cuántas veces, a lo largo del historial del archivo, se cambió una línea existente (pero no
recién agregado o eliminado).
22 | Capítulo 4: Cambio
Machine Translated by Google
Cambios totales
La suma de los recuentos de "Líneas añadidas", "Líneas eliminadas" y "Líneas modificadas" para
ese archivo.
Relación de
cambio Cuánto más grande es "Cambios totales" que "Líneas originalmente".
Cuando nos referimos a "líneas" en las descripciones anteriores, eso incluye cada línea en los archivos:
código, comentarios, documentación y líneas vacías. Si tuviera que hacer el análisis sin contar los
comentarios, la documentación y las líneas vacías, una de las principales diferencias que vería es que el
recuento de "Líneas sin cambios" sería mucho menor en proporción a los otros números. (En otras
palabras, las líneas sin cambios son casi siempre comentarios, documentación o líneas vacías).
Lo más importante que hay que darse cuenta de esta tabla es que se producen muchos cambios en un
proyecto de software. Cada vez es más probable que una determinada línea de código cambie a medida
que pasa el tiempo, pero no se puede predecir exactamente qué va a cambiar, cuándo va a cambiar o
cuánto tendrá que cambiar. Cada uno de estos cuatro archivos cambió de maneras muy diferentes (puede
ver esto incluso con solo mirar los números), pero todos cambiaron de manera significativa.
• Si observamos la proporción de cambios, vemos que se dedicó más trabajo a cambiar cada archivo
que a escribirlo originalmente. Obviamente, los recuentos de líneas no son una estimación perfecta
de cuánto trabajo se realizó realmente, pero nos dan una idea general. A veces, la proporción es
enorme; por ejemplo, el archivo 4 tuvo 36 veces más cambios totales que las líneas originales.
• El número de líneas sin cambios en cada archivo es pequeño en comparación con su cuenta de
"Líneas originalmente", e incluso menor en comparación con su cuenta de "Líneas ahora". • Se
pueden producir muchos cambios en un archivo, incluso si solo crece un poco con el tiempo.
Por ejemplo, el archivo 3 creció solo 161 líneas durante 13 años, pero durante ese tiempo el recuento
total de cambios alcanzó las 3047 líneas. • El recuento total de cambios siempre es mayor que el
recuento actual de líneas. En otras palabras, es más probable que haya cambiado una línea en un
archivo que tener una línea en un archivo, una vez que el archivo ha existido durante el tiempo
suficiente.
• En el archivo 3, el número de líneas modificadas es mayor que el número de líneas del archivo original
más el número de líneas añadidas. Las líneas de ese archivo se han modificado con más frecuencia
que las nuevas líneas que se han agregado. En otras palabras, algunas líneas de ese archivo han
cambiado una y otra vez. Esto es común en proyectos con una larga vida útil.
Los puntos anteriores no son todo lo que se puede aprender aquí; hay un análisis mucho más interesante
que se puede hacer con estos números. Lo alentamos a profundizar en estos datos (o calcular números
similares para su propio proyecto) y ver qué más puede aprender.
necesario 2. No hacer que el código sea fácil de cambiar 3. Ser demasiado genérico
Hoy en día existe una regla popular en el diseño de software llamada "No lo vas a necesitar", o
YAGNI para abreviar. Esencialmente, esta regla establece que no debe escribir código antes de
que realmente lo necesite. Es una buena regla, pero está mal llamada. En realidad, es posible que
necesite el código en el futuro, pero como no puede predecir el futuro, aún no sabe cómo debe
funcionar el código. Si lo escribe ahora, antes de que lo necesite, tendrá que rediseñarlo para sus
necesidades reales una vez que comience a usarlo. Así que ahórrese ese tiempo de rediseño y
simplemente espere hasta que necesite el código antes de escribirlo.
Otro riesgo de escribir código antes de que lo necesite es que el código no utilizado tiende a
desarrollar "bit rot". Dado que el código nunca se ejecuta, es posible que se desincronice lentamente
con el resto de su sistema y, por lo tanto, desarrolle errores, y nunca lo sabrá. Luego, cuando
comience a usarlo, tendrá que dedicar tiempo a depurarlo. O, peor aún, puede confiar en el código
nunca antes utilizado y no verificarlo, y puede causar errores a los usuarios. De hecho, la regla aquí
debería expandirse para decir:
No escriba código hasta que realmente lo necesite y elimine cualquier código que no se esté
utilizando.
Es decir, también debe deshacerse de cualquier código que ya no sea necesario. Siempre puede
volver a agregarlo más tarde si se vuelve a necesitar.
Hay muchas razones por las que las personas piensan que deben escribir código antes de que sea
necesario, o conservar el código que no se está utilizando. En primer lugar, algunas personas creen
que pueden eludir la Ley del Cambio programando todas las funciones que cualquier usuario podría
necesitar, ahora mismo. Entonces, piensan, el programa no tendrá que ser cambiado o
24 | Capítulo 4: Cambio
Machine Translated by Google
mejorado en el futuro. Pero esto está mal. No es posible escribir un sistema que nunca
cambie, mientras ese sistema siga teniendo usuarios.
Otros creen que se están ahorrando tiempo en el futuro al hacer un trabajo extra ahora. En
algunos casos esa filosofía funciona, pero no cuando estás escribiendo código que no es
necesario. Incluso si ese código termina siendo necesario en el futuro, es casi seguro que
tendrá que dedicar tiempo a rediseñarlo, por lo que en realidad está perdiendo el tiempo.
una vez, un desarrollador, llamémoslo Max (ejem), pensó erróneamente que podía ignorar esta
regla. En su programa, había cuadros desplegables donde los usuarios podían elegir un valor.
Todas las empresas que utilizaron el programa podían personalizar la lista de opciones que se
mostraba en cada cuadro desplegable. Algunas empresas pueden querer que las opciones sean
nombres de colores. Otros pueden querer que sean nombres de ciudades. Podrían ser cualquier
cosa. Por lo tanto, la lista de opciones válidas debía almacenarse en algún lugar donde cada
empresa pudiera modificarla.
Lo más obvio era almacenar la lista de valores y nada más. Después de todo, eso es todo lo que
se necesitaba. Pero Max decidió almacenar dos cosas: la lista de valores y también información
sobre si cada valor estaba actualmente "activo", es decir, si los usuarios podían seleccionar ese
valor actualmente o si estaba deshabilitado temporalmente.
Sin embargo, Max nunca escribió ningún código para usar la información sobre si cada campo
estaba activo o no. Todas las opciones estaban activas, todo el tiempo, sin importar lo que dijeran
los datos almacenados. Sin embargo, estaba seguro de que estaba a punto de escribir código para
usar la información "activa", tal vez incluso mañana.
Pasaron varios años y el código para manejar los datos "activos" no se escribió. En cambio, los
datos simplemente se quedaron allí, sin usar, confundiendo a las personas y causando errores.
Numerosos clientes y desarrolladores le escribieron a Max, preguntándose por qué no sucedió
nada cuando editaron manualmente la lista de valores y establecieron las opciones como inactivas.
Un desarrollador asumió incorrectamente que el campo "activo" estaba en uso y escribió un código
que lo usaba, aunque el resto del sistema no lo usaba. Esto llegó a los clientes, y comenzaron a
informar errores extraños que requerían mucho trabajo para rastrear.
Resultado neto: varios errores, mucha confusión y trabajo adicional para el desarrollador que
finalmente necesitó el código. ¡Y esta fue una violación relativamente menor de la regla!
Las infracciones graves pueden tener consecuencias considerablemente peores, como la pérdida
de plazos, grandes catástrofes y posiblemente incluso la destrucción de su proyecto de software.
Uno de los grandes asesinos de los proyectos de software es lo que llamamos "diseño rígido". Esto
cuando un programador diseña código de una manera que es difícil de cambiar. Hay dos formas de
obtener un diseño rígido:
Luego, los desarrolladores pasan tres años escribiendo el sistema de acuerdo con este documento.
Mientras trabajan, descubren que el diseño del documento es contradictorio, incompleto y difícil de
implementar. Pero el Hospital tardó un año entero en escribirlo; los desarrolladores no pueden esperar
otro año para revisarlo. Entonces implementan el sistema, siguiendo el documento tan de cerca como
pueden.
El sistema se completa y se entrega a los usuarios por primera vez. Sin embargo, la situación en el
Hospital ha cambiado drásticamente en los últimos cuatro años, y cuando los usuarios comienzan a
usar The Healthcare System, se dan cuenta de que quieren algo completamente diferente. Pero el
sistema se compone de cientos de miles de líneas de código, todas diseñadas rígidamente de acuerdo
con el documento; simplemente no se puede cambiar sin meses o años de esfuerzo.
Entonces el Hospital comienza a escribir un nuevo documento para un nuevo sistema, y el proceso
comienza de nuevo.
El error del Hospital fue intentar predecir el futuro. Asumieron que cualquier decisión que tomaran en
el documento era válida para usuarios reales y continuaría siendo válida cuando se completara el
sistema. Cuando llegó el futuro real, no se parecía en nada a lo que habían predicho, y su sistema fue
un fracaso multimillonario.
Una mejor solución hubiera sido especificar solo una función, o un pequeño conjunto de funciones, y
pedirles inmediatamente a los desarrolladores que las implementaran. Luego podría haber habido un ir
y venir de comunicación y pruebas de usuario a medida que se producía el desarrollo. Cuando se
completó y lanzó el primer conjunto de funciones, podrían haber trabajado en funciones adicionales,
una a la vez, hasta que finalmente tuvieran un sistema que estaba bien diseñado y satisfacía
completamente las necesidades de sus usuarios.
26 | Capítulo 4: Cambio
Machine Translated by Google
un desarrollador que cree un programa que las personas puedan usar para realizar un seguimiento de
las tareas que deben realizar. Para crear una nueva "tarea" en el sistema, los usuarios completan un
formulario con cierta información, como un breve resumen de la tarea y qué tan avanzados están en
ella. Esto almacena datos en una base de datos. Luego, pueden tomar notas sobre su progreso en la
tarea a medida que pasa el tiempo y, finalmente, notar que han completado la tarea.
Hay un campo llamado "Estado" que indica qué tan avanzado está el usuario en la realización de la tarea. Los valores
de este campo son "Ningún trabajo realizado", "En curso", "En espera" y "Completado". Cuando el campo Estado tiene
el valor "Sin trabajo realizado", solo puede cambiar a "En curso". Cuando el campo Estado es "En progreso", puede
cambiar a "En espera" o "Completado". Y cuando está "Completado", solo puede volver a cambiar a "En progreso".
Hay otros 10 campos en este programa con reglas similares. Cada uno contiene información diferente sobre la tarea
(por ejemplo, a quién está asignada, cuál es su fecha límite, etc.).
Para implementar estas reglas, el desarrollador escribe una pieza de código muy larga y continua sin estructura, en un
solo archivo. Él valida cada campo con un código personalizado que es específico para ese campo. Por ejemplo, cada
vez que necesita verificar si el estado es "Completado", literalmente escribe la palabra "Completado" en el código.
Además, el código no está escrito para ser reutilizable. Cuando el programa tiene campos similares, el desarrollador
corta y pega el código y luego lo modifica ligeramente para el nuevo campo.
El código funciona. El archivo tiene una extensión de 3.000 líneas. Carece casi por completo de un diseño.
Llega un nuevo desarrollador y se le asigna el mantenimiento de este proyecto. Rápidamente descubre que este
código es difícil de cambiar; si cambia una parte, también tiene que cambiar muchas otras partes de la misma manera
para que siga funcionando. Para empeorar aún más las cosas, las diversas partes están dispersas sin explicación ni
sistema lógico: simplemente debe leer el archivo completo cada vez que desee realizar un cambio.
Los clientes comienzan a solicitar nuevas funciones. Al principio, el nuevo desarrollador hace todo lo posible para
implementar estas nuevas funciones. Agrega aún más código a este archivo. Termina siendo 5.000 líneas de largo.
Eventualmente, los clientes comienzan a solicitar funciones que simplemente no se pueden implementar con este
diseño. Quieren enviar información de tareas por correo electrónico, pero este código solo lo hace con un formulario.
Todo está diseñado muy específicamente en torno a cómo funciona el formulario: nunca funcionaría con el correo
electrónico.
Empiezan a aparecer competidores que pueden actualizar tareas por correo electrónico. El proyecto empieza a perder
clientes.
La única razón por la que este proyecto sobrevive es que dos desarrolladores pasan un año entero rediseñando solo
este archivo para que se pueda cambiar fácilmente. Ellos hacen todo lo posible para mantenerse al día
con otras solicitudes de funciones mientras están rediseñando, pero la mayor parte de su tiempo se
dedica al rediseño.1
El código debe diseñarse en función de lo que sabe ahora, no de lo que cree que sucederá en el futuro.
Diseño basado únicamente en sus requerimientos inmediatos y conocidos, sin excluir la posibilidad de
requerimientos futuros. Si sabe con certeza que necesita el sistema para hacer X, y solo X, entonces
simplemente diséñelo para hacer X, ahora mismo. Podría hacer otras cosas que no son X en el futuro, y
deberías tener eso en cuenta, pero por ahora el sistema solo debería hacer X.
Al diseñar de esta manera, también ayuda mantener pequeños los cambios individuales. Cuando solo tiene
que hacer un pequeño cambio, es fácil hacer un diseño real en él.
Esto no quiere decir que la planificación sea mala. Cierta cantidad de planificación es muy valiosa en el
diseño de software. Pero incluso si no escribe planes detallados, estará bien siempre que sus cambios sean
siempre pequeños y su código se adapte fácilmente para el futuro desconocido.
Cuando se enfrentan al hecho de que su código cambiará en el futuro, algunos desarrolladores intentan
resolver el problema diseñando una solución tan genérica que (creen) se adaptará a todas las situaciones
futuras posibles. A esto lo llamamos "sobreingeniería".
El diccionario define la ingeniería excesiva como una combinación de "sobre" (que significa "demasiado") e
"ingeniería" (que significa "diseño y construcción"). Entonces, según el diccionario, significa diseñar o
construir demasiado para su situación.
Espera, ¿diseñar o construir demasiado? ¿Qué es "demasiado"? ¿No es el diseño algo bueno?
Bueno, sí, la mayoría de los proyectos podrían usar más diseño, como vimos en "Ejemplo: Código sin
suficiente diseño" en la página 27. Pero de vez en cuando, alguien realmente se involucra y simplemente se
pasa de la raya, algo así como construir un láser orbital. para destruir un hormiguero. Un láser orbital es una
hazaña de ingeniería increíble, pero cuesta una enorme cantidad de dinero, lleva demasiado tiempo
construirlo y es una pesadilla de mantenimiento. ¿Te imaginas tener que subir allí y arreglarlo cuando se
rompa?
28 | Capítulo 4: Cambio
Machine Translated by Google
1. No puede predecir el futuro, por lo que no importa cuán genérica sea su solución, no será lo
suficientemente genérica para satisfacer los requisitos futuros reales que tendrá.
2. Cuando su código es demasiado genérico, a menudo no maneja muy bien los detalles desde la
perspectiva del usuario. Por ejemplo, supongamos que diseña un código que trata todas las entradas
de la misma manera: son solo bytes. A veces, este código procesa texto y, a veces, imágenes, pero
todo lo que sabe es que obtiene bytes. En cierto modo, este es un buen diseño: el código es simple,
autónomo, pequeño, etc.
Pero luego te aseguras de que ninguna parte de tu código distinga entre imágenes y texto. Esto es
demasiado genérico. Cuando el usuario pasa una mala imagen, el error que obtiene es: "Pasó bytes
incorrectos". Debería haber dicho: "Pasó en una mala imagen", pero su código es tan genérico que
no puede decirle eso al usuario. (Hay muchas formas en las que el código genérico puede fallar
cuando se le aplica un uso específico; este es solo un ejemplo).
3. Ser demasiado genérico implica escribir mucho código que no es necesario, lo que nos lleva
Volvamos a nuestro primer defecto.
En general, cuando su diseño hace que las cosas sean más complejas en lugar de simplificarlas, está
haciendo un exceso de ingeniería. Ese láser orbital complicaría enormemente la vida de una persona que
solo necesitaba destruir algunos hormigueros, mientras que un simple veneno para hormigas simplificaría
enormemente la vida de esa persona al eliminar el problema de las hormigas (suponiendo que funcionara).
Ser genérico con las cosas correctas, de la manera correcta, puede ser la base de un diseño de software
exitoso. Sin embargo, ser demasiado genérico puede ser la causa de una complejidad incalculable,
confusión y esfuerzo de mantenimiento. La regla para evitar este defecto es similar a la regla para evitar
diseños rígidos: sea tan genérico como sepa que debe ser en este momento.
Para hacerlo más rápido, los desarrolladores decidieron no enviar todos los correos electrónicos de inmediato.
En cambio, se enviarían en segundo plano después de que el usuario enviara el formulario, utilizando un
código preexistente llamado "Remitente de correo electrónico".
El desarrollador que comenzó a trabajar en este cambio decidió que algunas empresas podrían querer usar
algo que no sea Email Sender. Escribió cientos de líneas de código para permitir a los clientes "conectar"
otros sistemas para realizar trabajos en segundo plano. Ningún cliente había pedido esto nunca; el
desarrollador simplemente predijo que alguien querría este tipo específico de flexibilidad en el futuro.
Eventualmente, el Arquitecto Jefe del programa se hizo cargo del trabajo en este cambio. Eliminó todo el
código para "conectar" otros sistemas, porque no había evidencia
que los usuarios lo querían. Por lo tanto, no había evidencia de que el código debería ser tan genérico
en este momento. Con esas piezas eliminadas, el cambio se volvió mucho más simple.
Han pasado cuatro años desde que se realizó originalmente el cambio y ningún cliente ha necesitado
la capacidad de conectar otros sistemas. De hecho, no había ninguna razón para ser tan genérico.
Es más fácil de explicar con un ejemplo. Así es como lo usaríamos para desarrollar un programa de
calculadora que necesita sumar, restar, multiplicar y dividir:
Este método de desarrollo requiere menos tiempo y menos reflexión que planificar todo el sistema por
adelantado y construirlo todo a la vez. Puede que no sea fácil al principio si está acostumbrado a otros
métodos de desarrollo, pero se volverá fácil con la práctica.
La parte complicada de usar este método es decidir el orden de implementación. En general, debe
elegir lo que sea más simple para trabajar en cada paso, cuando llegue allí. Elegimos la suma primero
porque era la más simple de las cuatro operaciones en general, y la resta en segundo lugar porque
lógicamente se basaba en la suma de una manera muy simple. Posiblemente podríamos haber
escogido la multiplicación en segundo lugar, ya que la multiplicación es solo la acción de sumar muchas
veces. Lo único que no habríamos escogido en segundo lugar es la división, porque pasar de la suma
a la división está demasiado lejos de un salto lógico: es
30 | Capítulo 4: Cambio
Machine Translated by Google
demasiado complejo Por otro lado, pasar de la multiplicación a la división al final fue realmente
muy simple, así que fue una buena elección.
A veces, es posible que incluso necesite tomar una sola característica y dividirla en muchos pasos
pequeños, simples y lógicos para que pueda implementarse fácilmente.
Esto es en realidad una combinación de dos métodos: uno llamado "desarrollo incremental" y otro
llamado "diseño incremental". El desarrollo incremental es un método para construir un sistema
completo haciendo trabajo en partes pequeñas. En nuestra lista, cada paso que comenzó con
"Implementar" fue parte del proceso de desarrollo incremental. El diseño incremental es igualmente
un método para crear y mejorar el diseño del sistema en pequeños incrementos. Cada paso que
comenzaba con "Arreglar el diseño del sistema" o "Planificar" era parte del proceso de diseño
incremental.
CAPÍTULO 5
Defectos y Diseño
En otras palabras, no importa lo bueno o malo que seas como programador, lo cierto es que cuanto más codifiques,
más defectos introducirás. Esto nos permite enunciar una ley llamada Ley de Probabilidad de Defectos:
La posibilidad de introducir un defecto en su programa es proporcional al tamaño de los cambios que le haga.
Esto es importante porque los defectos violan nuestro propósito de ayudar a las personas y, por lo tanto, deben
evitarse. Además, la reparación de defectos es una forma de mantenimiento. Así, aumentar el número de defectos
aumenta nuestro esfuerzo de mantenimiento.
Con esta ley, sin tener que predecir el futuro, podemos ver de inmediato que es probable que hacer pequeños
cambios conduzca a un menor esfuerzo de mantenimiento que hacer grandes cambios. Pequeños cambios =
menos defectos = menos mantenimiento.
Esta ley también se expresa a veces de manera más informal como "No puede introducir nuevos errores si no
agrega o modifica el código".
Lo curioso de esta ley es que parece estar en conflicto con la Ley del Cambio: su software tiene que cambiar, pero
cambiarlo introducirá defectos. Ese es un conflicto real, y es equilibrar estas leyes lo que requiere su inteligencia
como diseñador de software. En realidad, es ese conflicto el que explica por qué necesitamos el diseño y, de
hecho, nos dice cuál es el diseño ideal:
El mejor diseño es el que permite el mayor cambio en el entorno con el menor cambio en el software.
Y eso, de manera bastante simple, resume gran parte de lo que se sabe sobre el buen diseño de software en la
actualidad.
33
Machine Translated by Google
Si no está roto...
De acuerdo, entonces no puede introducir errores en su programa si no agrega o modifica el código, y esa
es una ley importante del diseño de software. Sin embargo, también hay una regla relacionada muy
importante que muchos ingenieros de software han escuchado de una forma u otra, pero que a veces olvidan:
Nunca “arregle” nada a menos que sea un problema y tenga pruebas que demuestren que el problema
realmente existe.
Es importante tener evidencia de los problemas antes de abordarlos. De lo contrario, podría estar
desarrollando características que no resuelven el problema de nadie, o podría estar “arreglando” cosas que
no están rotas.
Si arreglas problemas sin evidencia, probablemente vas a romper cosas. Está introduciendo cambios en su
sistema, lo que traerá consigo nuevos defectos. Y no solo eso, sino que está perdiendo el tiempo y agregando
complejidad a su programa sin motivo alguno.
Entonces, ¿qué cuenta como "evidencia"? Suponga que cinco usuarios informan que cuando presionan el
botón rojo, su programa falla. Bien, eso es suficiente evidencia! Alternativamente, puede presionar el botón
rojo usted mismo y notar que el programa falla.
Sin embargo, el hecho de que un usuario informe algo no significa que sea un problema. Algunas veces, el
usuario simplemente no se habrá dado cuenta de que su programa ya tenía alguna característica, y le pedirá
que implemente algo más innecesariamente. Por ejemplo, supongamos que escribe un programa que ordena
alfabéticamente una lista de palabras y un usuario le pide que agregue una función que ordena
alfabéticamente una lista de letras. Su programa ya lo hace. En realidad, ya hace más que eso; este suele
ser el caso, con este tipo de solicitud confusa. En este caso, el usuario puede pensar que hay un problema
cuando no lo hay. Incluso puede presentar "evidencia" de que no puede ordenar una lista de letras, cuando
en realidad el problema es que no se dio cuenta de que debería usar la función de clasificación de palabras.
Si recibe muchas solicitudes como las anteriores, significa que los usuarios no pueden
encontrar fácilmente las funciones que necesitan en su programa. Eso es algo que
deberías arreglar.
A veces, un usuario informará que hay un error, cuando en realidad es el programa comportándose
exactamente como lo pretendías. En este caso, es una cuestión de reglas mayoritarias. Si un número
significativo de usuarios piensa que el comportamiento es un error, es un error. Si solo una pequeña minoría
(como uno o dos) piensa que es un error, no es un error.
El error más famoso en esta área es lo que llamamos “optimización prematura”. Es decir, parece que a
algunos desarrolladores les gusta hacer que las cosas vayan rápido, ¡pero dedican tiempo a optimizar su
código antes de darse cuenta de que es lento! Esto es como una organización benéfica que envía comida a los ricos.
gente y diciendo: “¡Solo queríamos ayudar a la gente!” Ilógico, ¿no? Están resolviendo un problema que
no existe.
Las únicas partes de su programa en las que debería preocuparse por la velocidad son las partes
exactas que puede mostrar que están causando un problema real de rendimiento para sus usuarios.
Para el resto del código, las principales preocupaciones son la flexibilidad y la simplicidad, no hacerlo
rápido.
Hay infinitas formas de violar esta regla, pero la forma de seguirla es simple: solo obtén evidencia real
de que un problema es válido antes de abordarlo.
No te repitas
Esta es probablemente la regla más conocida en el diseño de software. Probablemente ya lo sepas.
Pero es válido, por lo que se incluye aquí:
En cualquier sistema en particular, cualquier pieza de información debería, idealmente, existir solo
una vez.
Supongamos que tiene un campo llamado "Contraseña" que aparece en 100 pantallas de la interfaz de
usuario de su programa. ¿Qué sucede si desea cambiar el nombre del campo a "Código de acceso"?
Bueno, si ha almacenado el nombre del campo en una ubicación central en su código, arreglarlo requerirá
un cambio de código de una línea. Pero si escribió la palabra "Contraseña" manualmente en las 100
pantallas de la interfaz de usuario, deberá realizar 100 cambios para solucionarlo.
Esto también se aplica a los bloques de código. No debe copiar y pegar bloques de código. En su lugar,
debe usar las diversas piezas de tecnología de programación que permiten que una pieza de código
"utilice", "llame" o "incluya" otra pieza de código existente.
Una de las buenas razones para seguir esta regla es la Ley de Probabilidad de Defectos. Si podemos
reutilizar el código antiguo, no tenemos que escribir ni cambiar tanto código cuando agregamos nuevas
funciones, por lo que introducimos menos defectos.
También nos ayuda con la flexibilidad en nuestros diseños. Si necesitamos cambiar el funcionamiento
de nuestro programa, podemos cambiar parte del código en un solo lugar, en lugar de tener que pasar
por todo el programa y realizar varios cambios.
Gran parte del buen diseño se basa en esta regla. Es decir, cuanto más inteligente pueda ser al hacer
que el código "use" otro código y centralice la información, mejor será su diseño.
Esta es otra área donde tu inteligencia realmente entra en juego en la programación.
No te repitas | 35
Machine Translated by Google
Machine Translated by Google
CAPÍTULO 6
Sencillez
De acuerdo, si nunca cambiamos nuestro software, podemos evitar los defectos por completo. Pero el
cambio es inevitable, especialmente si vamos a agregar nuevas funciones. Por lo tanto, “no cambie
nada” no puede ser la última técnica de reducción de defectos.
Como se explica en el Capítulo 5, si desea evitar defectos en su código, es útil mantener los cambios
pequeños. Pero si quieres ir más allá y eliminar los defectos incluso de tus pequeños cambios, hay otra
ley que te puede ayudar. Y no solo reduce los defectos: mantiene su código mantenible, facilita la
adición de nuevas características y mejora la comprensibilidad general de su código. Esta es la Ley de
la Simplicidad:
Es decir, cuanto más simples sean las piezas, más fácilmente podrás cambiar las cosas en el futuro.
La perfecta facilidad de mantenimiento es imposible, pero es el objetivo por el que se esfuerza: cambio
total o infinito código nuevo sin dificultad.
Sin embargo, es posible que haya notado que esta ley no habla de la simplicidad de todo el sistema,
sino solo de las piezas individuales. ¿Por qué?
Bueno, un programa de computadora de tamaño promedio es tan complejo que ningún ser humano
podría comprenderlo todo a la vez. Solo es posible comprender partes de él. Entonces, en realidad,
siempre tenemos una estructura grande y compleja para todo nuestro programa. Lo que entonces
cobra importancia es que las piezas se puedan entender cuando las miramos. Cuanto más simples
sean las piezas, más probable es que cualquier persona las entienda. Eso es particularmente importante
cuando entregas tu código a otras personas, o cuando te alejas de tu código durante unos meses y
luego tienes que volver y volver a aprender lo que hiciste.
37
Machine Translated by Google
Una analogía de la
arquitectura Imagina que estás construyendo una estructura de acero de 30 pies de altura.
Podrías hacerlo con un montón de vigas pequeñas, que son piezas simples. O podrías forjar
tres piezas de acero enormes y complejas y unirlas.
Con el enfoque de vigas, es fácil fabricar o comprar las piezas individuales. Y si uno se rompe,
simplemente lo reemplaza con una pieza de repuesto idéntica. La construcción es simple, y también
lo es el mantenimiento.
Las tres piezas enormes, por otro lado, tienen que ser cuidadosamente hechas a la medida y
trabajadas extensamente. Cada pieza terminada es tan grande que es difícil encontrarla y reparar
todos sus defectos. Y si, después de terminar el edificio, descubre numerosos defectos en cada
pieza, no puede reemplazarlos: el edificio se caería si quitara alguna pieza. Así que tienes que
soldar parches feos de metal y esperar que todo se mantenga.
Entonces, ¿por qué la gente a veces escribe software en fragmentos grandes y complejos en lugar
de en piezas pequeñas y simples? Bueno, se percibe un ahorro de tiempo con el método de piezas
grandes cuando se crea el software por primera vez. Con un montón de piezas pequeñas, se dedica
mucho tiempo a armarlas. No ves eso con las piezas grandes, hay algunas de ellas, se unen y eso
es todo.
Sin embargo, la calidad del sistema de piezas grandes es mucho menor y pasará mucho tiempo
arreglándolo en el futuro. Será cada vez más difícil de mantener, mientras que el sistema simple se
vuelve cada vez más fácil. A la larga, es la simplicidad lo que es eficiente, no la complejidad.
Entonces, ¿cómo usamos esta ley en el mundo práctico de la programación? Ese es el tema de
gran parte del resto de este libro. Sin embargo, en general, la idea es hacer que los componentes
individuales de su código sean lo más simples posible y luego asegurarse de que permanezcan así
con el tiempo.
Una buena manera de hacer esto es usar el método de diseño y desarrollo incremental presentado
al final del Capítulo 4. Dado que hay un paso de "rediseño" antes de agregar cada característica
nueva, puede usar ese tiempo para simplificar el sistema. Sin embargo, incluso si no está utilizando
ese método, puede tomarse un tiempo entre agregar funciones para simplificar cualquier pieza que
parezca demasiado compleja para usted o sus compañeros desarrolladores.
De una forma u otra, a menudo tiene que tomar lo que ha creado y simplificarlo; no puede confiar
en que su diseño inicial sea siempre el correcto. Tiene que rediseñar partes del sistema
continuamente a medida que surgen nuevas situaciones y requisitos.
38 | Capítulo 6: Simplicidad
Machine Translated by Google
Concedido, esto puede ser una tarea bastante difícil. No siempre se le brindan herramientas simples para escribir
sus programas: los lenguajes son complejos, la computadora en sí es compleja, etc.
Pero esfuércese por la simplicidad con lo que tiene.
Hay una cierta cantidad de trabajo involucrada en realizar esta simplificación, pero en general es mucho más
fácil realizar cambios en un sistema simple que en un sistema complejo, por lo que dedica un poco de tiempo a
la simplificación ahora para ahorrar mucho tiempo más adelante.
A medida que disminuye el esfuerzo de mantenimiento de su sistema, aumenta la conveniencia de todos los
cambios posibles. (Vuelva al Capítulo 3 y eche otro vistazo a la Ecuación del diseño de software si quiere
refrescar su memoria sobre los detalles.) Simplificar su código disminuye el esfuerzo de mantenimiento,
aumentando así la conveniencia de cualquier otro cambio posible.
La simplicidad es relativa
Bien, entonces queremos que las cosas sean simples. Sin embargo, la forma en que defina "simple" realmente
depende de su público objetivo. Lo que es simple para usted puede no serlo para sus compañeros de trabajo.
Además, cuando creas algo, puede parecerte relativamente "simple", porque lo entiendes por dentro y por fuera.
Pero para alguien que nunca lo haya visto antes, puede parecer muy complicado.
Si desea comprender el punto de vista de alguien que no sabe nada sobre su código, busque un código que
nunca haya leído y léalo. Trate de comprender no solo las líneas individuales, sino lo que está haciendo todo el
programa y cómo lo modificaría si tuviera que hacerlo. Esa es la misma experiencia que otras personas tienen al
leer su código. Puede notar que el nivel de complejidad no tiene que ser muy alto antes de que se vuelva
frustrante leer el código de otras personas.
Por eso es bueno tener secciones en la documentación de su código como "¿Nuevo en este código?" que
contienen algunas explicaciones simples que ayudarán a las personas a comprender su código. Estos deben
escribirse como si el lector no supiera nada sobre el programa, porque si la gente es nueva en algo, probablemente
no sepa nada al respecto.
Demasiados proyectos de software estropean esto. Vas a leer la documentación escrita para los desarrolladores,
y se te presenta una gran cantidad de enlaces y ninguna dirección.
Esto parece simple para el desarrollador del proyecto desde hace mucho tiempo, porque una página con muchos
La simplicidad es relativa | 39
Machine Translated by Google
de enlaces permite que el desarrollador vaya rápidamente a la parte que está buscando. Pero para
alguien nuevo en el proyecto, es complicado. Por otro lado, para el desarrollador veterano, agregar una
página con botones grandes y simples y eliminar esa lista de enlaces aumentaría la complejidad de su
tarea, porque su objetivo principal será encontrar algo muy específico muy rápido. en la documentación.
Lo único peor que la documentación compleja es la falta de documentación, donde solo se espera que
lo descubras por ti mismo o que "ya sepas" cómo funciona el código. Para el desarrollador, la forma en
que funciona su programa es obvia, pero para otros es totalmente desconocida.
El contexto también es importante. Por ejemplo, en el contexto del código del programa, las tecnologías
avanzadas a menudo conducen a la simplicidad, si se usan correctamente. Pero imagínese si la
estructura interna avanzada de un programa de este tipo se mostrara directamente en una página web
como la única interfaz para el programa: ¡no sería simple en ese contexto, incluso para el desarrollador!
A veces, lo que parece complejo en un contexto es simple en otro. Mostrar una gran cantidad de texto
explicativo en una valla publicitaria al costado de la carretera sería demasiado complejo: simplemente
no hay tiempo para que los conductores que pasan lean todo ese texto, por lo que sería estúpido ponerlo
allí. Pero en un manual para un programa de computadora, incluir mucho texto explicativo sería mucho
más simple que solo dar una descripción de algo en una oración. Es por eso que este libro no tiene solo
capítulos de una línea; realmente no sería tan simple simplemente decir algo y luego no explicarlo.
Con todos estos diferentes puntos de vista y contextos a considerar, ¿significa esto que lograr la
simplicidad es imposiblemente difícil? ¡No! De nada. Hay audiencias objetivo específicas para todo, y el
contexto de cualquier cosa individual que estés haciendo suele ser bastante limitado. El problema
siempre tiene solución. Es importante tener en cuenta estas consideraciones al diseñar su software, de
modo que cuando alguien llegue a usarlo, realmente sea simple para esa persona en particular.
La guerra de editores
Ha habido numerosos argumentos en el mundo del desarrollo de software sobre cuáles son las mejores
herramientas para un trabajo. A la gente le encantan los diferentes editores de texto, diferentes lenguajes de
programación, diferentes sistemas operativos, etc. Quizás la “guerra” más famosa en el desarrollo de software
es entre los usuarios de dos editores de texto en particular, vi y Emacs.
Los usuarios de cada uno de ellos han afirmado en ocasiones que su editor preferido es fundamentalmente
superior al otro.
En realidad, rara vez existe una herramienta fundamentalmente superior para escribir software; solo hay una
herramienta que las personas en particular encuentran más simple para la tarea en cuestión. Los usuarios de
Emacs consideran que Emacs es la herramienta más sencilla de usar para escribir software, y los usuarios de
vi consideran que vi es la más sencilla. Hasta cierto punto, esto tiene que ver con las diferencias fundamentales
entre los individuos en términos de cómo les gusta trabajar o cómo piensan. Las personas simplemente tienen
diferentes preferencias, y no hay bien o mal. Pero en mayor medida, la sencillez percibida de una herramienta
tiene que ver con la familiaridad: cualquier persona que haya usado una herramienta en particular durante
mucho tiempo probablemente se haya familiarizado mucho con ella, lo que la hace mucho más simple que
cualquier otra herramienta, desde el punto de vista de esa persona. punto de vista. Para que una nueva herramienta parezca
40 | Capítulo 6: Simplicidad
Machine Translated by Google
igualmente simple, esa herramienta tendría que ser extremadamente simple, y los editores de texto de los
programadores rara vez lo son.
Los no programadores probablemente considerarían que ambos editores de texto son complejos más allá de lo
razonable, lo cual es otro ejemplo de cómo la simplicidad es relativa.
Las herramientas pueden tener problemas que las hagan inadecuadas para la
tarea en cuestión o que sean una elección incorrecta por razones de diseño de
software (consulte “Malas tecnologías” en la página 52 en el Capítulo 7). Pero
salvo esos problemas, la relativa simplicidad de una herramienta es lo que
permitirá a un programador individual determinar qué es lo mejor para una situación dada.
Bueno, por supuesto, la simplicidad es relativa. Pero aun así, aún se puede lograr más o menos sencillez.
Desde el punto de vista relativo de su usuario, su producto puede ser difícil de usar, fácil de usar o algo
intermedio. Asimismo, desde el punto de vista de otro programador, su código puede ser relativamente
difícil o fácil de leer.
¿Honestamente?
Lo bueno de ese nivel de simplicidad es que, en su mayor parte, cualquier cosa que pueda usar la gente
normal también lo pueden usar los genios. Obtiene una gama mucho más amplia de posibles
usuarios
Pero a menudo, la gente realmente no entiende cuán estúpidos, tontos y simples tienen que ser para
llegar a ese nivel. Veamos un ejemplo. Cuando estás en el centro comercial, hay mapas que te dicen
dónde está todo. En los mejores mapas de centros comerciales, hay un gran punto rojo, con las palabras
“ESTÁS AQUÍ” en letras gigantes, justo frente a ti. En los mapas más pobres, hay un pequeño triángulo
amarillo en el medio del mapa que es muy difícil de encontrar, y a un lado hay un texto que explica: "El
pequeño triángulo amarillo significa '¡Estás aquí!'" Agrega esto a la confusión general de tratar de
encontrar algo en estos mapas, y podrías pasar cinco o seis minutos parado frente a la cosa, tratando de
descubrir cómo llegar a donde vas.
Para el tipo que diseñó el mapa, esto puede parecer totalmente razonable. Pasó mucho tiempo
diseñándolo, por lo que claramente era lo suficientemente importante para él como para estar feliz de
pasar varios minutos mirándolo, aprendiendo todo sobre él, averiguándolo, etc. Pero para nosotros, las
personas que realmente estamos usando el mapa, es una parte muy, muy pequeña de nuestra existencia.
¡Solo queremos que sea lo más simple posible, para que podamos usarlo rápidamente y continuar con
nuestras vidas!
Muchos programadores son particularmente malos acerca de esto con su código. Asumen que otros
programadores estarán dispuestos a pasar mucho tiempo aprendiendo todo sobre su código, porque
después de todo, ¡tomó mucho tiempo escribirlo! El código es importante para ellos, ¿no será importante
para todos?
Ahora, los programadores son generalmente un grupo inteligente. Pero sigue siendo un error pensar:
"Oh, otros programadores entenderán todo lo que he hecho aquí sin ninguna simplificación o explicación
de mi código". No es una cuestión de inteligencia, es una cuestión de conocimiento. Los programadores
que son nuevos en su código no saben nada al respecto; tienen que aprender. Cuanto más fácil sea para
ellos aprender, más rápido lo descubrirán y más fácil será para ellos usarlo.
Hay muchas maneras de hacer que su código sea fácil de aprender: documentación simple, diseño
simple, tutoriales paso a paso, etc.
Pero, si su código no es estúpido, tonto y simple de aprender, la gente tendrá problemas con él. Lo
usarán incorrectamente, crearán errores y, en general, estropearán las cosas.
Y cuando todo esto pase, ¿a quién le van a venir a preguntar? ¡Sí tú! Vas a pasar tiempo respondiendo
a todas sus preguntas. (Mmm, suena divertido, ¿no?)
A ninguno de nosotros nos gusta que nos hablen mal o que nos traten como si fuéramos idiotas. Y a
veces eso nos lleva a crear cosas que son un poco complicadas, para que sintamos que no estamos
hablando mal del usuario o de otros programadores. Lanzamos algunas palabras importantes, lo hacemos
un poco menos que simple, y las personas respetan nuestra inteligencia, pero se sienten un poco
estúpidos porque no la entienden. Podrían pensar que somos mucho más inteligentes de lo que podrían
ser, y eso es un poco halagador. Pero realmente, ¿eso les está ayudando?
Por otro lado, cuando haces que tu producto o código sea estúpidamente simple, estás permitiendo que
la gente lo entienda. Eso los hace sentir inteligentes, les permite hacer lo que están tratando de hacer y
no se refleja mal en ti en absoluto. De hecho, la gente probablemente te admirará más si haces las cosas
simples que si las haces complejas.
Ahora, toda su familia no tiene que poder leer su código. La simplicidad sigue siendo relativa, y el público
objetivo del código son otros programadores. Pero para esos otros programadores, su código debería
parecer muy simple y fácil de entender. Puede usar toda la tecnología avanzada que se requiera para
lograr esa simplicidad, pero en última instancia debería ser simple.
Cuando la pregunta “¿Qué tan simple tengo que ser?” surge, también podría preguntarse: "¿Quiero que
la gente entienda esto y sea feliz, o quiero que se sientan confundidos y frustrados?" Si eliges lo primero,
solo hay un nivel de simplicidad que asegurará tu éxito: estúpido, tonto simple.
42 | Capítulo 6: Simplicidad
Machine Translated by Google
Se consistente
La consistencia es una gran parte de la simplicidad. Si haces algo de una manera en un lugar, hazlo de esa
manera en todos los lugares.
Si nombra una variable algo como esto, entonces todas sus variables deben nombrarse de esa manera
(otraVariable, otroNombreComoEse, etc.). Si tiene variables que se llaman_como_este, entonces todas las
variables deben estar en minúsculas y tener guiones bajos entre las palabras.
Podemos ilustrar esto mirando un ejemplo del lenguaje natural. Compara estos
dos oraciones:
• Esta es una oración normal con palabras normales que todos pueden entender. • ESTA ES UNA
ORACIÓN ORMAL CON PALABRAS NORMALES QUE TODO EL CUERPO PUEDE ENTENDER.
Ambas oraciones dicen exactamente lo mismo, pero la primera es mucho más fácil de leer porque es
consistente con la forma en que la mayoría de la gente escribe en inglés. Claro, es posible leer la segunda
oración, pero ¿le gustaría leer un libro completo escrito así?
Derecha. Entonces, ¿le gustaría leer un programa completo escrito sin ninguna consistencia?
Hay situaciones en la programación en las que no importa cómo hagas las cosas, siempre y cuando siempre
las hagas de esa manera. Teóricamente, podrías escribir tu código de una forma loca y compleja, pero
siempre que fueras coherente con él, la gente aprendería a leerlo. (Por supuesto, es mejor ser consistente
y simple, pero si no puede ser totalmente simple, al menos sea consistente).
La coherencia total también puede facilitar la programación en muchos casos. Por ejemplo, si cada objeto
en su programa tiene un campo llamado nombre, puede escribir una pieza de código simple que trate con
el campo de nombre de cada objeto en todo su programa. Pero si en el Objeto A el campo de nombre se
llama a_name y en el Objeto B se llama name_of_mine, tendrá que escribir un código especial para tratar
el Objeto A y el Objeto B de manera diferente.
Tal vez las cosas no sean tan consistentes en el mundo real, pero usted está a cargo del mundo de su
programa, por lo que puede hacer que las cosas sean simples y consistentes.
Sea consistente | 43
Machine Translated by Google
Hay algunos ejemplos de consistencia en el mundo real. En gran parte de Asia, la gente usa palillos para
comer. En las Américas y Europa, la gente usa tenedores. De acuerdo, son dos métodos diferentes de
comer, pero en general es bastante consistente, en cualquier área determinada. Ahora imagina si cada
vez que vas a la casa de alguien, tienes que aprender una nueva forma de comer. Tal vez en casa de Bob
se come con tijeras, y en casa de Mary se come con cartones planos. Comer se volvería bastante
complejo, ¿no?
Es lo mismo en la programación: sin consistencia, las cosas se vuelven muy complejas. Con consistencia,
se vuelven simples. E incluso si no son simples, al menos puedes aprender la complejidad solo una vez,
y luego la sabes para siempre.
Legibilidad
Como se ha dicho muchas veces en el mundo del desarrollo de software, el código se lee más a menudo
de lo que se escribe. Por lo tanto, es importante hacer que el código sea fácil de leer:
La legibilidad del código depende principalmente de cómo el espacio está ocupado por letras y
símbolos.
Si todo el universo fuera negro, no serías capaz de diferenciar los objetos. Todos serían una sola masa
negra. De la misma manera, si un archivo completo es una masa de código sin suficiente espacio lógico y
consistente, es difícil separar las piezas. El espacio es lo que mantiene las cosas separadas.
No desea demasiado espacio, porque entonces es difícil saber cómo se relacionan las cosas.
Y no quieres muy poco, porque entonces es difícil decir que las cosas están separadas.
No existe una regla estricta sobre cómo se debe espaciar exactamente el código, excepto que debe
hacerse de manera consistente y el espaciado debe ayudar a informar al lector sobre la estructura del
código.
Ejemplo: Espacios
Este código es difícil de leer porque tiene muy poco espacio; se proporciona muy poca información
sobre la estructura del código:
x=1+2;y=3+4;z=x+y;if(z>y+x){imprimir"error";}
Aquí está el mismo bloque de código con demasiado espacio: el espacio impide que el lector vea
la estructura del código:
X = 1+ 2;
y=3 +4;
z=x + y;
si (z > { y+x)
imprime "error"; }
44 | Capítulo 6: Simplicidad
Machine Translated by Google
x = 1 + 2;
y = 3 + 4;
z = x + y;
if (z > y + x)
{ imprime "error";
}
Eso es mucho más fácil de leer y te ayuda a darte cuenta de cómo el programador pretendía que se
diseñara el programa. Se establecen tres variables y luego, en alguna condición, se genera un error.
Esa es la estructura del sistema, aclarada al lector por la forma en que el programador usó el espacio.
Hacer que el código sea fácil de leer también ayuda a que sea fácil de arreglar. En el ejemplo anterior,
cuando el código está debidamente espaciado, podemos ver fácilmente que z nunca será mayor que
y + x, porque z siempre es igual a y + x. Por lo tanto, el bloque que comienza con if (z > y + x) debe
eliminarse, ya que no es necesario.
En general, si tiene un código con muchos errores que también es difícil de leer, lo primero que debe
hacer es hacerlo más legible. Entonces puedes ver más claramente dónde están los errores.
son.
Nombrar cosas
Una parte importante de la legibilidad es dar buenos nombres a las variables, funciones, clases,
etc. Idealmente:
Los nombres deben ser lo suficientemente largos para comunicar completamente qué es o
qué hace algo sin ser tan largos que se vuelvan difíciles de leer.
Legibilidad | 45
Machine Translated by Google
Ejemplo: nombres
Aquí hay un código con nombres realmente pobres:
Esos nombres no comunican qué son las variables o qué hacen las funciones.
Aquí está el mismo código con buenos nombres:
Y aquí está el mismo código nuevamente, con nombres que son tan largos que son difíciles de leer:
total_trimestral_para_la_compañía_en_2011_como_de_hoy
= sumar_todos_estos_juntos_y_devolver_el_resultado(cantidad_total_de_enero,
cantidad_total_de_febrero, cantidad_total_de_marzo);
enviar_a_la_pantalla_y_no_esperar_a_el_usuario_para_responder(total_trimestral_para_la_compañía_en_2011_a_día_hoy);
Esos nombres ocupan demasiado espacio, lo que los hace difíciles de leer. Así, en cierto modo, nombrar
las cosas también se remonta a cómo las letras y los símbolos ocupan el espacio.
Comentarios
Tener buenos comentarios en el código es una gran parte de hacerlo legible. Sin embargo,
generalmente no debe agregar comentarios que digan lo que está haciendo un fragmento de código.
Eso debería ser obvio al leer el código. Si no es obvio, el código debe simplificarse.
Solo si no puede simplificar el código, debe tener un comentario que explique lo que hace.
El propósito real de los comentarios es explicar por qué hiciste algo, cuando la razón no es obvia. Si
no explica eso, otros programadores pueden confundirse, y cuando vayan a cambiar su código,
pueden eliminar partes importantes si esas partes no parecen tener una razón para existir.
Algunas personas creen que la legibilidad es el principio y el fin de la simplicidad del código: que si
su código es fácil de leer, ha hecho todo lo que necesita hacer como diseñador. Eso no es cierto:
puede tener un código muy legible y aun así tener un sistema demasiado complejo.
Sin embargo, hacer que su código sea legible es muy importante y, por lo general, es el primer paso
que se debe dar en el camino hacia un buen diseño de software.
Si su proyecto carece de un buen diseño y continúa creciendo, eventualmente terminará con una
complejidad excesiva. Esto es difícil de imaginar para ciertas personas—algunos
46 | Capítulo 6: Simplicidad
Machine Translated by Google
No puedo imaginar que haya un futuro más allá del almuerzo, y otros simplemente no han tenido
suficiente experiencia para comprender cuán complejas pueden ser las cosas. Y puede haber una
cultura corporativa que diga: “Oh, solo pirateamos nuevas funciones; deberíamos hacer las cosas
bien, pero no podemos porque bla, bla, bla”. Pero un día, su proyecto fracasará. Y no importa
cuántas razones pueda dar para ese fracaso, no cambiará el hecho de que su proyecto fracasó.
Por el otro lado de las cosas, cuando ha diseñado bien, a menudo no hay mucho crédito que se le
presente. Las fallas catastróficas en el diseño son grandes y notorias, mientras que los pequeños
incrementos de trabajo hacia un buen diseño son invisibles para las personas que no están
íntimamente conectadas con el código. Esto puede hacer que ser diseñador sea un trabajo difícil.
Manejar un gran fracaso te da muchas gracias, pero evitar que ocurra uno... bueno, es probable que
nadie se dé cuenta.
Entonces, vamos a felicitarte aquí. ¿Pensaste un poco en el diseño? ¡Excelente! Sus usuarios y
compañeros desarrolladores verán los beneficios: software que funciona, lanzamientos a tiempo y
una base de código clara y comprensible. Se sentirá confiado en su propio trabajo y se irá a casa
sintiéndose realizado. ¿Sabrán los otros desarrolladores cuánto trabajo se necesitó para que todo
funcionara tan bien? Tal vez no. Pero eso está bien. Hay otras recompensas en el mundo además
de las felicitaciones de tus compañeros.
Sin embargo, de vez en cuando obtendrás algún reconocimiento por todo tu trabajo. No se
desespere, alguien se dará cuenta eventualmente. Y hasta entonces, disfrute de todos los demás
resultados positivos del diseño efectivo y correcto.
Cuando comience a aplicar los principios de diseño de este libro a su proyecto, es posible
que a algunos de sus programadores o colegas jóvenes les tome mucho tiempo comprender
por qué también deben diseñar bien. Hacer que lean este libro ayudará. Si no pueden o no
quieren leerlo, siga guiándolos (o obligándolos, en el peor de los casos) hacia buenas
decisiones de diseño, y verán después de un par de años (en el exterior) qué tan bien valen
las buenas decisiones de diseño. .
CAPÍTULO 7
Complejidad
Cuando trabajas como programador profesional, es probable que conozcas a alguien (¡o eres alguien!) que está
pasando por esta historia de terror de desarrollo común: "Comenzamos a trabajar en este proyecto hace cinco
años, y la tecnología que estábamos usando/haciendo Era moderno entonces, pero ahora está obsoleto. Las cosas
se vuelven cada vez más complejas con esta tecnología obsoleta, por lo que cada vez es menos probable que
terminemos el proyecto. ¡Pero si reescribimos, podríamos estar aquí por otros cinco años!”.
Otro popular es: "No podemos desarrollarnos lo suficientemente rápido para mantenernos al día con las necesidades
de los usuarios modernos". O, "Mientras estábamos desarrollando, la Compañía X escribió un producto mejor que
el nuestro mucho más rápido que nosotros".
Ahora sabemos que la fuente de estos problemas es la complejidad. Comienza con un proyecto simple que se
puede completar en un mes. Luego agrega complejidad y la tarea llevará tres meses. Luego tomas cada parte de
eso y lo haces más complejo, y la tarea tomará nueve meses.
La complejidad se basa en la complejidad, no es solo algo lineal. Es decir, no puede hacer suposiciones como:
"Tenemos 10 funciones, por lo que agregar 1 más solo agregará un 10 por ciento más de tiempo". De hecho, esa
nueva función tendrá que coordinarse con las 10 funciones existentes. Por lo tanto, si se necesitan 10 horas de
tiempo de codificación para implementar la función en sí, es posible que se necesiten otras 10 horas de tiempo de
codificación para que las 10 funciones existentes interactúen correctamente con la nueva función. Cuantas más
funciones haya, mayor será el costo de agregar una función. Puede minimizar este problema si tiene un excelente
diseño de software, pero siempre habrá un pequeño costo adicional por cada función nueva.
Algunos proyectos comienzan con un conjunto de requisitos tan complejo que nunca obtienen una primera versión.
Si se encuentra en esta situación, solo debe recortar las características. No apunte a la luna en su primer
lanzamiento: obtenga algo que funcione y haga que funcione mejor con el tiempo.
49
Machine Translated by Google
También hay otras formas de agregar complejidad además de simplemente agregar características. Las otras
formas más comunes son:
Agregar programadores
Sí, así es, agregar más personas al equipo no simplifica las cosas; en cambio, agrega complejidad. Hay
un libro famoso llamado The Mythical Man Month de Fred Brooks, que señala esto. Si tiene 10
programadores, agregar un undécimo significa pasar tiempo para disfrutar de ese programador, más
tiempo para disfrutar de los 10 programadores existentes para la nueva persona, más el tiempo que la
nueva persona dedica a interactuar con los 10 programadores existentes, y así y así sucesivamente. Es
más probable que tenga éxito con un pequeño grupo de programadores expertos que con un grupo
grande de programadores inexpertos.
Malentendidos Los
programadores que no entienden completamente su trabajo tienden a desarrollar sistemas complejos.
Puede convertirse en un círculo vicioso: los malentendidos conducen a la complejidad, lo que conduce a
más malentendidos, y así sucesivamente. Una de las mejores maneras de mejorar sus habilidades de
diseño es asegurarse de comprender completamente los sistemas y las herramientas con las que está
trabajando. Cuanto mejor los entienda, y cuanto más sepa sobre el software en general, más simples
pueden ser sus diseños.
50 | Capítulo 7: Complejidad
Machine Translated by Google
adecuadamente y no puede hacerse cargo del mantenimiento de las mismas (porque, por ejemplo, no
Todos estos factores son lenta y gradualmente dañinos para su proyecto, no inmediatamente destructivos. La
mayoría de ellos solo causan daños a largo plazo, algo que no verá durante un año o más, por lo que cuando
alguien los propone, a menudo suenan inofensivos. E incluso cuando comienzas a implementarlos, pueden
parecer correctos. Pero a medida que pasa el tiempo, y particularmente a medida que se acumulan más y más,
la complejidad se vuelve más evidente y crece y crece y crece, hasta que eres otra víctima de esa historia de
terror tan común, El producto que nunca se envía.
Complejidad y Propósito
El propósito básico de cualquier sistema en el que esté trabajando debería ser bastante simple.
Eso ayuda a mantener el sistema en su conjunto tan simple como puede ser de manera realista. Pero si
comienzas a agregar funciones que cumplen algún otro propósito, las cosas se vuelven muy complejas muy rápidamente.
Por ejemplo, el propósito básico de un procesador de textos es ayudarte a escribir cosas. Si de repente
hiciéramos que también pudiera leer su correo electrónico, sería ridículamente complicado.
¿Te imaginas cómo sería la interfaz de usuario? ¿Dónde pondrías todos los botones? Diríamos que esto es una
violación del propósito de su procesador de textos. Ni siquiera ampliaste su propósito; acabas de agregar
características que no tienen nada que ver con eso.
También es importante pensar en el propósito del usuario. Tu usuario intentará hacer algo. Idealmente, el
propósito de un programa debería estar muy cerca (en las palabras exactas
Complejidad y Propósito | 51
Machine Translated by Google
usaría para describirlo) al propósito del usuario. Por ejemplo, digamos que el propósito del usuario es
hacer sus impuestos. Ella quiere un software cuyo propósito sea ayudar a las personas a hacer sus impuestos.
Si su propósito y el propósito del usuario no coinciden, probablemente le esté haciendo la vida difícil. Por
ejemplo, si quiere leer su correo electrónico, pero el propósito principal del programa que está usando es
mostrar anuncios a los usuarios, esos propósitos no coinciden.
¿Quieres ver a tu usuario enfadarse muy rápido? Haz que sea difícil para ella lograr su propósito. Abre
ventanas en su cara cuando está tratando de hacer algo. Agregue tantas funciones a su programa que no
pueda encontrar la adecuada. Usa muchos íconos extraños que ella no entienda. Hay muchas formas de
hacerlo, pero todas se reducen a interferir con el propósito del usuario o violar el propósito básico del
programa en sí.
A veces, los especialistas en marketing o los gerentes tienen objetivos para un programa que no están
realmente alineados con el propósito básico del programa, como "ser lindo", "tener un diseño vanguardista",
"volverse popular entre los medios de comunicación", "usar las últimas tecnologías". ," y así. Estas
personas pueden ser importantes para su organización, ¡pero no son las personas que deberían decidir
qué hace su programa! Como diseñador de software o gerente técnico, es su trabajo asegurarse de que
el programa se mantenga encaminado y nunca viole su propósito básico.
Nadie más va a tener esa responsabilidad. A veces es posible que realmente tengas que luchar por ello,
pero a la larga vale la pena.
Y no es como si hubieras llegado a un fracaso de marketing con esa filosofía. Hay muchos, muchos
productos que han tenido mucho éxito al apegarse a un solo propósito. El propósito del jabón es
simplemente limpiar las cosas. La sal solo hace que las cosas sean saladas. Una bombilla simplemente
ilumina las cosas. Pero todos estos son productos que han respaldado a corporaciones enormes durante
décadas. No es necesario tener un producto complicado para tener un marketing efectivo, solo debe tener
conocimientos y habilidades en marketing, que es un campo completamente separado del diseño de
software.
Realmente, no hay necesidad de volverse sofisticado y complejo e intentar hacer 500 cosas a la vez en un
solo programa. Los usuarios están más contentos con un producto enfocado y simple que nunca viola su
propósito básico.
Malas tecnologías
Otra fuente común de complejidad es elegir la tecnología incorrecta para usar en su sistema, en particular
una que termina por no cumplir con los requisitos futuros.
Sin embargo, puede ser complicado saber, sin poder predecir el futuro, qué tecnología debe elegir ahora.
Afortunadamente, hay tres factores que puede observar para determinar si una tecnología es "mala"
incluso antes de comenzar a usarla: potencial de supervivencia, interoperabilidad y atención a la calidad.
52 | Capítulo 7: Complejidad
Machine Translated by Google
Potencial de supervivencia
Puede hacerse una idea del potencial de supervivencia de una pieza de software mirando su
historial de lanzamiento reciente. ¿Los desarrolladores han estado presentando con frecuencia
nuevas versiones que resuelven problemas reales de los usuarios? Además, ¿qué tan receptivos
son los desarrolladores a los informes de errores? ¿Tienen una lista de correo o un equipo de
soporte muy activo? ¿Hay mucha gente en línea hablando de esta tecnología? Si una tecnología
tiene mucho impulso ahora, puede estar bastante seguro de que no va a morir pronto.
Popularidad
Puede parecer que estamos diciendo que debe elegir la tecnología más popular que se adapte
a sus necesidades. Hasta cierto punto, esto es cierto: las tecnologías populares tienen un gran
potencial de supervivencia. Sin embargo, debe observar la diferencia entre las herramientas que
son válidamente populares y las herramientas que son populares solo porque tienen algún tipo
de monopolio.
Sin embargo, algunas tecnologías son populares solo porque usted debe usarlas.1 Suponga que
la Compañía X diseña su propio lenguaje de programación. Luego diseña un dispositivo popular
que acepta solo programas escritos en ese idioma. Este es el caso de "un proveedor" mencionado
en el texto: el lenguaje puede parecer popular, pero en realidad tiene un potencial de
supervivencia bajo a menos que sea aceptado ampliamente en la industria del software.
Interoperabilidad La
interoperabilidad es una medida de lo fácil que es cambiar una tecnología si es necesario. Para tener una idea
de la interoperabilidad de una tecnología, pregúntese: "¿Podemos interactuar con esta tecnología de alguna
manera estándar, de modo que sea fácil cambiar a otro sistema que siga el mismo estándar?"
1. Los desarrolladores pueden ser muy apasionados por las tecnologías con las que trabajan. Para evitar ofender a los usuarios de
ciertas tecnologías, no se menciona ninguna tecnología específica aquí.
malas tecnologías | 53
Machine Translated by Google
Por ejemplo, existen estándares internacionales sobre cómo un programa debe interactuar con un
sistema de base de datos. Algunos sistemas de bases de datos admiten muy bien estos estándares.
Si elige uno de estos buenos sistemas de base de datos, puede cambiar a otro sistema de base
de datos en el futuro con solo cambios menores en su programa.
Sin embargo, algunos otros sistemas de bases de datos no son muy buenos para admitir
estándares. Si desea cambiar entre sistemas de bases de datos que no admiten estándares,
deberá reescribir su programa. Por lo tanto, cuando elige uno de estos sistemas no estándar, está
bloqueado y no podrá cambiar fácilmente a un sistema diferente.
Atención a la calidad
Esta es más una medida subjetiva, pero la idea es ver si el producto ha mejorado en sus
lanzamientos recientes. Si puede ver el código fuente, verifique si los desarrolladores están
refactorizando y limpiando la base de código. ¿Se está volviendo más fácil de usar o más complejo?
¿Las personas que mantienen la tecnología realmente se preocupan por la calidad de su producto?
¿Ha habido recientemente muchas vulnerabilidades de seguridad graves en el software que
parecen ser el resultado de una mala programación?
Otras razones
Hay otros aspectos a considerar cuando elige una tecnología, principalmente su simplicidad y qué
tan adecuada es para sus propósitos. La opinión personal también puede desempeñar un papel,
después de haber tenido en cuenta todas las consideraciones prácticas. A algunas personas les
gusta la forma en que un lenguaje de programación se ve mejor que la forma en que lo hace otro.
A veces, esa puede ser una razón válida para elegir una tecnología: si simplemente le gusta una
tecnología más que otra, y todo lo demás es igual entre ellas, elija la que lo haga feliz. Después de
todo, usted es quien lo va a usar, ¡su opinión importa! Las pautas anteriores lo ayudarán a eliminar
las opciones definitivamente malas; el resto depende de su investigación personal, requisitos y
deseos.
Por ejemplo, es muy difícil hacer que un automóvil conduzca rápido si tiene ruedas cuadradas.
Afinar el motor no va a resolver el problema: debe rediseñar el automóvil para que sus ruedas sean
redondas.
Cada vez que hay una "complejidad irresoluble" en su programa, es porque hay algo
fundamentalmente mal con el diseño. Si el problema parece irresoluble en un nivel, retroceda y
observe qué podría estar detrás del problema.
54 | Capítulo 7: Complejidad
Machine Translated by Google
Los programadores en realidad hacen esto con bastante frecuencia. Es posible que te encuentres
diciendo: "Tengo este código terriblemente desordenado, ¡y es realmente complejo agregar una nueva
función!" Bueno, tu problema fundamental es que el código está desordenado. Límpielo, simplifique el
código ya existente y encontrará que agregar la nueva característica también será simple.
Entonces, cuando las cosas se compliquen, retroceda y observe el problema que está tratando de
resolver. Da un gran paso atrás. Se le permite cuestionar todo. Tal vez pensaste que sumar dos y dos
era la única manera de obtener cuatro, y no pensaste en sumar uno y tres en su lugar, o saltearte la
suma por completo y solo poner cuatro ahí. El problema es, "¿Cómo obtengo el número cuatro?"
Cualquier método para resolver ese problema es aceptable, por lo que lo que debe hacer es averiguar
cuál sería el mejor método para la situación en la que se encuentra.
Desecha tus suposiciones. Mire realmente el problema que está tratando de resolver. Asegúrese de
comprender completamente todos los aspectos y luego descubra la forma más sencilla de resolverlo.
No preguntes, "¿Cómo resuelvo este problema usando mi código actual?" o "¿Cómo resolvió la
profesora Anne este problema en su programa?" No, solo pregúntese: "¿Cómo, en general, en un
mundo perfecto, debería resolverse este tipo de problema?" A partir de ahí, es posible que vea cómo
su código necesita ser reelaborado. Entonces puedes reelaborar tu código.
Entonces puedes resolver el problema.
Problemas complejos A
veces se le pedirá que resuelva un problema que es intrínsecamente muy complejo, por ejemplo,
revisar la ortografía o hacer que una computadora juegue al ajedrez. Esto no significa que su solución
tenga que ser compleja, pero sí significa que tendrá que trabajar más de lo habitual para simplificar su
código cuando se enfrente a este problema.
Si tiene problemas con un problema complejo, escríbalo en un papel en un lenguaje sencillo o dibújelo
como un diagrama. Parte de la mejor programación se hace en papel, de verdad. Ponerlo en la
computadora es solo un detalle menor.
Problemas complejos | 55
Machine Translated by Google
Manejo de la complejidad
Como programador, se encontrará con la complejidad. Otros programadores escribirán programas
complejos que tendrás que arreglar. Los diseñadores de hardware y los diseñadores de idiomas le
harán la vida difícil.
Si alguna parte de su sistema es demasiado compleja, existe una forma específica de solucionarlo:
rediseñe las piezas individuales, en pequeños pasos. Cada arreglo debe ser tan pequeño como
puedas hacerlo de manera segura sin introducir mayor complejidad. Cuando está pasando por este
proceso, el mayor peligro es que posiblemente pueda introducir más complejidad con sus arreglos.
Esta es la razón por la que tantos rediseños o reescrituras finalmente fallan: introducen más
complejidad de la que solucionan, o terminan siendo tan complejos como el sistema original.
estaba.
Cada paso puede ser tan pequeño como dar un mejor nombre a una sola variable, o simplemente
agregar algunos comentarios a un código confuso. Pero más a menudo, los pasos implican dividir una
pieza compleja en múltiples piezas simples.
Por ejemplo, si tiene un archivo largo que contiene todo su código, comience a mejorarlo dividiendo
una pequeña parte en un archivo separado. Luego mejora el diseño de esa pequeña pieza. Luego
divida alguna otra pequeña parte del sistema en un nuevo archivo y mejore su diseño. Continúe así y
eventualmente terminará con un sistema confiable, comprensible y mantenible.
Si su sistema es muy complejo, esto puede requerir bastante trabajo, por lo que debe tener paciencia.
Primero debe concebir un sistema que sea más simple que el que tiene ahora, aunque solo sea en
pequeña medida. Luego trabaja hacia ese sistema más simple, paso a paso. Una vez que alcanzas
ese sistema más simple, vuelves a concebir un sistema aún más simple y trabajas para lograrlo.
Nunca tienes que concebir el sistema “perfecto”, porque no existe tal cosa. Solo tiene que trabajar
continuamente para lograr un sistema que sea mejor que el que tiene ahora y, eventualmente,
alcanzará un nivel de simplicidad altamente manejable.
Sin embargo, es importante tener en cuenta que no puede dejar de escribir funciones y pasar mucho
tiempo simplemente rediseñando. La Ley del Cambio nos dice que el entorno alrededor de su
programa cambiará continuamente y, por lo tanto, la funcionalidad de su programa debe adaptarse.
Si no logra adaptarse y mejorar desde la perspectiva del usuario durante un período de tiempo
significativo, corre el riesgo de perder su base de usuarios y la muerte de su proyecto.
Hay, afortunadamente, varias formas de equilibrar estas dos necesidades de escribir funciones y
manejar la complejidad. Una de las mejores formas es rediseñar únicamente con el objetivo de hacer
que alguna característica específica sea más fácil de implementar y luego implementar esa
característica. De esa forma, cambia regularmente entre el trabajo de rediseño y el trabajo de
características. Esto también ayuda a que su nuevo diseño se ajuste bien a sus necesidades, porque
lo está creando con un uso real en mente. Con el tiempo, su sistema se volverá menos complejo y
seguirá el ritmo de las necesidades de sus usuarios. Incluso puede hacer esto para los errores: si ve
que algún error sería más fácil de corregir con un diseño diferente, rediseñe el código antes de corregirlo.
56 | Capítulo 7: Complejidad
Machine Translated by Google
Un proyecto llamado Bugzilla almacena todos sus datos en una base de datos. Bugzilla solo
admite un sistema de base de datos en particular para almacenar datos, llamado OldDB. Algunos
clientes nuevos quieren usar un sistema de base de datos diferente para almacenar datos,
llamado NewDB. Estos clientes tienen buenas razones para desear esta función: entienden
NewDB mucho mejor que OldDB y ya tienen NewDB ejecutándose en sus empresas. Pero todos
los clientes existentes quieren seguir usando OldDB.
Entonces, Bugzilla tiene que comenzar a admitir más de una base de datos. Esto requerirá muchos cambios
de código, ya que Bugzilla no tiene ningún código centralizado para almacenar y recibir información de la
base de datos. En cambio, hay muchos comandos de base de datos personalizados repartidos por todo el
código que son específicos de OldDB y no funcionarán en NewDB.
Una opción es esparcir sentencias if por todo el código base, escribiendo código diferente para NewDB y
OldDB en todos los lugares a los que se acceda a la base de datos. Sin embargo, esto duplicaría
aproximadamente la complejidad de todo el código base, y el equipo de Bugzilla está formado por solo unos
pocos programadores a tiempo parcial. Si la complejidad del sistema se duplicaba, ya no podían mantenerlo.
En su lugar, el equipo de Bugzilla decide rediseñar el sistema para que pueda soportar fácilmente múltiples
bases de datos. Este es un gran proyecto. Aquí hay una descripción general de alto nivel de cómo lo logran:
1. Existen algunos comandos de base de datos estándar que funcionan en cualquier sistema de base de
datos, pero no siempre se utilizan. Revise el sistema y corrija un archivo a la vez, cambiándolo para
usar comandos estándar siempre que sea posible.
2. Para los comandos de la base de datos donde no hay una versión estándar, cree funciones que
devuelvan el comando correcto para la base de datos en uso. Se crea una función para un comando
no estándar y luego cada instancia de ese comando no estándar se reemplaza con la llamada de
función. Continúe con este proceso hasta que desaparezcan todas las funciones no estándar.
3. Numerosos fragmentos de código están diseñados completamente en torno a funciones que solo
existen en OldDB. Deje de usar esas funciones específicas de OldDB y, en su lugar, use funciones
estándar que funcionarán en todos los sistemas de bases de datos. Corrija estas características una
a la vez, en varios pasos si es necesario.
4. Rediseñar el sistema de instalación de Bugzilla para que pueda configurarse en cualquier sistema de
base de datos, no solo en OldDB. Esto implica primero rediseñar el sistema de instalación para que
sea más simple y luego ajustar ese código simple para admitir OldDB y NewDB.
Cada paso anterior es un proyecto en sí mismo. Todos se dividen en pasos más pequeños, de modo que
se pueda hacer un buen diseño en cada pieza de trabajo. Además, el sistema se prueba después de realizar
cualquier cambio, para asegurarse de que todavía funciona de la misma manera en OldDB que antes.
¿Resulta esto en un sistema perfecto? No. Pero da como resultado un sistema que es mejor que antes:
además de admitir NewDB, el código ahora es mucho más fácil de usar.
Manejo de la complejidad | 57
Machine Translated by Google
mantener. Eventualmente, Bugzilla se expandió para admitir cuatro sistemas de bases de datos
diferentes, todo porque este trabajo facilitó mucho la compatibilidad con los nuevos.2
anterior está muy bien, pero ¿qué haces realmente para simplificar One Piece?
Bueno, aquí es donde entra en juego todo el conocimiento existente en el mundo sobre el diseño
de software. Es de gran ayuda estudiar patrones de diseño, métodos para tratar con código
heredado y todas las herramientas de la ingeniería de software en general. Puede ser
particularmente útil conocer varios lenguajes de programación y estar familiarizado con muchas
bibliotecas diferentes, ya que cada uno implica diferentes formas de pensar sobre los problemas
que podrían aplicarse a su situación, incluso si no está utilizando esos lenguajes o bibliotecas.
Estudiar esos materiales te dará muchas opciones para elegir cuando te enfrentes a una
complejidad. Las leyes del diseño de software pueden ayudarlo a elegir qué opciones son buenas,
y luego su juicio y experiencia pueden determinar qué hacer realmente con su problema
específico. Nunca aplique una herramienta de manera robótica simplemente porque alguna
autoridad lo haya considerado mejor; siempre haga lo que sea correcto para el código que está
viendo y la situación en la que se encuentra.
A veces, sin embargo, puede mirar un fragmento de código y no conocer ninguna herramienta
para simplificarlo. O puede ser nuevo en la programación y no tener tiempo para estudiar toda
esta información de inmediato. En ese caso, solo debe mirar la complejidad y preguntarse:
"¿Cómo podría ser más fácil de manejar o más comprensible?"
Esa es la pregunta clave detrás de cada simplificación. Cualquier respuesta verdadera es una
forma válida de simplificar su código; las herramientas y técnicas de diseño de software nos
ayudan a encontrar mejores respuestas.
Complejidad irreparable
Cuando está trabajando en la simplificación de su sistema, puede encontrar que cierta complejidad
es difícil de evitar, como la complejidad del hardware subyacente. Si te encuentras con una
complejidad irreparable como esta, tu objetivo es ocultar la complejidad. Ponga un envoltorio a su
alrededor que sea simple para que otros programadores lo usen y lo entiendan.
2. Bugzilla se rediseñó de esta manera muchas veces, durante muchos años, por muchas razones diferentes.
Si desea ver un historial del trabajo principal que se realizó, puede consultar los elementos tachados aquí:
[Link] Si desea obtener más
detalles sobre cómo se realizó el trabajo de la base de datos, consulte los elementos tachados aquí:
[Link] Leer el título de cada
elemento debería darle una idea de cómo se logró el proyecto, si está familiarizado con los sistemas de
bases de datos.
58 | Capítulo 7: Complejidad
Machine Translated by Google
reescritura
Algunos diseñadores, cuando se enfrentan a un sistema muy complejo, lo descartan y comienzan de nuevo. Sin
embargo, reescribir un sistema desde cero es esencialmente admitir el fracaso como diseñador. Está haciendo la
declaración: "No logramos diseñar un sistema mantenible y, por lo tanto, debemos comenzar de nuevo".
Algunas personas creen que todos los sistemas eventualmente deben ser reescritos. Esto no es verdad. Es
posible diseñar un sistema que nunca necesite ser desechado. Un diseñador de software que dice: "Tendremos
que tirarlo todo algún día de todos modos" sería muy parecido a un arquitecto de edificios que dice: "Este
rascacielos se derrumbará algún día de todos modos". Si el rascacielos estuviera mal diseñado y no se mantuviera
bien, entonces sí, algún día se caería. Pero si se construyó correctamente desde el principio y luego se mantuvo
adecuadamente, ¿por qué se derrumbaría?
Es tan posible construir sistemas de software mantenibles como construir rascacielos sólidos.
Ahora, con todo lo dicho, hay situaciones en las que la reescritura es aceptable. Sin embargo, son muy raros. Solo
debe reescribir si todo lo siguiente es verdadero:
1. Ha desarrollado una estimación precisa que muestra que reescribir el sistema será un uso más eficiente del
tiempo que rediseñar el sistema existente. No se limite a adivinar, haga experimentos reales con el rediseño
del sistema existente para ver cómo funciona. Puede ser muy difícil confrontar la complejidad existente y
resolver parte de ella, pero en realidad debe intentarlo varias veces antes de saber cuánto esfuerzo requerirá
arreglar todo.
2. Tiene una enorme cantidad de tiempo para dedicar a la creación de un nuevo sistema.
3. De algún modo, es mejor diseñador que el diseñador original del sistema o, si es el diseñador original, sus
habilidades de diseño han mejorado drásticamente desde que diseñó el sistema original.
4. Tiene toda la intención de diseñar este nuevo sistema en una serie de pasos simples y hacer que los usuarios
quién puede darle retroalimentación para cada paso en el camino.
5. Tiene los recursos disponibles para mantener el sistema existente y diseñar un nuevo sistema al mismo
tiempo. Nunca deje de mantener un sistema que está actualmente en uso para que los programadores
puedan reescribirlo. Los sistemas siempre deben recibir mantenimiento si están en uso. Y recuerde que su
atención personal también es un recurso que debe tenerse en cuenta aquí: ¿tiene suficiente tiempo
disponible en cada día para ser un diseñador tanto en el nuevo sistema como en el antiguo sistema
simultáneamente, si va a trabajar en ¿ambas cosas?
Si todos los puntos anteriores son ciertos, es posible que se encuentre en una situación en la que sea aceptable
volver a escribir. De lo contrario, lo correcto es manejar la complejidad del sistema existente sin reescribirlo,
mejorando el diseño del sistema en una serie de pasos simples.
Reescritura | 59
Machine Translated by Google
Machine Translated by Google
CAPÍTULO 8
Pruebas
No hay certeza de que un programa se ejecutará en el futuro; solo existe la certeza de que un
programa se está ejecutando ahora. Incluso si lo ha ejecutado una vez, es posible que no vuelva
a ejecutarse. Tal vez el entorno cambie a su alrededor y deje de funcionar. Tal vez lo ejecute en
una computadora diferente y no funcione en la nueva máquina.
Sin embargo, hay esperanza: no estamos condenados a una incertidumbre interminable sobre
la funcionalidad de nuestro software. La Ley de la Prueba nos dice la salida:
El grado en que sabe cómo se comporta su software es el grado en que lo ha probado con
precisión.1
Cuanto más recientemente haya probado su software, más probable es que aún funcione.
Cuantos más entornos lo haya probado, más seguro podrá estar de que funciona en esas
circunstancias. Esto es parte de lo que queremos decir cuando hablamos del "grado" de prueba:
cuántos aspectos del software ha probado, qué tan recientemente y en cuántos entornos
diferentes. En general, simplemente podría decir:
Sin embargo, decir "funciona" es bastante vago. ¿Qué quieres decir con "funciona"?
Lo que realmente sabe cuando prueba es que su software se comporta como usted lo esperaba.
Por lo tanto, debe saber qué comportamiento pretendía. Eso puede sonar estúpido y obvio, pero
es un hecho crítico en las pruebas. Debe hacer una pregunta muy precisa con cada prueba y
obtener una respuesta muy específica. La pregunta podría ser algo como: "¿Qué sucede cuando
un usuario presiona este botón como lo primero que hace después de que se inicia la aplicación,
cuando la aplicación nunca se ha iniciado antes?" Y debería estar buscando alguna respuesta
específica, como "La aplicación muestra una ventana que dice '¡Hola, mundo!'"
Entonces, tienes una pregunta y sabes cuál debería ser la respuesta. Si obtiene alguna otra
respuesta, entonces su software "no funciona".
1. Esta ley es considerablemente más nueva que las demás y agradecería cualquier verificación o contraejemplo.
que tienes para ello.
61
Machine Translated by Google
A veces, un comportamiento es muy difícil de probar y solo puede preguntar: "Si un usuario hace
esto, ¿el programa falla?" y espera la respuesta, “No”. Pero con un software bien diseñado, en la
mayoría de las situaciones, puede obtener información mucho más específica que esa con sus
pruebas.
Y, por supuesto, también debe hacer que sus pruebas sean precisas. Si le dicen que el programa
se está comportando correctamente cuando no es así, o le dicen que está roto cuando en realidad
funciona bien, son pruebas inexactas.
Finalmente, debe observar los resultados de sus pruebas para que sean válidos. Si fallan, debe
haber alguna manera de saber que fallaron, y específicamente cómo fallaron.
Las pruebas pueden ser fáciles de pasar por alto. Escribimos un código, lo guardamos y nos
olvidamos de ver si realmente funciona. Pero no importa lo brillante que seas como programador,
no importa cuántas pruebas matemáticas hagas para demostrar que tu código es correcto, no
sabes que funciona a menos que realmente hayas intentado usarlo.
Y si en algún momento cambia una parte de su software, ya no sabe que esa parte funciona. Debe
volver a probarse. Además, es probable que esa pieza esté conectada a muchas otras piezas, por
lo que ahora tampoco sabe si alguna de esas piezas funciona. Si su cambio es lo suficientemente
grande, es posible que deba volver a probar todo el programa.
Obviamente, no desea tener que probar manualmente todo el programa cada vez que realiza un
pequeño cambio. Entonces, en los tiempos modernos, los desarrolladores generalmente aplican
esta ley creando pruebas automatizadas para cada pieza de código que escriben. Lo bueno de
eso es que pueden ejecutar las pruebas justo después de realizar cualquier cambio, y esas
pruebas automatizadas probarán cada pieza del sistema para asegurarse de que todo siga
funcionando después de cada cambio individual.
Hay mucha información en Internet y en libros sobre cómo escribir pruebas automatizadas y sobre
pruebas en general; es un área muy bien cubierta y vale la pena leerla. La Ley de las Pruebas
simplemente explica por qué deberíamos probar, cuándo deberíamos probar y qué información
nos están dando realmente las pruebas.
62 | Capítulo 8: Pruebas
Machine Translated by Google
APÉNDICE A
Este apéndice resume todas las leyes reales discutidas en este libro:
dónde:
D
Representa la conveniencia del cambio.
vn
Representa valor ahora.
v.f.
Representa el valor futuro.
ei
Representa el esfuerzo de implementación.
Em
Representa el esfuerzo de mantenimiento.
Esta es la ley principal del diseño de software. A medida que pasa el tiempo, esta ecuación se reduce
a:
Lo que demuestra que es más importante reducir el esfuerzo de mantenimiento que reducir el
esfuerzo de implementación.
3. La Ley del Cambio: Cuanto más tiempo exista su programa, más probable es que alguna parte de él
tenga que cambiar.
63
Machine Translated by Google
Eso es todo. En este libro se discutieron muchos más hechos e ideas, pero estos seis elementos
son las leyes del diseño de software. Tenga en cuenta que de todos estos, los más importantes
a tener en cuenta son el propósito del software, la forma reducida de la Ecuación de Diseño de
Software y la Ley de Simplicidad.
Si quisiera resumir los hechos más importantes a tener en cuenta sobre el diseño de software en
dos oraciones simples, serían:
Armado con solo esas dos declaraciones y una comprensión del propósito del software, muy
posiblemente podría volver a desarrollar todo en este libro, siempre que también entendiera que
la complejidad del sistema en realidad proviene de la complejidad de sus piezas individuales.
APÉNDICE B
Este apéndice enumera cada uno de los principales hechos, leyes, reglas y definiciones que se tratan en este libro:
• Realidad: La diferencia entre un mal programador y un buen programador es la comprensión. Es decir, los malos
programadores no entienden lo que están haciendo y los buenos programadores sí. • Regla: Un buen
programador debe hacer todo lo que esté a su alcance para hacer que lo que escribe sea simple para que otros
El diseño no es una democracia. Las decisiones deben ser tomadas por individuos. • Derecho: El propósito
un cambio es directamente proporcional al valor ahora más el valor futuro, e inversamente proporcional al
esfuerzo de implementación más el esfuerzo de mantenimiento.
Lo que demuestra que es más importante reducir el esfuerzo de mantenimiento que reducir el esfuerzo de
implementación.
sesenta y cinco
Machine Translated by Google
• Regla: el nivel de calidad de su diseño debe ser proporcional a la duración del futuro
tiempo en el que su sistema seguirá ayudando a las personas. • Regla:
Hay algunas cosas sobre el futuro que no sabes. • Realidad: El error más común y
desastroso que cometen los programadores es predecir algo sobre el futuro cuando en realidad no pueden
saberlo. • Regla: Está más seguro si no intenta predecir el futuro en absoluto y, en cambio, toma todas
sus decisiones de diseño basándose en información del tiempo presente inmediatamente conocida.
• Ley: La Ley del Cambio: Cuanto más tiempo exista su programa, más probable es que alguna parte de
él tenga que cambiar. • Realidad: Los tres errores (llamados “los tres defectos” en este libro) que los
diseñadores de software son propensos a cometer al hacer frente a la Ley del Cambio son:
• Regla: no escriba código hasta que realmente lo necesite y elimine cualquier código que no sea
siendo utilizado.
• Realidad: cuando su diseño en realidad hace las cosas más complejas en lugar de simplificarlas
cosas, estás haciendo un exceso de
ingeniería. • Regla: Sea tan genérico como sepa que debe ser en este momento. •
Regla: Puede evitar los tres defectos haciendo desarrollo y diseño incrementales. • Ley: La Ley de
• Regla: El mejor diseño es el que permite el mayor cambio en el entorno con el menor cambio en el
software. • Regla: nunca “arreglar” nada a menos que sea un problema y tenga pruebas que demuestren
• Regla: en cualquier sistema en particular, cualquier pieza de información debería, idealmente, existir solo
una vez.
Si realmente quieres triunfar, lo mejor es ser estúpido, tonto simple. • Regla: Sea constante.
• Regla: la legibilidad del código depende principalmente de cómo las letras ocupan el espacio
y simbolos
• Regla: los nombres deben ser lo suficientemente largos para comunicar completamente lo que algo es o
hace sin ser tan largos que se vuelvan difíciles de leer.
• Regla: los comentarios deben explicar por qué el código está haciendo algo, no qué es.
— Malentendido
- Reinventando la rueda
significa que hay un error en el diseño en algún lugar por debajo del nivel donde aparece la complejidad.
• Regla: cuando se le presente complejidad, pregunte: "¿Qué problema estás tratando de resolver?"
¿resolver?"
individuales en pequeños
pasos.
• Realidad: La pregunta clave detrás de todas las simplificaciones válidas es: "¿Cómo podría ser esto
más fácil de manejar o más comprensible?"
• Regla: si se encuentra con una complejidad irreparable fuera de su programa, ponga un ajuste
alrededor que sea simple para otros programadores. • Regla: la reescritura es aceptable solo en un
conjunto muy limitado de situaciones. • Ley: la ley de las pruebas: el grado en que sabe cómo funciona
su software
tiene es el grado en que lo ha probado con precisión. • Regla: a menos
Sobre el Autor
Max Kanat-Alexander, arquitecto jefe del Proyecto Bugzilla de código abierto,
ingeniero de software de Google y escritor, repara computadoras desde que tenía
ocho años y desarrolla software desde que tenía catorce. Es el autor de http://
[Link] [Link]/ y [Link] y actualmente vive en el
norte de California.
Machine Translated by Google