Test Driven Development TDD Universidad
Test Driven Development TDD Universidad
Investigación Aplicada de
Desarrollo de Software Guiado
por Tests (TDD)
2017
Seminario de Sistemas
Tesis
A mis hijos, que son la razón principal por la que, después de tantos años, me embarcara de
nuevo en la Universidad.
A mi esposo Gustavo, por tenerme paciencia.
A Nilsa por apoyarme y alentarme.
A todos aquellos de la comunidad de Internet que ofrecen sus aportaciones, sin las cuales me
habrı́a encontrado más de una vez en un callejón sin salida.
Muchas gracias a todos.
2
Índice general
Agradecimientos 2
1. Introducción 6
1.1. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.1. Objetivos especı́ficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2. Alcance del Proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2. Marco Teórico 8
2.1. Modelo Ágil de Desarrollo de Software . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.1. Introducción al Modelo Ágil . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.2. El Agilisimo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.3. Manifiesto ágil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2. Metodologı́as ágiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.1. XP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2. SCRUM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.3. Crystal Methodologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.4. Dynamic Systems Development Method (DSDM) . . . . . . . . . . . . . . . . 20
2.2.5. Adaptive Software Development (ASD) . . . . . . . . . . . . . . . . . . . . . 20
2.2.6. Feature-Driven Development8 (FDD) . . . . . . . . . . . . . . . . . . . . . . 22
2.2.7. Lean Development (LD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.2.8. Kanban - revisar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3. Investigación de TDD 25
3.1. TDD (Test Driven Development) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.1.1. ¿Qué es TDD? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.2. ¿Cómo se hace TDD? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.3. El lado no tan bueno de TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2. ATDD (Acceptance Test Driven Development) . . . . . . . . . . . . . . . . . . . . . 31
3.3. BDD (Behaviour Driven Development) . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.4. Variantes de TDD clásico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3
Índice general
5. Guı́a práctica 95
5.1. Evaluación previa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
5.2. Tipos de test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.2.1. Test unitarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.2.2. Test de aceptación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.2.3. Test funcionales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.2.4. Test de integración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.2.5. Test de sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.2.6. Objetos simulados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.3. Métodos prácticos de refactorización. . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
5.3.1. Composición de Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
5.3.2. Desplazamiento de funcionalidad entre métodos . . . . . . . . . . . . . . . . . 105
5.3.3. Organización de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.3.4. Simplificación de expresiones condicionales . . . . . . . . . . . . . . . . . . . 107
5.3.5. Generalización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
5.4. Ejemplo práctico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
7. Conclusiones 128
Glosario 130
Bibliografı́a 135
Introducción
1.1. Objetivos
El objetivo del Trabajo de Seminario es hacer una recopilación Bibliográfica y construir un
Marco Teórico Completo de las Metodologı́as Ágiles en particular del Desarrollo Guiado por Pruebas
(TDD) como metodologı́a ágil con el fin de entender las fortalezas y debilidades.
Se destacará como TDD cumple con los postulados del manifiesto ágil para ası́ asegurar su
validez como metodologı́a de desarrollo de software ágil.
Este trabajo presentará una introducción y utilización de la práctica de desarrollo de software
6
Capı́tulo 1. Introducción
Mostrar las fortalezas y debilidades de TDD, de modo que sirva de ayuda para la toma de
decisión al momento de decidir su utilización.
Comprobar que la aplicación obtenida usando TDD tiene menor ı́ndice de errores.
Marco Teórico
El modelo ágil de desarrollo de software, de la década de 1990, decide romper enfoques tradi-
cionales, dejar de lado lo estructurado, también las burocracias que acompañaban al desarrollo de
software. Se hizo al desarrollo de software más flexible, más ligero. De esta forma nacen métodos
ágiles, los más importantes y populares del desarrollo de software, que posteriormente evolucionaron
son Scrum en 1995, Crystal Clear, Extreme Programming, en 1996. En 2001, un grupo de pioneros
en el desarrollo ágil de software se reunieron y declararon el “Manifiesto Ágil”, que es un conjunto
de reglas canónicas de la clase, para los métodos ágiles de desarrollo de software.
Las metodologı́as ágiles emergen como una posible respuesta para llenar el vació metodológico
en la parte del desarrollo del Software. Las metodologı́as ágiles son sin duda uno de los temas
recientes en ingenierı́a de software que están acaparando gran interés.
8
Capı́tulo 2. Marco Teórico
1. Definir y mostrar cómo poner en práctica una colección de valores, principios y prácticas que
conlleven a un modelado ligero efectivo.
El modelo ágil es la actitud que tiene un individuo para el desarrollo del software, tener a
priori una dirección hacia un fin determinado, no es un proceso , o algo que se establece, un
ejemplo de algo prescriptivo como el manual de un televisor, el modelo ágil no dice que hay
que hacer en determinado caso.
El equipo se adapta a los requerimientos de los productos que cambian de forma dinámica.
Lo importante, modelar con un propósito, identificar lo válido, luego averiguar hasta qué punto
de detalle se desea la información, y saber para quién va dirigido el modelo.
El Modelo Ágil, es un modelo que logra recuperar gran parte del complejo social en el desarrollo
del Software. Hace que el modelo se regule ası́ mismo, que siempre tenderá hacia el equilibrio, lo
cual lo hace un modelo ideal pero obviamente imperfecto.
Las metodologı́as ágiles resuelven los problemas surgidos por las expectativas y necesidades por
parte de los usuarios, las cuales se hicieron más urgentes y frecuentes. Fue ası́ como a comienzo
de los 90 surgieron propuestas metodológicas para lograr resultados más rápidos en el desarrollo
de software sin disminuir su calidad. En febrero de 2001 en Utah-EEUU, se reunieron 17 empre-
sarios de la industria del software y como resultado del debate respecto a las metodologı́as, se
obtuvo principios y valores que deben regir el desarrollo de software de buena calidad, en tiempos
cortos y flexible a los cambios, se aceptó el término ágil para hacer referencia a nuevos enfoques
metodológicos en el desarrollo de software [34].
En esta reunión se creó “The Agile Alliance”, organización sin ánimo de lucro dedicada a
promover los conceptos relacionados con el desarrollo ágil de software. Como punto de partida o
base fundamental de las metodologı́as ágiles se redactó y proclamó el manifiesto ágil.
Modelado Ágil es una metodologı́a basada en la práctica para modelado efectivo de sistemas
de software. La metodologı́a del Modelo Ágil es una colección de prácticas, guiadas por principios.
El Modelo Ágil no es un proceso prescriptivo, en él no existen procedimientos detallados de cómo
crear un modelo, solo sugiere prácticas para ser un modelador efectivo. Es flexible, no es rı́gido y
es rápido. Es más un arte, nadie te dice cómo hacer las cosas, más bien te dicen que podrı́as hacer
para que te salgan mejor.
2.1.2. El Agilisimo
El agilı́simo es una respuesta a los fracasos y las frustraciones del modelo en cascada. Si bien las
metodologı́as ágiles llevan siendo usadas, no mucho, la cantidad de metodologı́as ágiles es amplia,
existiendo métodos para organizar equipos y técnicas para escribir y mantener software [12].
Muchos autores afirman que para atacar la forma de organizar equipos deberı́amos irnos hacia
Scrum y para el mantenimiento del software Programación Extrema.
Cuando se habla de agilı́simo no se busca el perfeccionismo, se reconoce que el software es
propenso a errores, pero es cierto que la naturaleza viene propiamente de quienes realizan el código,
es por ello que se toman medidas para minimizar sus efectos nocivos desde el principio.
Se reconoce que los humanos nos equivocamos con frecuencia, por lo que no se espera encontrar
desarrolladores perfectos, en el agilı́simo se proponen técnicas que ayudan a minimizar los errores
y se intenta dar confianza a pesar de ellos.
La esencia del agilı́smo es adaptarse a los cambios, entonces, se ve al modelo en cascada trans-
formado en una rueda, que a cada vuelta obtenemos una iteración, se alimenta con nuevos reque-
rimientos o aproximaciones más refinadas, se pulen detalles técnicos. Ejecutando diversas técnicas
que se engloban, con la debida disciplina, se obtienen resultados satisfactorios sin entrar en un caos.
El alcance del software: Viene siendo discutido, ya que no hay un consenso claro sobre la
unidad de medida (lı́nea de código, punto función, caso de uso...) a aplicar.
El tiempo: Algo que es trivial de medir, y sin embargo arroja terribles resultados. Aproxima-
damente sólo un tercio de los proyectos informáticos logran ser puestos en funcionamiento en
el tiempo inicialmente estimado o acordado, lo que denota un proceso descontrolado.
El coste: en la que normalmente se centran las metodologı́as y gerentes del sector, incidiendo
en ella con poca precisión, puesto que habitualmente la presión gerencial sobre esta dimensión
afecta a la calidad resultante.
La calidad, la realidad demuestra que muchos clientes y usuarios no tienen un mı́nimo co-
nocimiento de en qué dimensiones pueden y deben exigir, ni con qué parámetros medirla. A
pesar de la existencia de clasificaciones de factores de calidad del software fáciles de explicar
y comprender.
La mayorı́a de los factores nombrados son factores humanos. Se evidencia el problema, el agilı́si-
mo intenta dar respuesta.
Los valores anteriores inspiran los doce principios del manifiesto. Estos principios son las ca-
racterı́sticas que diferencian un proceso ágil de uno tradicional. Los dos primeros son generales y
resumen gran parte del espı́ritu ágil. Son:
II. Dar la bienvenida a los cambios. Se capturan los cambios para que el cliente tenga una ventaja
competitiva. Este principio es una actitud que deben adoptar los miembros del equipo de
desarrollo. Los cambios en los requisitos deben verse como algo positivo. Les va a permitir
aprender más, a la vez que logran una mayor satisfacción del cliente. Este principio implica
además que la estructura del software debe ser flexible para poder incorporar los cambios
sin demasiado coste añadido. El paradigma orientado a objetos puede ayudar a conseguir
esta flexibilidad. Luego existen una serie de principios que tienen que ver directamente con el
proceso de desarrollo de software a seguir.
III. Entregar frecuentemente software que funcione desde un par de semanas a un par de meses,
con el menor intervalo de tiempo posible entre entregas. Las entregas al cliente se insiste en
que sean software, no planificaciones, ni documentación de análisis o de diseño.
IV. La gente del negocio y los desarrolladores deben trabajar juntos a lo largo del proyecto. El
proceso de desarrollo necesita ser guiado por el cliente, por lo que la interacción con el equipo
es muy frecuente.
VI. El diálogo cara a cara es el método más eficiente y efectivo para comunicar información
dentro de un equipo de desarrollo. Los miembros de equipo deben hablar entre ellos, éste es
el principal modo de comunicación. Se pueden crear documentos pero no todo estará en ellos,
no es lo que el equipo espera.
VIII. Los procesos ágiles promueven un desarrollo sostenible. Los promotores, desarrolladores y
usuarios deberı́an ser capaces de mantener una paz constante. No se trata de desarrollar
lo más rápido posible, sino de mantener el ritmo de desarrollo durante toda la duración del
proyecto, asegurando en todo momento que la calidad de lo producido es máxima. Finalmente
los últimos principios están más directamente relacionados con el equipo de desarrollo, en
cuanto metas a seguir y organización del mismo.
IX. La atención continua a la calidad técnica y al buen diseño mejora la agilidad. Producir código
claro y robusto es la clave para avanzar más rápidamente en el proyecto.
X. La simplicidad es esencial. Tomar los caminos más simples que sean consistentes con los
objetivos perseguidos. Si el código producido es simple y de alta calidad será más sencillo
adaptarlo a los cambios que puedan surgir.
XI. Las mejores arquitecturas, requisitos y diseños surgen de los equipos organizados por sı́ mis-
mos. Todo el equipo es informado de las responsabilidades y éstas recaen sobre todos sus
miembros. Es el propio equipo el que decide la mejor forma de organizarse, de acuerdo a los
objetivos que se persigan.
XII. En intervalos regulares, el equipo reflexiona respecto a cómo llegar a ser más efectivo, y
según esto ajusta su comportamiento. Puesto que el entorno está cambiando continuamente,
el equipo también debe ajustarse al nuevo escenario de forma continua. Puede cambiar su
organización, sus reglas, sus convenciones, sus relaciones, etc., para seguir siendo ágil.
Los firmantes de los valores y principios de este Manifiesto son: Kent Beck, Mike Beedle, Arie van
Bennekum, Alistair Cockburn, Ward Cunningham, Martin Fowler, James Grenning, Jim Highsmith,
Andrew Hunt, Ron Jeffries, Jon Kern, Brian Marick, Robert C. Martin, Steve Mellor, Ken Schwaber,
Jeff Sutherland y Dave Thomas. Aunque los creadores e impulsores de las metodologı́as ágiles más
populares han suscrito el manifiesto ágil y coinciden con los principios enunciados anteriormente,
cada metodologı́a tiene caracterı́sticas propias y hace hincapié en algunos aspectos más especı́ficos
[34].
adición de nuevo código en cada iteración, pero también por refactorización del código existente
escrito durante las iteraciones anteriores. Esta refactorización puede lograrse de manera segura sólo
si se tiene un sistema de prueba fuerte, capaz de verificar que todo el producto de software no se
romperá cuando se agregue nuevo código, o al modificar lo existente.
Por lo tanto, cuando se desarrolla el software, finalmente se crean dos sistemas separados, pero
fuertemente conectados:
El objetivo principal de XP es la satisfacción del cliente. Se le trata de dar al cliente lo que quiere
y cuando quiere. Por tanto, se debe responder rápidamente a las necesidades del cliente, aunque
realice cambios en fases avanzadas del proyecto. Como metodologı́a Ágil que es, se pueden producir
modificaciones de los requisitos del proyecto a lo largo de su desarrollo, sin que esto produzca un
buen dolor de cabeza. Otro de los objetivos es el trabajo en grupo. Tanto los jefes del proyecto,
clientes y desarrolladores forman parte del equipo y deben estar involucrados en el desarrollo.
Para garantizar el éxito de un proyecto, los autores de XP han considerado como fundamentales
cuatro valores:
Sencillez. Los programas deben ser los más sencillos posibles y tener la funcionalidad necesaria
que se indican en los requisitos. No hay que añadir algo que no se necesite hoy. Si se necesita
añadir más funcionalidad mañana pues ya se hará entonces.
Retroalimentación. Las pruebas que se le realizan al software nos mantiene informados del
grado de fiabilidad del sistema.
Valentı́a. Asumir retos, ser valientes ante los problemas y afrontarlos. El intentar mejorar algo
que ya funciona. Aunque gracias a las pruebas unitarias no existe el riesgo de ‘meter la pata’.
Algunas voces, añaden además un quinto valor: la humildad. El compartir el código, la refac-
torización y el trabajo en equipo tan estrecho es una buena dosis de humildad que siempre es de
agradecer.
Prácticas de XP
El juego de la planificación (the planning game). Es un permanente diálogo entre las partes
empresarial (deseable) y técnica (posible).
Pequeñas entregas (small releases). Cada versión debe de ser tan pequeña como fuera posible,
conteniendo los requisitos de negocios más importantes, las versiones tienen que tener sentido
como un todo, no se puede implementar media caracterı́stica y lanzar la versión.
Es mucho mejor planificar para 1 mes o 2 que para seis meses y un año, las compañı́as que
entregan software muy voluminoso no son capaces de hacerlo con mucha frecuencia.
Metáfora (metaphor). Una metáfora es una historia que todo el mundo puede contar acerca de
cómo funciona el sistema. Algunas veces podremos encontrar metáforas sencillas “Programa
de gestión de compras, ventas, con gestión de cartera y almacén”. Las metáforas ayudan a
cualquier persona a entender el objeto del programa.
Diseño sencillo (simple design): Se basa en la filosofı́a de que el mayor valor de negocio es
entregado por el programa más sencillo que cumpla los requerimientos. Un diseño sencillo se
enfoca en proporcionar un sistema que cubra las necesidades inmediatas del cliente, ni más
ni menos. Este proceso permite eliminar redundancias y rejuvenecer los diseños obsoletos de
forma sencilla.
Pruebas (testing). No debe existir ninguna caracterı́stica en el programa que no haya sido
probada, los programadores escriben pruebas para chequear el correcto funcionamiento del
programa, los clientes realizan pruebas funcionales. El resultado un programa más seguro que
conforme pasa el tiempo es capaz de aceptar nuevos cambios.
Programación por parejas (pair programming). Todo el código de producción lo escriben dos
personas frente al ordenador, con un sólo ratón y un sólo teclado. Cada miembro de la pareja
juega su papel: uno codifica en el ordenador y piensa la mejor manera de hacerlo, el otro
piensa más estratégicamente, ¿Va a funcionar?, ¿Puede haber pruebas donde no funcione?,
¿Hay forma de simplificar el sistema global para que el problema desaparezca?
Propiedad colectiva (collective ownership). Cualquier persona que crea que puede aportar
valor al código en cualquier parcela puede hacerlo, ningún miembro del equipo es propietario
del código. Si alguien quiere hacer cambios en el código puede hacerlo. Si hacemos el código
propietario, y necesitamos de su autor para que lo cambie entonces estaremos alejándonos
cada vez más de la comprensión del problema, si necesitamos un cambio sobre una parte del
código lo hacemos y punto. XP propone un propiedad colectiva sobre el código nadie conoce
cada parte igual de bien pero todos conoce algo sobre cada parte, esto nos preparará para la
sustitución no traumática de cada miembro del equipo.
Integración continua (continuos integration). El código se debe integrar como mı́nimo una vez
al dı́a, y realizar las pruebas sobre la totalidad del sistema. Una pareja de programadores se
encargara de integrar todo el código en una máquina y realizar todas las pruebas hasta que
estas funcionen al 100
40 horas semanales (40-hour week). Si se quiere que los programadores estén frescos y mo-
tivados cada mañana y cansados y satisfechos cada noche. Esto requiere que trabajemos 40
horas a la semana, mucha gente no puede estar más de 35 horas concentrada a la semana,
otros pueden llegar hasta 45 pero ninguno puede llegar a 60 horas durante varias semanas y
aun seguir fresco, creativo y confiado. Las horas extras son sı́ntoma de serios problemas en el
proyecto, la regla de XP dice nunca 2 semanas seguidas realizando horas extras.
Cliente en casa (on-site costumer). Un cliente real debe sentarse con el equipo de programado-
res, estar disponible para responder a sus preguntas, resolver discusiones y fijar las prioridades.
Lo difı́cil es que el cliente nos ceda una persona que conozca el negocio para que se integre en
el equipo normalmente estos elementos son muy valiosos, pero debemos de hacerles ver que
será mejor para su negocio tener un software pronto en funcionamiento, y esto no implica que
el cliente no pueda realizar cualquier otro trabajo.
Algunas de estas prácticas reciben muchas crı́ticas, sobre todo la programación por parejas.
Muchos jefes de proyecto no aceptan que dos desarrolladores tengan un único ordenador, ya que
creen que esto minimizará la productividad, sin saber que de este modo puede producirse el mismo
código que dos personas trabajando en solitario pero con un código de mayor calidad.
XP lleva las mejores prácticas a niveles extremos [17]. Por ejemplo la práctica de hacer test
antes de desarrollar fue usada por la NASA en el programa Mercury Space por primera vez para
tarjetas perforadas en 1960. XP la llevo al extremo con TDD. Aunque Kent Beck con XP no se
considera a sı́ mismo el creador de Test Driven Development, fue el que implemento SUnit, un
framework de tests unitarios para Smalltalk que fueron las bases de la familia xUnit (conjunto de
frameworks basados en sus premisas como nUnit, phpUnit, junit, MsUnit, etc). Este framework se
pensó para realizar TDD basándose en ideas de Gerard Weinberg y Leeds, Herbert D. en su libro
(Computer Programming Fundamentals – 1960).
CI(Continuos integration) fue propuesta y nombrada por primera vez en 1991 por Grady Booch
en su método (Método Booch). En este caso Booch no hablaba en ningún caso de integrar varias
veces al dı́a. Grady Booch es conocido por desarrollar UML junto con James Rumbaugh. En 1991/94
desarrolló el método Booch. Se trataba de una técnica usada en ingenierı́a software para el diseño
de objetos (predecesor de UML y RUP).Este método hablaba de uso de objetos, métricas, QA,
patrones de diseño, formalismo, madurez de procesos y una notación robusta. Habla de sacar
releases de arquitectura hasta llegar al sistema final (evolutivos). . . si, es el precursor de RUP
también, evidentemente.
2.2.2. SCRUM
Desarrollada por Ken Schwaber, Jeff Sutherland y Mike Beedle. Define un marco para la gestión
de proyectos, que se ha utilizado con éxito durante los últimos 10 años. Está especialmente indicada
para proyectos con un rápido cambio de requisitos. Sus principales caracterı́sticas se pueden resumir
en dos. El desarrollo de software se realiza mediante iteraciones, denominadas sprints, con una
duración de 30 dı́as. El resultado de cada sprint es un incremento ejecutable que se muestra al
cliente. La segunda caracterı́stica importante son las reuniones a lo largo proyecto. Éstas son las
verdaderas protagonistas, especialmente la reunión diaria de 15 minutos del equipo de desarrollo
para coordinación e integración.
Popular metodologı́a ágil, fácil de entender y de implementar en muchos tipos de procesos
de desarrollo, no siendo fácil de dominar porque requiere mucho esfuerzo de equipo y apoyo de
autoridades. Esta documentada en el “Scrum Framework”, es un conjunto de prácticas, guı́a de
grupos, roles, eventos, herramientas y reglas, con las cuales ejecutar proyectos. La teorı́a del método
Scrum está basada en tres pilares: Transparencia, Inspección y Adaptación [30]:
Transparencia: este pilar consiste en dar visibilidad a los responsables del producto final. Un
ejemplo de transparencia serı́a crear una definición común de que se entiende por “acabado”,
de manera que todas las partes estén de acuerdo.
Inspección: este pilar consiste en crear puntos de chequeo en los cuales verificar como está avan-
zando el proyecto hacia su meta final, vigilando posibles desviaciones problemáticas de lo que
serı́a el resultado final esperado.
Adaptación: este pilar consiste en ajustar un proceso para minimizar los posibles problemas
si una inspección muestra un problema o una tendencia indeseada.
Es una metodologı́a en donde gran parte de las actividades que componen su proceso son
actividades de gestión. Las actividades se organizan en tres fases llamadas de pre-juego, juego y
post-juego. Las actividades técnicas se encuentran principalmente en las fases de Juego y post-
juego. La seleccion de estas practicas tiene su origen en un estudio realizado en Hirotaka Takeuchi
e Ikujio Nonaka sobre ”nuevas practicas de produccion.a mediados de los 80 en su articulo titulado
”The new product develoment game”[27]
Se descubrio que las empresas que estaban obteniendo mejores resultados en el desarollo de
software a pesar de lo acelerado que cambiaba el mercado eran aquellas que se estaban alejando de
la forma tradicional de desarrollar sus productos.
Los objetivos de la gestión con Scrum son[42]:
Generar Valor.
Agilidad y flexibilidad.
Fiabilidad.
limitado por los recursos a utilizar. El equipo de desarrollo es un factor clave, por lo que se deben
invertir esfuerzos en mejorar sus habilidades y destrezas, ası́ como tener polı́ticas de trabajo en
equipo definidas. Estas polı́ticas dependerán del tamaño del equipo, estableciéndose una clasificación
por colores, por ejemplo Crystal Clear (3 a 8 miembros) y Crystal Orange (25 a 50 miembros).
Crystal es una familia de metodologı́as diseñada para proyectos que van desde los dirigidos por
pequeños equipos desarrollando sistemas de baja criticidad (Crystal Clear), a aquéllos dirigidos por
grandes equipos construyendo sistemas de alta criticidad (Crystal Magenta). El sistema Crystal
provee un gran ejemplo de como adaptar un método para que coincida con las caracterı́sticas de
un proyecto y una organización. En la figura 3, vemos los métodos Crystal básicos:
El tamaño del equipo viene representado en el eje de las X y el nivel de criticidad del proyecto
en el eje de las Y. Crystal Clear está dirigido a proyectos pequeños con equipos de una a seis
personas. Los proyectos Crystal Clear desarrollan sistemas en los cuales un fallo puede resultar en
una pérdida de confort (p.e. un fallo en un videojuego) o una pérdida financiera de bajo nivel (p.e.
un fallo del procesador de textos resultante en una pérdida de tiempo en el negocio). Ası́, el proyecto
involucra a más gente y desarrolla aplicaciones más crı́ticas, escala los procedimientos detrás de la
comunicación cara a cara e introduce validaciones adicionales y medidas de trazabilidad.
2. Entregar a tiempo.
3. Colaborar.
8. Demostrar control.
Iterativo.
Orientado a componentes.
Soporta cambios.
ASD es un cambio orientado a un ciclo de vida donde hay tres componentes: especular, colaborar
y aprender.
Especular : Es la primera fase donde se establecen los principales objetivos, se analizan las
limitaciones, riesgos con las que se trabajar en el proyecto.
Las estimaciones sufren como en todo proyecto desviaciones, ayudan a la correcta atención de
los miembros del equipo, de forma de mover los plazos y dar correcta prioridad a las tareas.
Como en la mayorı́a de las metodologı́as ágiles se presta atención a las caracterı́sticas que
se requiere que pueden ser utilizadas por el cliente al final de cada iteración. Por lo tanto
hay una serie de tareas dentro de cada iteración que tienen prioridad, además que las tareas
o pasos se pueden volver a examinar hasta que los miembros del equipo y el cliente estén
satisfechos con el resultado.
Aprender:La última etapa termina con una serie de ciclos de colaboración, su trabajo consiste
en capturar lo que se ha aprendido, tanto positivo como negativo. Es un elemento crı́tico para
la eficacia de los equipos. Jim Highsmith identifica cuatro tipos de aprendizaje en esta etapa:
• Calidad del producto desde un punto de vista del cliente: Es la única medida legı́tima
de éxito.
• Calidad del producto desde un punto de vista de los desarrolladores. La calidad desde
el punto de vista técnico.
• Gestión y rendimiento: Se evalúa los procesos utilizados por el equipo, y lo que se ha
aprendido.
• Situación del proyecto: Es cuando hacemos la planificación de la siguiente iteración, que
es el punto de partida de la construcción de la siguiente.
Usada de manera adecuada esta metodologı́a ASD se puede alcanzar excelentes resultados pero
debido a las caracterı́sticas que maneja es mas factible usarla para proyectos pequeños y medianos,
para adquirir practica y experiencia para ası́ poder llegar al Rapid Application Development (RAD)
en donde tendremos productos de alta calidad.
Ámbito del modelado de objetos: En esta práctica, los equipos exploran y explican el ámbito
(o el ambiente de negocio) del problema a ser resuelto.
Desarrollo por caracterı́stica: Esta práctica implica romper funciones trozos de dos semanas
o menos y llamarlas caracterı́sticas.
Clase (código) individual de propiedad: Con esta práctica, las áreas de código tienen un único
propietario para garantizar la consistencia, rendimiento e integridad conceptual (a diferencia
del planteamiento colectivo del método XP).
Equipos por caracterı́stica: consiste en equipos pequeños, formados dinámicamente que per-
miten evaluar múltiples opciones de diseño antes de escoger un diseño. Los equipos de carac-
Inspecciones: Son revisiones que ayudan a asegurar un diseño y código de buena calidad.
Manejo de la configuración: Esta práctica implica etiquetar códigos, rastrear los cambios, y
manejar el código fuente.
Visibilidad del progreso y de los resultados: Esta práctica rastrea el progreso basado en el
trabajo completado.
El desarrollo basado en las caracterı́sticas es una metodologı́a ágil que populariza los diagramas
de flujo acumulativos y los diagramas de parking. Ambas son herramientas útiles de rastreo y
diagnóstico que se utilizan ahora para otros enfoques ágiles.
Eliminar las pérdidas: Para maximizar el valor, debemos minimizar las pérdidas. Para los
sistemas de software, las pérdidas pueden tomar la forma de trabajo parcialmente hecho,
retrasos, transferencias, caracterı́sticas innecesarias. Por lo tanto, para incrementar, debemos
desarrollar vı́as para identificar y eliminar estas pérdidas.
Optimizar el total: El objetivo es ver el sistema como la suma de sus partes. Vamos más
allá de las partes del proyecto y buscamos como se alinean con la organización. Como parte de
optimización del total, también centrarce en la formación de mejores relaciones intergrupales.
Construir la calidad desde dentro: El desarrollo Lean no intenta testear la calidad al final;
construye la calidad en el producto y continuamente asegura la calidad a través del proceso
de desarrollo, usando técnicas como la refactorización, integración continua, y testeo de las
unidades.
Visualiza el flujo de trabajo: Los proyectos con trabajadores con conocimientos manipulan el
conocimiento, el cual es intangible e invisible. Es importante por lo tanto tener una manera
de visualizar el flujo de trabajo para organizar, optimizar y seguirlo.
Dirige el flujo de trabajo: Mediante el seguimiento del flujo de trabajo a través de un sistema,
los problemas pueden ser identificados y se puede medir la efectividad de los cambios.
Hacer polı́ticas de proceso explicitas: Es importante explicar claramente como funcionan las
cosas de manera que el equipo pueda tener discusiones abiertas sobre las mejoras objetiva-
mente en lugar de emocional o subjetivamente.
Investigación de TDD
25
Capı́tulo 3. Investigación de TDD
vidad es la capacidad de generar nuevas ideas o conceptos, de nuevas asociaciones entre ideas y
conceptos conocidos, que habitualmente producen soluciones originales.
Según la Real Academia Española la creatividad es la facultad de crear o capacidad de creación.
Ahora el verbo crear nos dice:
2. tr. Establecer, fundar, introducir por vez primera algo; hacerlo nacer o darle vida, en sentido
figurado. Crear una industria, un género literario, un sistema filosófico, un orden polı́tico,
necesidades, derechos, abusos.
Esta definición nos ayuda mucho a convencernos que el desarrollo de software es algo creativo.
Cuando creamos también estamos aprendiendo. Ahora si pensamos en el desarrollo de software
como un proceso en el cual uno va adquiriendo conocimiento, donde nos vamos haciendo una idea
mental de cómo resolver el problema y al cual luego vamos representando, modelando, en lo que
nosotros llamamos programa, estarı́amos ante un proceso de aprendizaje.
Esto tiene mucho que ver con la esencia de lo que es TDD. Entender el desarrollo de software
como un proceso de adquisición de conocimiento ayuda a que no confundamos a TDD como solo
una herramienta de testing, donde el testing no es más ni menos que un medio para llegar al fin,
que es obtener un buen diseño.
Como todo proceso de aprendizaje si lo vemos desde la visión constructivista del aprendizaje,
donde la idea esencial es aprender haciendo. La evaluación de lo que vamos haciendo genera infor-
mación, por lo que es importante detenernos a pensar que hacemos con esta información. Como es
sistematizada, interpretada y comunicada, podemos decir que esta evaluación genera conocimiento
con un alto valor retroalimentador.
Las caracterı́sticas básicas de este proceso de aprendizaje son que es iterativo, incremental y
que hay que tener una retroalimentación inmediata. La metodologı́a de desarrollo Lean apoyada
por la comunidad ágil, en unos de sus principios hace hincapié en el desarrollo de software como
un proceso de aprendizaje [59], existe un marco teórico sólido y basado en la experiencia de las
practicas ágiles de gestión.
Para aprender algo y bien hay que obtener lo más rápido posible una retroalimentación. Cuando
desarrollamos necesitamos ir viendo como se comporta nuestro código, por eso el proceso iterativo
e incremental también hay que aplicarlo cuando uno está desarrollando software.
Cuando se empieza a entender que el desarrollo de software es un proceso iterativo, incremental
con feedback inmediato en definitiva constructivista, podemos empezar a pensar en herramientas,
técnicas, qué es lo que conviene utilizar. Por ejemplo un lenguaje de programación que tarde mucho
en realizar lo que está haciendo, claramente no está ayudando a obtener un feedback inmediato.
Además desde el momento en que se coloca el código fuente en un repositorio o al alcance de otros
desarrolladores supone un feedback inmediato a los desarrolladores sobre posibles defectos en el
código, problemas de seguridad, rendimiento, etc.
Una caracterı́stica esencial del software es que cambia3 , es mutable, ya sea porque cambia el
dominio del problema, o el soporte o nuestra manera de entender el dominio del problema.
Pero lo que impacta más es que nosotros cambiamos la manera de entender cuándo vamos
modelando y estamos continuamente en el desafı́o de poder reflejar ese cambio en nuestro modelo.
Cuando no podemos o no se quiere actualizar estamos en presencia de un sistema legacy4 .
Resumiendo, hay que tener claro que el software debe ser un buen modelo, representar correc-
tamente el dominio, ser fiable, fácil de cambiar (acompañar el proceso de aprendizaje del domino
del problema), y saber auto-defenderse de usos incorrectos[13].
Como explicamos anteriormente esta introducción es importante para entender la esencia de
TDD.
aplicaciones) que ha quedado anticuado pero que sigue siendo utilizado por el usuario (generalmente, una organización
o empresa) y no se quiere o no se puede reemplazar o actualizar de forma sencilla.
5 Ingeniero en Software, profesor de la Universidad de Buenos Aires
6 Ingenieria Tecnica en Informatica de Sistemas, de la Universidad de la Laguna, autor del libro ”Diseño Agil con
TDD”
Primero los Tests: Las pruebas se escriben primero, incluso antes del propio código. Estás
deben estar escritas por los desarrolladores, por lo que nos referı́amos más arriba cuando
hablábamos de entender el dominio del problema. El proceso de aprendizaje que estamos
teniendo al desarrollar las pruebas, y el código implementado que se va a probar.
Automatización: Las pruebas deben ser ejecutadas automáticamente las veces que sea nece-
sario, debemos tener la retroalimentación inmediata que nos brindará el conocimiento de lo
que estamos probando, y si estamos en lo correcto o no.
Refactorizar: TDD habla de que la arquitectura se forja a base de iterar y refactorizar en lugar
de diseñarla completamente de antemano. La refactorización permite mantener la calidad de
la arquitectura, se cambia el diseño sin cambiar la funcionalidad, manteniendo las pruebas
como reaseguro.[55]
¿Cómo escribimos un test para un código que todavı́a no existe?. Para contestar esta pregunta
vamos a repasar primero que hacemos cuando estamos haciendo las especificaciones de nuestro
dominio del problema.
En las especificaciones escribimos lo que deberı́a hacer nuestro software, los requisitos. En TDD
estarı́amos expresando un requisito en forma de código (el test), lo que debe hacer nuestro sistema
y que deberı́a devolver. Un ejemplo de esto son las JSR (Java Specification Request) que se escriben
para que luego en otras partes la implementen. En TDD escribimos nuestros tests para que luego
se implemente el código que los hará pasar.
Inicialmente a lo que llamamos ejemplo o test no es mas que una especificación [12]. La diferencia
fundamental es que el test puede ser modificado, una especificación se espera que no. Lo que en
realidad estamos haciendo es un ejemplo en código de como cumplir un requisito, una manera de
resolverlo, pero sin alterar la esencia del requisito.
Cuando elaboramos el test tenemos que hacer el esfuerzo de imaginar como serı́a el código como
si ya estuviera implementado, y como comprobarı́amos que hace efectivamente lo que queremos que
haga. Al tener que usar una funcionalidad antes de haberla escrito, buscamos simpleza, tratamos
de no complicarnos a nosotros mismos, que sea cómodo, más claro, pero que siempre cumpla con
el objetivo del requisito.
Los primeros tests son difı́ciles, al escribir el test empezamos a analizar el problema y empezamos
a pensar como lo escribiremos. Generalmente no se sabe por donde empezar o encarar el problema,
por donde resolverlo. Siempre conviene comenzar por la aserción o las aserciones, escribirlas, son
las que formaran parte del test, porque a partir de ellas voy a lograr deducir que es lo que quiero
probar [13].
El algoritmo de TDD es un ciclo que debe ser realizado de forma rápida, es posible incluso que
al agregar una caracterı́stica sea necesario crear muchos más tests, hasta que ya no quede más por
agregar o eliminar por medio de la refactorización.
Posteriormente veremos mediante ejemplos como desarrollar tests, su implementación y refac-
torización.
Teniendo las mı́nimas aserciones escritas en el test y el test falla, codificamos lo mı́nimo para que
éste pase. Las aserciones nos guı́an en lo que tenemos que hacer. Cuando decimos el mı́nimo código
nos referimos al que menos tiempo nos lleve escribir, si el código parece feo o groseramente simple
en este momento no nos debe importar, luego lo arreglaremos. Es importante no implementar nada
mas que lo mı́nimo y necesario para que el test pase.
Es un proceso de pensar la mejor forma de hacer eficiente el código, no de hacerlo sin pensar.
Es algo difı́cil de hacer, ya que solemos escribir mas código del que nos hace falta. El hecho de ser
minimalista en el código nos ayuda a desarrollar código eficiente.
Si nos concentramos en este paso nos aparecerán las dudas propias del requisito, el comporta-
miento que debe tener el software, si deberı́an existir nuevas especificaciones, si existen más entradas
de las que pensábamos. Haremos un análisis de los distintos flujos condicionales que pueden entrar
en juego.
De seguro estaremos tentados de escribir más código sobre la marcha, pero solo tenemos que
tener la atención de anotar las preguntas que nos surgen que podrán convertirse en especificaciones
que tendremos que retomar después.
En la refactorización hay que enfocarse en escribir código que implemente una ejecución exitosa,
cuando decimos exitosa nos referimos a que el código haga lo que esperamos que haga y además las
pruebas pasen. Se debe enfocar en eliminar código duplicado, innecesario, mejorarlo para cumplir
con patrones de codificación establecidos que faciliten la lectura y claridad.
No significa reescribir código. Según Martı́n Fowler, refactorizar [37] es modificar el diseño sin
alterar el funcionamiento. En este paso del algoritmo de TDD intentaremos, porque no estamos
libres de pasar por alto algo, de buscar código duplicado, innecesario, tanto en los tests como
en el código. Se busca también cumplir con principios de diseño. Si estamos desarrollando con
programación orientada objeto podrı́amos usar S.O.L.I.D7 que son cinco principios. S.O.L.I.D fue
introducido por ”Tı́o Bob”Martı́n en el 2000. La idea es ser fiel a principios de desarrollo de software
para obtener mas robustes.
En la refactorización existen muchas recetas, dadas precondiciones se aplican determinados
cambios. Los cambios mejoran el diseño del software pero no alteran su comportamiento. Cuando
decimos que mejoran deberı́amos aplicar alguna métrica para afirmarlo, generalmente en la refac-
torización usarı́amos la métrica del código duplicado como parámetro de calidad. Entonces si no
existe código duplicado, obtuvimos código de mejor calidad comparándolo con el que presentaba
duplicidad.
Claro que la refactorización depende mucho del programador, de su conocimiento y experien-
cia. Hoy en dı́a existen muchas aplicaciones que ayudan al desarrollador en la refactorización sin
mencionar los IDE que también contribuyen bastante.
Aún ası́ existen refactorizaciones mas complejas, y otras que a modo de patrón parecen trucos
tı́picos de los que uno llama “trucos de cocina” que suelen eliminar la duplicidad, que mantenga su
coordinación con el resto del código lo que se suele llamar API Pública.
Como se decı́a arriba la refactorización depende mucho del desarrollador, se recomienda ir paso
a paso, para cada cambio ejecutar los tests. En este proceso suele pasarse de una visión global del
código a una local, es como repasar nuestro diseño modular, las llamadas, etc. La tarea de revisar el
código suele olvidarse o dejarse para el último, en la refactorización es donde la haremos. La ventaja
es que no estamos revisando todo el código sino a medida que lo implementamos y probamos.
Estarı́amos haciendo pruebas de unidad a medida que desarrollamos cada test y luego el código
que lo pasa. Y podrı́amos decir que hacemos pruebas de integración cuando corremos todos los
tests y refactorizamos.
Los pasos del algoritmo de TDD son todos importantes, si pasamos de largo uno no estamos
haciendo TDD.
Si nos preguntamos cual es el objetivo principal de TDD encontraremos que hay dos puntos de
vista, uno es que el objetivo de TDD es la especificación y no la validación. (Martin, Newkirk, y
Kess 2003 ). Es una manera de pensar a través de requisitos o diseño antes de escribir el código
funcional. Otro punto de vista es que es una técnica de programación como a Ron Jeffries le gusta
decir el objetivo de TDD es escribir código limpio que funciona.
Creo ambos argumentos son validos, me inclino más por la opinión de la especificación porque
a medida que vamos desarrollando los tests estamos cumpliendo especificaciones que nos dicen que
tiene que hacer el software y como realiza lo que hace y los resultados que debemos obtener, porque
nos obliga a pensar en que debe hacer el software antes de incluso hacer el código.
Es importante entender que no tener la cantidad de pruebas (unitarias o no) conducirı́a a
muchos ciclos de ida y vuelta entro lo que necesitamos desarrollar, la calidad requerida e incluso
para que el mismo desarrollador entienda la lógica de negocio. Por eso el uso de TDD (o sus
7 SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion)
es un acrónimo mnemotécnico introducido por Robert C. Martin1 2 a comienzos de la década del 20003 que representa
cinco principios básicos de la programación orientada a objetos y el diseño.
variantes) ayuda a asegurarse que un código correcto cortará los ciclos de ida y vuelta causados
por requerimientos incomprendidos. El proceso de desarrollo será más corto usando TDD que no
usarlo, independientemente de la pregunta de calidad.[9]
La idea es que los criterios de aceptación sean concisos, cuanto menos palabras halla mejor,
intentamos que no haya ambigüedad, ejemplo ”Si el ticket fue creado se enviará un mail de confir-
mación ”.
Los tests de aceptación están escritos como dijimos por el cliente y el equipo de desarrollo por
lo tanto deben estar escritos en lenguaje humano, con términos que entienda el cliente.
Mas adelante veremos como conectar estos criterios escritos en lenguaje humano con herramien-
tas de automatización de tests que permiten ahorrar mucho el trabajo en la creación de datos que
serán usados por los tests.
Comunicación y visión compartida. Todo el equipo aprende la lógica del negocio y la entiende.
Se parte discutiendo y analizando ejemplos concretos de funcionamiento, y estos se discuten
con el cliente. Incluso el Cliente aprende de su negocio y puede ofrecer mejores ideas de
implementación o el equipo sugerir cambios significativos que agilicen, optimicen los procesos
de negocio. Se refinan los ejemplos, y se logra entender que es lo que hay que construir.
Guı́a para el desarrollo, antes de programar los programadores conocen los test de aceptación,
estos ejemplos que se analizaron y crearon serán los que ayudaran a minimizar dudas y
ambigüedades que se van presentando.
¿El qué? ¿Y no el cómo?. El equipo se prepara para preguntarle al cliente que quiere y no
como hacerlo. Existen herramientas que nos ayudan en esta etapa como el Concordion6. La
mayorı́a de las veces el cliente no sabe que es lo que quiere, el equipo intenta aclarar que es
lo que quiere haciendo preguntas con afirmaciones que no tengan ambigüedades, pero nunca
el cliente deberá indicar como implementarlo, salvo casos justificados.
El entendimiento de los criterios de aceptación, ayuda a prevenir bugs, en vez de controlar que no
haya bugs al final.
Ofrece una guı́a precisa sobre cómo organizar la conversación entre desarrolladores, probadores
y expertos en dominios
Las anotaciones originadas en el enfoque BDD están más cerca del lenguaje cotidiano y
tienen una curva de aprendizaje más superficial comparada con las de herramientas como Fit
/ FitNesse.
mejoraron esto, sigue estando presente la palabra Test en las anotaciones que utilizan). Nadie niega
que TDD genera un buen conjunto de pruebas de regresión, pero ese no pretende ser su objetivo
principal, sino más bien un efecto lateral positivo.
El segundo se produce porque en todos los ejemplos que plantean sus creadores, se trabaja sobre
pequeñas porciones de código, e incluso ellos mismos hablan de pruebas unitarias. Asimismo, las
herramientas reflejan esto en sus nombres: JUnit, SUnit, NUnit, etc. Y cuando Beck escribe su libro
de TDD se basa primordialmente en ejemplos de pruebas unitarias. Pero notemos que el propio
esquema de TDD y sus ventajas exceden en mucho las pruebas unitarias.
A continuación se plantean variantes al clásico TDD que se irán describiendo brevemente.
Las pruebas en código sirven como documentación del uso esperado de las clases y métodos
en cuestión.
Muchos años a TDD se lo vio como sinónimo de pruebas unitarias automatizadas realizadas
antes de escribir el código.
UTDD habla solamente de pruebas y solo de pruebas unitarias, un motivo de este mal entendido
es su propio nombre, ya que usa la palabra Tests. Por ello la confusión de que se dice ser una técnica
de diseño y no de pruebas.
Otro motivo son las herramientas que salieron para el uso de TDD que implicaban que los test
o clases deberı́an empezar con el nombre tests. Tambien el hecho de que todos los ejemplos de TDD
que se plantean empiezan con pruebas unitarias, solo pequeñas porciones de codigo, o solo se habla
de pruebas unitarias.[24].
Con estos equı́vocos de origen, UTDD se ha aplicado con creciente éxito. Las mayores ventajas
de UTDD es que las pruebas de codigo sirven como documentacion del uso esperado de las clases
y metodos en cuestion[24].
Las pruebas en código indican con menor ambigüedad lo que las clases y métodos deben hacer.
Las pruebas escritas con anterioridad ayudan a entender mejor la clase que se está creando,
antes de escribirla.
Las pruebas escritas con anterioridad suelen incluir más casos de pruebas negativas que las
que escribimos a posteriori.
Basa todo el desarrollo en la programación de pequeñas unidades, sin una visión de conjunto.
Hay un antipatrón clásico de UTDD que es el de una clase de prueba por clase productiva y
un método de prueba por método productivo.
Relacionado con lo anterior, muchos han criticado la pretensión de que la arquitectura evolu-
cione sola, sin hacer nada de diseño previo.
Es una práctica centrada en la programación, con lo cual no sirve para especialistas del negocio
ni testers. Los testers tradicionales tienden a desconfiar de ella por este mismo motivo.
Si bien las refactorizaciones son más sencillas con pruebas automatizadas, los cambios de
diseño medianos y grandes suelen exigir cambios en las pruebas unitarias.
instancia DDD se trata de crear un ecosistema de código que captura implı́cita o explı́citamente
partes importantes de conocimiento del dominio.
TDD y DDD no son mutuamente excluyentes, tener conocimiento en DDD, es ciertamente tener
también conicimiento en TDD, sienod siempre TDD el núcleo.
DDD no es necesariamente un análisis desde arriba hacia abajo, los contextos pueden ser aco-
tados, y posiblemente el concepto mas importante de DDD es poder usar un lenguaje del cliente
en todas partes y las conversaciones con el cliente es para determinar lineas generales para el uso
de TDD.
Por ejemplo, al escribir la lógica de negocio de dominio, uno no debe estar preocupado por
el ahorro de entidades en la base de datos. En resumen, no se debe pensar en nada fuera de los
dominios al escribir la lógica de negocio.[23]
”DDD es acerca del descubrimiento de lo QUÉ es necesario escribir, PORQUÉ es necesario
escribirlo y CUÁNTO esfuerzo hay que utilizar para ello ”[51]
Arriba se habı́a dicho que DDD no era un gran conjunto de patrones, tampoco es un lenguaje
de patrones, y menos un framework, ni nada mágico ”Silver bullet”9 . Como dijimos es una filosofı́a
abstracta que no esta basada en el código sino en el entendimiento del dominio. DDD se basa en
la colaboración y exploración con los expertos del Dominio ”Domain Experts”10 , experimentación
para producir un modelo útil.
La mayorı́a de los escritos sobre DDD son de Eric Evans, donde se ve conceptos de dominio
empresarial y el intento de mapearlos en artefactos de software. Abarca modelos y diseños de
dominio, desde el punto de vista conceptual y de diseño. Se discute los principales elementos en
DDD como Entidad, Objeto de Valor, Servicio, etc. y se habla de conceptos como Lenguaje Ubicuo,
Contexto Limitado y Capa Anticorrupción.
Las directrices, mejores prácticas, los marcos y las herramientas que los técnicos y los arquitec-
tos pueden utilizar en el esfuerzo de implementación usando DDD están influenciados por varios
aspectos arquitectónicos, de diseño e implementación tales como[51]:
Reglas de negocio
Persistencia
Almacenamiento en caché
Gestión de transacciones
Seguridad
Generación de Código
Refactorización
Como dijimos anteriormente el diseño con DDD está impulsado por el dominio y existen un
conjunto de patrones para crear aplicaciones empresariales desde el modelo de dominio la aplicación
de ellos permitirá construir sistemas que realmente satisfacer las necesidades de la empresa[16].
Los principales patrones de DDD, resumidos y simplificados [51]:
Códigos y Modelos
predominantes están basados en OO, la mayorı́a de los modelos serán en OO. Los conceptos del
modelo entonces se representarán con clases e interfaces, y las responsabilidades como miembros
de las clases.
Hablando el idioma
DDD aboga para que los expertos y desarrolladores del dominio se comuniquen conscientemente
utilizando los conceptos dentro del modelo. Ası́ los expertos de dominio hablan de la propiedad y
el comportamiento subyacente que se requiere en un objeto de dominio y los desarrolladores no
hablan de nuevas variables de instancia de una clase o columnas en una tabla de base de datos,
sino que usan un lenguaje ubicuo.
Si una idea no puede expresarse fácilmente, entonces indicarı́a un concepto faltante en el modelo
de dominio y el equipo deberá trabajar en conjunto para averiguar cúal es el concepto. Una vez
que está establecido el nuevo campo en pantalla o la columna en la tabla de la base de datos, se
seguirá la idea de eso.
Al igual que gran parte de DDD, esta idea de desarrollar un lenguaje omnipresente no es
realmente una idea nueva: los XPers lo llaman un ”sistema de nombres”, y los DBAs han reunido
durante años diccionarios de datos.
Modelos y contextos
Siempre que discutimos un modelo siempre está dentro de algún contexto. Este contexto suele
inferirse del conjunto de usuarios finales que utilizan el sistema. Estos usuarios se relacionan con
los conceptos del modelo de una manera particular, y la terminologı́a del modelo tiene sentido para
estos usuarios, pero no necesariamente para cualquier otra persona fuera de ese contexto. DDD
llama a esto Contexto limitado (BC). Cada modelo de dominio vive exactamente en un BC, y un
BC contiene precisamente un modelo de dominio.
La idea es que hay varios BCs en un sistema de información, que interactúan enviando archivos,
pasando mensajes, invocando APIs, etc. Ahora, si sabemos que hay dos BCs que interactúan entre
si, sabemos entonces que hay que tener cuidado de traducir entre los conceptos de un Dominio y
los de otro Dominio de otro BC.
Entonces se plantea el discutir las relaciones entre los BCs. DDD de hecho identifica un conjunto
completo de relaciones entre BCs, para que podamos racionalizar lo que debemos hacer cuando
necesitamos vincular nuestros diferentes BCs juntos:
Publicado : los BCs que interactúan están de acuerdo en un lenguaje común (por ejemplo, un
montón de esquemas XML sobre un bus de servicios empresariales) mediante el cual pueden
interactuar entre sı́;
Open host service: un BC especifica un protocolo mediante el cual cualquier otro BC puede
usar sus servicios;
Kernel compartido : dos BC utilizan un kernel común de código (por ejemplo, una biblioteca)
como una lingua-franca común, pero de otra manera hacen sus otras cosas en su propia manera
especı́fica;
Conformista : un BC utiliza los servicios de otro pero no es un accionista a ese otro BC. Como
tal, utiliza ”tal cual”(se ajusta a) los protocolos o APIs proporcionados por ese BC;
Capa anti-corrupción : un BC utiliza los servicios de otro y no es un stakeholder, sino que tiene
como objetivo minimizar el impacto de los cambios en el BC de lo que depende al introducir
un conjunto de adaptadores - una capa anticorrupción.
A medida que descendemos en esta lista, podemos ver que el nivel de cooperación entre los dos
BCs se reduce gradualmente.
Sin embargo, cuando llegamos al conformismo , sólo vivimos con nuestra suerte; Una BC es
claramente subordinada a la otra. Para no depender tanto de un BCs significa tener mas código
que implementar, por supuesto es mas costoso, pero reduce el riesgo de dependencia. Una capa
anticorrupción también es mucho más barata que la reintroducción de ese sistema heredado, algo
que en el mejor de los casos distraerı́a nuestra atención del dominio central y en el peor terminarı́a
en fracaso.
DDD sugiere que elaboremos un mapa de contexto para identificar nuestros BC y aquellos de
los cuales dependemos o dependemos, identificando la naturaleza de estas dependencias.
Lo que llamamos mapas de contexto y BCs es DDD estratégico. Averiguar la relación entre BCs
es bastante polı́tico cuando se piensa en ello: ¿qué sistemas de upstream de mi sistema dependen, es
fácil para mı́ integrarme con ellos, tengo influencia sobre ellos, ¿ confı́o en ellos? Y lo mismo es cierto
en sentido descendente: ¿qué sistemas utilizarán mis servicios, cómo expongo mi funcionalidad como
servicios, tendrán influencia sobre mı́? No entender esto o su aplicación podrı́a ser un fracaso.
Capas y hexágonos
Viendo hacia adentro y considerar la arquitectura de nuestro propio BC (sistema). DDD sólo
está realmente preocupado por la capa de dominio y no tiene mucho que decir sobre las otras capas:
presentación, aplicación o infraestructura (o capa de persistencia).
La mayorı́a de la lógica del negocio parece filtrarse en la capa de aplicación o (aún peor) capa
de presentación. DDD trata de que no haya ninguna lógica de dominio en la capa de aplicación o
de presentación. En su lugar la capa de aplicación se hace responsable de cosas como la gestión
de transacciones y la seguridad, o como en algunas arquitecturas también puede asumir la res-
ponsabilidad de asegurar que los objetos de dominio recuperados de la capa de infraestructura /
persistencia se inicialicen correctamente antes de interactuar.
Un inconveniente de la arquitectura en capas es que sugiere un apilamiento lineal de dependen-
cias, desde la capa de presentación hasta la capa de infraestructura.
En lugar de considerar nuestra aplicación como un conjunto de capas, una alternativa es verlo
como un hexágono.
Bloques de construcción
La mayorı́a de los sistemas DDD como dijimos probablemente utilizarán un paradigma OO.
Como tal, muchos de los bloques de construcción para nuestros objetos de dominio pueden ser bien
conocidos, como entidades, objetos de valor y módulos. Objetos de valor son cosas como cadenas,
números y fechas; Y un módulo es un paquete.
Sin embargo, DDD tiende a poner más énfasis en los objetos de valor de lo que podrı́a estar
acostumbrado. Por lo tanto, sı́, puede usar una cadena para contener el valor de la propiedad
FirstName de un cliente , por ejemplo, y eso probablemente serı́a razonable. Pero ¿qué pasa con
una cantidad de dinero, por ejemplo, el precio de un producto ? En su lugar, debemos introducir un
tipo de valor de Money , el cual encapsula la moneda y las reglas de redondeo (que serán especı́ficas
de la moneda ).
Además, los objetos de valor deben ser inmutables, y deben proporcionar un conjunto de fun-
ciones de efectos secundarios libres para manipularlos.
Los valores también deben tener semántica de valor, lo que significa (en Java y C #, por
ejemplo) que implementan equals () y hashCode () . También son a menudo serializable, ya sea en
un bytestream o tal vez ay desde un formato String . Esto es útil cuando tenemos que persistir.
La introducción de objetos de valor permite ampliar nuestro lenguaje omnipresente, el compor-
tamiento de los valores mismos. Si decimos que el dinero nunca puede ser negativo, esta implemen-
tación estarı́a dentro de objeto de valor Money, y no deberı́amos asegurarnos que no sea negativo
en cada parte que se use Money.
Ahora las entidades no necesitan explicarse mucho, suelen ser persistentes, normalmente mu-
tables y tienden a tener una vida de cambios de estado. En su libro Evans habla de contornos
conceptuales , una frase elegante para describir cómo separar las principales áreas de interés del
dominio. Los módulos son la forma principal en la que se realiza esta separación, junto con las
interfaces para asegurar que las dependencias de módulos sean estrictamente acı́clicas.
Escribir las expectativas para describir los servicios que el objeto receptor requiere del resto
del sistema.
Cuando llegas a un punto en el que necesitas una función, o un módulo que no existe, sim-
plemente haces el desarrollo de la simulación y continuas con el módulo actual. El desarrollo de
esta manera tiene ventajas distintas. En primer lugar, permite que cada módulo evolucione de for-
ma natural, como segunda ventaja ahorra tener que predecir la interfaz de un módulo, el cual se
necesitará antes de tiempo.
Los objetos Mocks también mejoran el proceso de desarrollo al facilitar una metodologı́a conoci-
da como pruebas basadas en la interacción. Las pruebas simplemente verifican que un módulo dado
interactúa con otros módulos de una manera esperada y produce un resultado esperado basado en
un conjunto dado de entradas.
heredado se debe construir un set de pruebas unitarias que cubran el comportamiento del objeto
que deseamos modificar.[39]
Esto puede ser muy ambiguo y para cada caso muy diferente de encarar, mas si el código es
extenso, pero para clarificar un poco debemos enfocarnos en que funciones debemos dedicar nuestros
esfuerzo en hacer el set de pruebas que parte del código. Para esto TDM recurre a las heurı́sticas,
como por ejemplo el tamaño de la función, la frecuencia de modificación, frecuencia de corrección
de defectos, entre otros.
Una clasificación utilizada es :
Modificación:
• MFM - (Most frequently modified) Las funciones que fueron modificadas más veces desde
el inicio del proyecto, tienden a decaer con el tiempo permitiendo la aparición de defectos.
• MRM - (Most recently modified) Las funciones que fueron modificadas recientemente,
tienen mayor tendencia a tener defectos (debido a los cambios recientes)..
Corrección de Defectos:
• MFF - (Most frecuently fixed) Las funciones que fueron corregidas más veces desde el
inicio del proyecto y las funciones que fueron corregidas muchas veces en el pasado,
tienen más probabilidades de tener defectos en el futuro.
• MRF - (Most recently fixed) Las funciones que fueron corregidas recientemente, tienen
más probabilidades de tener defectos en el futuro.
Tamaño:
Riesgos:
• CR - (Change Risk) Las funciones más riesgosas definidas por el número de corrección
de defectos divididas por el total de número de cambios. Por ejemplo, una función que
cambia 10 veces y 9 de ellas era para corregir defectos, deberı́a tener una prioridad
mayor de ser testeada que una función que fue cambiada 10 veces, pero sólo una fue
para corregir defectos.
Aleatorio:
• Random - Seleccionar funciones de manera aleatoria para escribir casos de prueba puede
considerarse como el escenario de lı́nea base, por lo tanto usamos el rendimiento de la
heurı́stica aleatoria para comparar el rendimiento de las otras heurı́sticas. Entre las cosas
que encontré mientras escribı́a este artı́culo, hay una afirmación en la que se expresa que
de todos los métodos anteriormente descriptos, los que mejores resultados generan son
LM (Largest Modified) y LF
• (Largest Fixed) “Aún combinando diferentes criterios para intentar mejorar el rendi-
miento, LM y LF se mostraron imbatibles”.
El uso de TDM reduce la cantidad de errores mejorando la calidad del producto. El resultado final
es un sistema más sólido ya que garantiza que por el despliegue de las pruebas, el momento y la
forma en que se realizan los cambios funcionen, en comparación con los métodos tradicionales en
los que el código sólo se prueba mucho tiempo después de su ejecución, obligando al desarrollador a
pensar en pequeños trozos de código que pueden ser probados de manera aislada e independiente.
En resumen su metodologı́a sigue los siguientes 5 pasos, que se repiten a modo de ciclo:
1. Se extrae información histórica (de nuestro repositorio de código y base de datos de bugs
registrados).
6. Vuelta al paso 1
El principal obstáculo de esta metodologı́a es la reticencia inicial del equipo para adoptar ésta
técnica. Principalmente porque los desarrolladores que deben escribir más código de lo usual. La
curva de aprendizaje es alta, y los lenguajes de programación que no contemplan el marco de
pruebas unitarias puede ser una tarea difı́cil.
Se suele decir que el mismo código es la documentación del sistema, pero muchas veces no suele
ser suficiente para entender la funcionalidad, por lo que naturalmente hay un rechazo a modificar
una porción de código al no querer generar errores en otras partes del sistema.
Pero todos estos miedos y rechazos a implementar TDM hay que superarlo ya que los beneficios
pueden ser muchos, como por ejemplo menos errores y perı́odos de mantenimiento más cortos, es
lo que nos dice Michael Feathers en su libro ”Working Effectively with Legacy Code”.
ATDD BDD
Requerimiento (US)14 =¿Pruebas de acepta- US con lenguaje del negocio =¿UAT con len-
ción (UAT)15 guaje de comportamiento
Los principales puntos en el desarrollo ágil es la entrega continua y regular de valor. Por ello
existen muchas técnicas como la integración continua (CI), la cual nos ayuda a tener un software
compilable en todo momento. Pero no basta con que el software únicamente se pueda compilar,
de hecho es el primer paso de toda una serie de elementos y caracterı́sticas que debe cumplir el
software.
Otra práctica que mitiga los niveles de riesgos introducidos por los cambios con modificaciones
solicitadas o realizadas durante un sprint de desarrollo, es el ejecutar constantemente pruebas de
software automatizadas, las que deben estar presentes en las diferentes fases del ciclo de vida del
software. Aquı́ es donde aparece TDD como una práctica de software para algunos o metodologı́a
según otros,y por consiguiente la refactorización.
La refactorización es un tema bastante interesante y complejo, que lleva a una serie de muchos
otros como son los patrones de diseño, los ”malos olores.en el código, etc. que estaremos desarrollando
en este capı́tulo.
Lo más recomendable es que la propia refactorización sea parte del proceso de desarrollo que
surja como algo natural .
4.1. Refactorización
En la refactorización el objetivo es reescribir el código de manera de obtener un mejor diseño. Un
código más simple sin ninguna lı́nea innecesaria, siempre tratando de minimizar y dar eficiencia. La
idea es, no hay que buscar errores y corregir sino reescribir el código, idea de los gurús del software
libre[47].
El convencimiento de que la inclusión de pruebas (que nos da TDD), y que la corrección de
errores será algo mucho más costoso en el futuro que la propia reescritura ayuda al que el software
sea mantenible.
Tener un sistema mantenible, simple habré muchas posibilidades. Los nuevos desarrolladores
48
Capı́tulo 4. Prácticas y técnicas con TDD
que entren al proyecto y quieran realizar aportes no se verán contra una pared con el código.
En refactorización no es necesario tener el conocimiento de toda la infraestructura para poder
aportar un código simple y fácil de entender, ni de tenerla creada antes de refactorizar. Complicado
serı́a tener que crear una infraestructura que pueda preveer todas las funcionalidades futuras,
incluso las que todavı́a no se han llegado a pensar, por lo que si no refactorizamos acabará siendo
un impedimento.
Con la refactorización continua se podrı́a evitar que aplicaciones enteras sean reescritas, porque
los errores de diseño, la calidad del código y otros parámetros hacen imposible mantener la antigua
versión.
En el caso de un sistema legacy la refactorización permite tomar diseños defectuosos, con códi-
go mal escrito (duplicidad, complejidad innecesaria, por ejemplo) y adaptarlo a uno bueno, más
organizado.
La refactorización también muestra que el diseño no se da solo al inicio, sino también a lo largo
del ciclo de desarrollo, durante la codificación, de manera tal que el diseño original no decaiga.
Antes de hablar un de los pasos o consejos sobre que refactorizar, vamos a definir los tipos de
refactorización.
La refactorización tiene como prioridad la conservación del comportamiento del codigo, por
lo que primeramente deberiamos tener clara idea de lo que esto significa. Opdyke[41] definió y
demostró la preservación del comportamiento del código a través del proceso de refactorización.
Opdke dice:
3. Los miembros de una misma clase y las funciones deben tener nombres distintos.
4. En las redefinición de una función, las signaturas deben ser compatibles (para preservar el
principio de substitucón de Liskov[41])
2. composite refactorings (refactorizaciones compuestas) los cuales se construyen con las de bajo-
nivel. Dado que las compuestas están construidas usando refactorizaciones que preservan el
comportamiento, entonces el comportamiento se conserva si también las precondiciones son
cumplidas.
Se define una cierta metodologı́a particular de cuando y cuanto refactorizar, es una secuencia
similar a la siguiente:
4. Repetir los pasos anteriores para encontrar más refactorizaciones que aplicar.
Además, existen algunas importantes heurı́sticas a tener en cuenta durante el proceso, que tienen
mucha relación con lo anteriormente expuesto.
1 Opdyke define equivalencia semántica, cuando una función es llamada dos veces, una antes y otra después, y en
Uso estricto de las pruebas. Al realizar pruebas en cada paso se reduce el riesgo del cambio,
siendo este un requisito obligatorio tras la aplicación de cada refactorización individual.
Martin Fowler también define en su libro una serie de pasos sistemáticos que se pueden realizar
en la refactorización, pero desde el punto de vista de criterios para modificar el código. Con técnicas
que están claramente definidas.
Fowler [37] habla de ‘bad smells’, código que ‘huele mal’, y nos da pistas sobre como localizarlo:
código duplicado, métodos o clases demasiado extensas, listas de parámetros muy grandes, son
pistas de que es necesaria una intervención importante. La idea es crear un codigo cohesivo y
modular, también se revisan nombres inadecuados y acoplamiento. [26]
Fowler realizó un estudio sobre las técnicas de refactorización dando patrones de modificación
de código con el fin de obtener un resultado con la misma funcionalidad pero con un diseño más
simple y sencillo de comprender.
de defectos de diseño a un nivel más global, como los antipatrones4 . Dichos Code smells son indi-
cadores o sı́ntomas de la posible presencia de Design smells. Fowler presenta veintidós Code Smells
en su libro [37], todos ellos estructuras en el código fuente que sugieren la posibilidad de refacto-
rizaciones. Duplicated code, long methods, large classes, y long parameter lists, son sólo algunos
sı́ntomas de Design smells y de oportunidades de refactorización de entre los veintidós presentados.
“Se utiliza el término “smell” para designar tanto los errores en código (Code smells) como los
Design smells. Este uso no excluye que, en un contexto particular, un smell pueda ser la mejor
forma de diseñar o implementar de manera efectiva un sistema” [38].
Además hay otros Design Smells a tener en cuenta como Bad Pattern Usage(Referente a la mala
aplicación de un patrón en el código a analizar como puede suceder, por ejemplo, con el patrón
Singleton, lo que nos lleva a los antipatrones) o Metrics Warnings (Donde la herramienta detecta
defectos a través del cálculo de métricas).
También estan las Disharmonies: “Defectos de diseño que afectan a entidades individuales tales
como clases y métodos”[33].
Para tener una guia de que refactorizar se puede empezar con listas de antipatrones (que se
pueden encontrar en [11] [56], Bad Smells y de Disharmonies. Debido a su proceso de constante
ampliación y a su gran variedad existe un catalogo de ellos. Se podra consultarlos en el Anexo I de
este trabajo.
Ahora para aplicar refactorización con TDD nos enfocaremos en los que nombra Fowler[37].
Método largo (Long Method): Los programas con orientación a objetos viven mejor y
tienen mantenibilidad, estabilidad son los que tienen métodos mas cortos. Se suele decir que
en algunos objetos nunca ocurre ningún calculo, que hay infinitas secuencias de delegación,
pero cuando se ha estado con un programa por muchos años, se aprende lo valioso que es
4 “Un antipatrón es una forma literaria que describe una solución recurrente que genera consecuencias negativas
[11]
método. Si se tiene un método con muchos parámetros y variables temporales, elementos que
se interponen en la forma de extraer métodos, a veces terminas pasando tantos parámetros
y variables temporales como parámetros al método extraı́do que el resultado es escasamente
más legible que el original. Para esto se puede reemplazar las variables utilizando un objeto
que las contenga. ¿Cómo identificar porciones de código para extraer?, una técnica es buscar
comentarios, a menudo indican una porción de código que realiza una determinada función
que puede ser extraı́da, otra forma es buscar condiciones y bucles. En un bucle se puede
extraer el código dentro del bucle y ponerlo en un método nuevo.
Clase extensa (Large Class): Cuando una clase está tratando de hacer demasiado, a
menudo se ve una larga lista de instancias de variables y cuando esto ocurre seguro puede
haber código duplicado. Se puede agrupar algunas variables usando .Extracción de Clase”,
crear una nueva clase o subclase Usando extracción de método, se puede reducir un montón
el código de una clase. Si se tiene muchos métodos con un montón de código en común, se
puede convertirlos en métodos de diez lı́neas con otros métodos de dos lı́neas extraı́dos del
original. Un forma util es determinar cómo los clientes usan la clase y ası́ determinar como se
puede romper la clase.
Lista de parámetros larga (Long Parameter List): Se nos ha enseñado a pasar a una
rutina tantos parámetros como necesite, es comprensible porque la alternativa era variables
globales, y esto es malo, hasta podrı́amos decir doloroso de mantener, refactorizar, y entender.
Con los objetos podemos cambiar esta situación, porque si necesitamos algo podemos pedı́rselo
a un objeto. En los programas orientados a objetos, las listas de parámetros tienden a ser
mucho más pequeñas que en programas tradicionales. Esto es bueno porque las listas de
parámetros largos son difı́ciles de entender, porque se vuelven inconsistentes y difı́ciles de
usar, y esto es para siempre por que se necesita cambiar continuamente a medida que necesite
más datos. La mayorı́a de los cambios se eliminan pasando objetos porque es mucho más
probable que necesite hacer sólo un par de peticiones para obtener una nueva pieza de datos.
cambio. Cuando no se puede hacer esto es porque algo está .oliendo mal”. El cambio diver-
gente ocurre cuando una clase es comúnmente cambiada de diferentes maneras por diferentes
razones. Si se observa una clase y ocurre que en ella se tendrá que cambiar algunos métodos
cada vez que se modifique algo en la base de datos, y otros métodos cada vez que cambie una
lógica de negocio, es probable que tengamos una situación en la que dos objetos son mejores
que uno. De esta manera cada objeto se cambia sólo como resultado de un tipo de cambio.
Por supuesto, esto se descubre por haber agregado varias veces cambios en la base de datos o
instrumentos de lógica de negocio. Cualquier cambio deberı́a preveer un cambio en una sola
clase y toda una nueva clase expresar la variación. Para refactorizar esto,se debe identificar
todo lo que cambia por una causa en particular y usar Extract Class para juntarlos.
ner todos los cambios en una sola clase. Si ninguna clase actual parece ser un buen candidato,
se crea una. A menudo se puede usar el método Ïnline Class”, que es clase que proporciona
una base que contiene un montón de comportamientos juntos. De este modo se realiza un
poco de cambio divergente, pero se puede manejar más fácilmente cuando es una clase la
que sufre muchos tipos de cambios, y la cirugı́a de escopeta es un cambio que altera muchas
clases. Un ”mal olorçlásico es un método que parece estar más cómodo o interesado en una
clase distinta de la que realmente está.
Agrupaciones de datos (Data Clumps): Los datos tienden a ser como los niños; disfrutan
colgando alrededor en grupos juntos. A menudo,se ve los mismos tres o cuatro datos juntos
en un montón de lugares: campos en un par de clases, parámetros en muchas firmas de
métodos. Los grupos de datos que cuelgan juntos deberı́an ser un objeto. Utilizar extraer
clase en los campos para convertir los agregados en un objeto. Luego introducir el objeto
como parámetro. El beneficio inmediato es que se reduce muchas listas de parámetros y se
simplifica las llamadas a métodos. Una buena prueba es considerar la eliminación de uno de
los valores de los datos. Evaluar si los demas tendrian sentido, si no lo tienen es una señal
segura de que hay un objeto decidido a nacer.
Sentencias switch (Switch Statemetns): Una de las consecuencias más obvias del código
orientado a objetos es la falta de comparaciones switch (o caso). El problema con las sentencias
switch es esencialmente de la duplicación. A menudo se encuentra la misma instrucción switch
en diferentes lugares. Si se agrega una nuevo caso se tiene que encontrar en todas las partes
donde aparece el mismo switch y cambiarlo. La programación orientada a objetos tiene una
solución elegante a esto, usando polimorfismo.
Clase perezosa (Lazy Class): Cada clase que se crea cuesta dinero, mantenimiento y
entendimiento. Una clase que no está haciendo lo suficiente para pagar esto por sı́ misma,
entonces debe ser eliminada. A veces la clase tenı́a un sentido en un principio, pero luego de
algunas refactorizaciones perdió responsabilidad y sentido. Lo que se puede hacer es colocar
esa responsabilidad en otra clase. En este caso se utiliza un Inline Class y se lleva esto a esa
última clase, eliminando definitivamente a la clase perezosa.
que no fueron requeridas. El resultado de esto, es un código difı́cil de entender y por lo tanto
de mantener. La complicación viene cuando aparece un nuevo requerimiento y este debe
incorporase a toda esa funcionalidad .agregada”, que contempla cosas no pedidas. Claro que
siempre está la opción de refactorizar, pero el criterio serı́a no hacer cosas de mas, y esperar
a que los requerimientos nuevos lleguen.
Campo Temporal: Existen variables de instancia que parecen usarse sólo en algunos casos,
esto se vuelve confuso de entender en cuáles. Es mejor usar el extraer método y poner estas
variables en otra clase para crear un hogar para las variables huérfanas. Poner todo el código
que se refiere a las variables en el componente. Un caso común de campo temporal se produce
cuando un algoritmo complicado necesita varias variables. Porque el ejecutor no quiere pasar
alrededor de un enorme lista de parámetros.
Cadenas de mensajes (Message Chains): Estas cadenas aparecen cuando un cliente pide
un objeto a otro objeto y a su vez llama a éste último para obtener otro objeto. De esta
manera, el cliente se acopla a toda esta estructura de navegación y cualquier cambio en ella le
afectará. Es mejor crear un objeto delegado que encapsule la navegación y abstraiga al cliente
de ella.
”Hombre en el medio”(Middle Man): Tiene que ver con el caso anterior, no es necesario
que se cumpla estrictamente. A veces, si existen muchos métodos que delegan a una misma
clase, es mejor quitarnos el delegado y referirnos a ella directamente.
Clase de librerı́a incompleta (Incomplete Library Class): A veces una clase no realiza
todo lo que necesitamos y debemos adaptar su uso a lo que se requiere, ya que no podemos
modificarla.
Clase de datos (Data Class): Las clases que solo tienen datos getters y setters son mani-
puladas en gran medida por otras clases. Podemos buscar este comportamiento para llevarlo
a las clases que contienen los datos.
Legado rechazado (Refused Bequest): A veces una subclase no usa todos los métodos que
hereda de su clase padre. Esto puede significar que la jerarquı́a no es correcta y los métodos
de las clases se deben mover a donde se usan realmente.
Comentarios (Comments): Los comentarios suelen marca el área en el código que se puede
usar el método de Extract Method. Es mejor invertir el tiempo en mejorar este código que en
comentarlo.
JustCode (Telerik)
ReSharper (JetBrains)
CodeRush (DevExpress)
lidades que esta incorporando. Por supuesto también tendrá el feedback necesario cuando una de
sus funcionalidades pueda ocasionar errores en resto del sistema.
Ahora si vamos a un enfoque más técnico, ¿qué es Integración Continua?. Dijimos que era una
práctica de desarrollo, en ella los miembros del grupo de desarrollo integran (compilan y ejecutan)
los componentes de un proyecto con una frecuencia especificada.
Cada programador en su estación de trabajo ”baja.el código fuente del proyecto, integra a este
el código de su autorı́a y luego compila. Luego debe correr los tests en su máquina a fin de detectar
errores de integración lo antes posible, serı́a la primera integración que se realiza, en la maquina
del programador.
Esto reduce significativamente los problemas de integración al detectar errores en la maquina
local del programador, permite tener un software cohesivo más rápido.
Un escenario tı́pico de CI[3][21]se compone de la siguiente manera:
El servidor de CI genera feedback con los resultados del proceso de building, el cual es enviado
a los miembros que se especifique del proyecto.
Calidad de proceso
Otorga visibilidad al proceso de desarrollo, por el hecho de que todos los pasos que se siguen
para implementarlo se siguen desde que se empieza a programar un requerimiento hasta que el
software está en producción.
Todos los miembros del equipo saben que fases pasa el código, y el estado de desarrollo en cada
momento. Podemos saber si compila, si pasa las pruebas, que versión incorporó ciertas funcionali-
dades, el origen de un error (si se da a partir de cierta incorporación de código), que versión paso
las pruebas completas, etc.
También se puede ver que necesidades se tienen en la gestión de configuración, que polı́ticas de
control habrı́a que implementar, necesidades de instalación de componentes particulares incorpo-
rados a cada versión, entre otras cosas más.
Si el equipo no conocı́a los pasos para la configuración del software que deben estar definidas,
con la CI todos deben saberlo. Es importante destacar que en una fase de integración también
estamos realizando una prueba de sistema, de compatibilidad.
Por otro lado, también se mejora la calidad del producto software[20]. El principal objetivo de
la CI es detectar los errores lo más pronto posible, en fases tempranas del desarrollo, para poder
solucionarlos rápidamente.
Con la introducción de pruebas y comprobaciones de compatibilidad, de recursos, los riesgos
se van minimizando, el software resultante tiene menos errores y una mayor confiabilidad. Todo
esto lo conseguimos con la CI. Pero si en fases mas avanzadas de CI se incorporan herramientas
que sirvan para inspecciones continuas de código, análisis periódicos para detectar problemas de
calidad en él; incluso se puede impedir que desarrolladores suban el código al control de versiones
si no cumplen los estándares de calidad definidos por la empresa.
Mejores programadores
El equipo se mejora, se hace mas eficiente, esta mejor preparado, ya que la contribución continua
del código facilita el aprendizaje continuo, el conocimiento de la lógica de negocio y la capacitación,
el equipo acaba aprendiendo a hacer distintos tipos de pruebas (unitarias, de integración),se dan
mejores prácticas de programación y en general se desarrolla código de mayor calidad.
Los desarrolladores obtienen mas confianza en su código al realizar distintas comprobaciones y
al saber que el resto del equipo también pudo ver y revisar su código, por ende el equipo tiene mas
confianza. Serán capaces de afrontar nuevos retos, mejoras, cambios y estarán más motivados.
Sin hablamos de tiempo, seguro estarı́amos de acuerdo que los tiempos en un desarrollo de
software con CI es mucho mas productivo y menor, a un desarrollo sin ella. Los procesos repetitivos
son automatizados, dejando más tiempo para hacer otras cosas.
1. Repositorio de código: La herramienta que permite que el equipo trabaje de forma total-
mente sincronizada, pero a la vez sencilla. Cada uno trabaja en su parte y puede actualizar los
cambios sin necesidad de que otros desarrolladores tengan que esperar por estos y viceversa.
3. Commits diarios: No todos los requisitos se basan en tener un determinado tipo de he-
rramienta, algunos se basan en saber cómo utilizar una determinada herramienta. Una vez
que tenemos un control de versiones hay que recordar que el almacenamiento de los cambios
debe ser diario, idealmente un desarrollador debe hacer incluso varias subidas al repositorio
de código al dı́a.
Si tenemos un repositorio de código, pero cada desarrollador sube sus cambios cada dos
semanas seguimos en el mismo problema de antes, la integración del proyecto se retrasa
durante todo ese tiempo, perdiendo toda opción de obtener información inmediatamente.
5 Segmentación
Además, retrasar la integración tanto tiempo genera más conflictos entre los ficheros editados
por los desarrolladores. Debido a que con cada actualización del repositorio se hace una
integración del proyecto completo, cada mı́nimo cambio que no desestabilice el proyecto debe
ser subido para que se compruebe que todo sigue funcionando correctamente.
4. Pruebas unitarias: Hemos hablado todo el tiempo de comprobar que el proyecto funciona
correctamente y al mismo tiempo de automatizar todo el proceso lo mejor posible. Para
poder comprobar que el proyecto funciona de forma automática necesitamos pruebas unitarias
(muchas veces incluso pruebas de integración).
Existen muchas maneras diferentes de incluir tests en el proyecto, personalmente creo que
TDD es la manera más adecuada, pero si el equipo no tiene experiencia y crea las pruebas
después de haber realizado la implementación tampoco es un método inválido. La premisa
fundamental es que toda nueva funcionalidad debe tener una baterı́a de pruebas que verifique
que su comportamiento es correcto.
5. Servidor de integración: Esta es la pieza más polémica, mucha gente cree que no es ab-
solutamente necesaria para hacer CI correctamente, por ejemplo, algunos equipos hacen la
integración de forma manual con cada subida al repositorio de código. En mi opinión es un
paso tan sencillo y barato de automatizar que no merece la pena ahorrárselo. Montar algún
servidor de integración, como por ejemplo Jenkins o Cruise Control, es gratuito y tan senci-
llo como desplegar un fichero en un servidor. Por contra las ventajas son grandı́simas. Para
empezar el proceso está totalmente automatizado, lo que evita el error humano. Y por otro
lado reduce la cantidad de trabajo, ya que tenemos una solución prefabricada sin necesidad
de tener que crear nosotros mismos complejas soluciones caseras.
4.2.3. Beneficios
La lista de beneficios identificados según diversos autores de usar CI son los siguientes:
Reducción del riesgo: Nos referimos al riesgo intrı́nseco que todo proyecto tiene por su
carácter de temporal y único. Esto da origen a la necesidad de una gestión de riesgo como
algo fundamental en la gestión de proyectos [44]. En el desarrollo de software todavı́a no se
tiene la visión global de un proyecto debido a que los requerimientos pueden ir cambiando,
por lo que no se tienen en cuenta los riesgos que hay que asumir. Los riesgos que se puedan
asumir al integrar diferentes componentes no son analizados. La integración de componentes
se hacen durante las últimas etapas en el desarrollo. Muchos proyectos de desarrollo fracasan
debido a tiempos lejos de los estimados en la entrega, lo que suma costos no previstos. La
CI permite reducir el riesgo en la integración de componentes por que los problemas son
detectados antes.
Eliminación de errores: Eliminar defectos, detectarlos con anticipación es mucha más fácil
con CI. El hacer pruebas en periodos cortos de tiempo aumenta garantı́as de que los fallos
serán mucho menos o que los mismos aparecerán tempranamente.
Andres Hunt con David Thomas ambos firmantes del manifiesto ágil dicen en el libro ”Prag-
matic Programming”que Üno de los beneficios de detectar problemas lo antes posible es que
un puede estrellarse antes. Y muchas veces, estrellar su programa es el mejor cosa que puedes
hacer.”, .Es mucho más fácil encontrar y diagnosticar el problema al estrellarse temprano”.
Mejores relaciones con los clientes: Normalmente se escribe software para personas, a
menudo uno se acuerda de obtener los requisitos de ellos. Realizar pequeñas entregas ayuda
a eliminar barreras entre los clientes y los desarrolladores, las caracterı́sticas del software son
rápidamente visibles, creando un ambiente colaborativo.
Estimaciones más acertadas: Cada integración es verificada con una secuencia de tareas de
construcción automática la cual es acompañada de pruebas para detectar errores tan rápido
como sea posible. Además, se generan informes para mostrar el resultado de cada integración.
Al tener una dea mas real del estado del proyecto desarrollado se puede estimar cuanto tiempo
falta para acabar con las funcionalidades requeridas, esto se puede lograr con mayor certeza.
La CI evita la aparición del llamado Big Bang que se origina cuando se realiza una unica
integracion al final del desarrollo[45].
Reducción de costos: Al detectar algunos de los errores lo antes posible gracias al uso de
CI trae el beneficio de una reducción de costos ya que este aumenta exponencialmente en
cada fase en la que aún no se haya descubierto dicho fallo según Barry Boehm, 20026 En
otras publicaciones se han confirmado las teorı́as de Boehm, se explica que reparar un defecto
6 Barry W. Boehm (n. 1935) es un ingeniero informático estadounidense y también es profesor emérito de esta
materia en el departamento de ciencias tecnológicas en la Universidad del Sur de California. Es conocido por sus
múltiples aportes a este campo.
4.2.4. Inconvenientes
Desmejoramiento de la arquitectura:Los desarrolladores se centran más en la resolución
de las cosas en el corto plazo, debido a esto la arquitectura sufre una degeneración.
Posible sobrecarga del sistema: Se hacen continuamente integraciones del código, esto
puede hacer que el sistema este sobrecargado en ciertos momentos, no suele ser un problema
muy importante.
Miedo a subir código erróneo: Los desarrolladores generalmente suelen resentirse a subir
su código al repositorio ya que debe coexistir con él todo, surgen dudas y miedos de causar
problemas con el código de los demás. Pese a todo, siempre será más problemático subir el
código completo en una única iteración que hacerlo progresivamente con la práctica de la CI.
depende del tipo lenguaje utilizado que se encargan de realizar las compilaciones, ejecutar las
pruebas y realizar los informes.
Para cada tipo de tarea o proceso existen herramientas, a continuación se detallarán algunas de
ella segun las funciones que cumplen dentro del proceso de CI.
Búsquedas: Posibilidad de hacer búsquedas de distintos tipos y filtros según criterios como
usuarios.
Readmine
Redmine es una aplicación Web flexible de Gestión de Proyectos. Se escribio usando Ruby on
Rails, es multiplataforma y cross-database[29]. Tiene licencia GNU (General Public License v2
(GPL), de código abierto.
Caracterı́sticas:
Foros de proyectos
Soporte multilingüe
En la captura podemos ver que los módulos disponibles para un proyecto son ”Peticiones”,
que se refiere a errores reportados, nuevas caracterı́sticas o cambios solicitadas en un proyecto, el
manejo de Documentos, Foros, Control de tiempo, Archivos, visualización de Calendario, Noticias,
Wiki y el diagrama de Gantt.
La aplicación cuenta con un Dashboard o Vistazo, donde podemos visualizar las peticiones
realizadas, la lista de miembros del proyecto, y el tiempo dedicado al mismo. Las peticiones son
ordenadas por su tipo : Bugs, Caracterı́sticas, Support.
También cuenta con la opción de menú para ver el diagrama de Gantt según las peticiones
ingresadas, un resumen de las listas de Actividades ( conjunto de peticiones).
Los estados de cada petición son Nuevo (New), Resuelto (Resolved), En Progreso (In Progress),
retroalimentación (FeddBack), Cerrado (Close), Rechazado (Reject).
La herramienta Redmine es intuitiva, reúne las necesidades básicas para la gestión de tareas y
el seguimiento de proyectos. Cuenta con la opción de incorporar plugins que aumentan las funcio-
nalidades. También podemos mejorar su visualización con temas.
Easy Redmine es una versión mejorada de Redmine, es un plugin gigante y siempre es compatible
con la última versión de Redmine.
La siguiente lista muestra algunas de las caracterı́sticas que incorpora Easy Redmine[22]
Estadı́sticas de proyecto
Con Easy Redmine, Redmine se convierte en herramienta poderosa y amigable. Podemos decir
entonces que Redmine cumple con todas las caracterı́sticas que se eligieron para analizar.
BaseCamp
Basecamp es una aplicación que está muy bien considerada y valorada como organizador, gestor
de tareas para equipos de personas que trabajan de manera colaborativa. Desde su aparición en
2004, esta herramienta de gestión de proyectos online, cuenta con 5 millones de usuarios. Fue
desarrollado por 37 Signals, una pequeña empresa americana con sede en Chicago que predica la
simplificación de las herramientas de productividad y de los métodos de trabajo.
Es una aplicación comercial, que ofrece herramientas básicas de gestión de proyecto (lista de
tareas, compartir archivos, etc.) se basa en una receta simple: la utilidad óptima más que la multi-
plicación de funcionalidades que no siempre son explotadas y la circulación de la información fluida
entre colaboradores, gerentes y clientes[6].
En la misma página oficial de BaseCamp se puede realizar la registración en forma gratuita por
un periodo de 30 dı́as.
En BaseCamp se puede administrar proyectos, equipos de desarrollos, lista de clientes y podcast7
y clientes. Una vez que se ingresa a la aplicación se puede gestionar un calendario personal, la
actividad reciente, cuales tareas se nos fue asignada y otras opciones mas.
Basecamp es una herramienta que cuenta con la funciones básicas y hasta algunas más avanzadas
para la gestión de proyectos. Su principal diferencia con RedMine es que tiene una sección de
7 El podcasting o podcast consiste en la distribución de archivos multimedia (normalmente audio o vı́deo que
suelen ser de corta duración, que pueden incluir texto como subtı́tulos y notas) mediante un sistema de redifusión
(RSS) que permite opcionalmente suscribirse y usar un programa que lo descarga para que el usuario lo escuche
GitLab
GitLab es un proyecto de software libre de la compañı́a del mismo nombre que está programado
en Ruby, es una suite completa que permite gestionar, administrar, crear y conectar repositorios
de código con diferentes aplicaciones y hacer todo tipo de integraciones con ellas. Incluye módulos
para revisar ficheros con facilidad, revisar diffs entre los mismos de una manera muy visual de todos
los commits, y ver dónde se producen los cambios.
Incluye un completo sistema de integración continua que cubre todas las fases, desde el test
hasta el despliegue y que además es compatible con Docker8 , tanto como para correr todos los tests
en el ambiente que nosotros queramos como para crear máquinas Docker dentro del registro de
contenedores que provee GitLab.
GitLab es una herramienta online orientada a la administración de nuestro código, depende
mucho el alcance de lo que denominamos gestión de requisitos, si incluimos principalmente código,
hitos y seguimiento de problemas, Gitlab puede satisfacer la necesidad. Es posible completar Gitlab
con herramientas de terceros que se integran con su API como Taiga9 , con esta nueva herramienta
GitLab se convierte en una aplicación de gestión de requisitos más completa al incorporarse otros
módulos como backlogs, wiki, videoconferencia, actualización de equipo y gracias a su potente API
permite la integración con servicios de terceros como Slack, GitHub, GitLab, Bitbucket, HipChat,
Gogs, Hall entre otros.
Como se puede ver en la captura GitLab es una herramienta para gestionar las versiones de
código alojadas en distintos tipos de servidores de control de versiones. Con las opciones de gestión
de equipos avanzada.
Taiga en cambio incorpora muchas funcionalidades que hacen a GitLab-Taiga una completa
herramienta para la gestión de proyectos de desarrollo de software. Taiga posee las funcionalidades
básicas de las metodologı́as Scrum y Kanban, incorpora la filosofı́a de ambas.
Una vez que nos registramos gratuitamente en Taiga sitio web tree.taiga.io, elegimos que me-
todologı́a utilizar. A modo de ejemplo se eligió SCRUM. Al igual que Redmine permite gestionar
estados en las Historias de Usuarios creadas en el proyecto.
El conjunto GitLab+Taiga[52] proveerı́a de revisiones de código y una completa herramienta
para gestión de proyectos en metodologı́as SCRUM y Kanban. Con la opciones de control de flujo
8 Docker es un proyecto de código abierto que automatiza el despliegue de aplicaciones dentro de contenedores de
software, proporcionando una capa adicional de abstracción y automatización de Virtualización a nivel de sistema
operativo en Linux.
9 Taiga es una herramienta de software libre y código abierto, creada para gestionar y colaborar en proyectos
ágiles, principalmente aquellos que utilizan metogologı́a Scrum y Kanban, además permite gestionar issues.
Collabtive
Collabtive sus funciones para la gestion de proyectos son muchas, permiten planificar, organizar
y coordinar todo tipo de proyectos de una manera fácil, automatizada y colaborativa.
Si bien Collabtive cuenta con una interfaz de trabajo muy intuitiva y con módulos que facilitan
el desarrollo y gestión de proyectos de todo tipo. Siendo una alternativa muy buena y destacable
frente a las opciones comerciales existentes, no incorpora funciones para la gestión de requisitos
como son los diagramas de Gantt y la posibilidad de asignar estados a las tareas que quizás para
la emisión de informes y la comunicación con el cliente pueden llegar a ser importantes.
JIRA Software
JIRA es una aplicación online comercial para el seguimiento de errores, de incidentes y para
la gestión operativa de proyectos. Jira también se utiliza para el desarrollo de software, sirviendo
de apoyo para la gestión de requisitos, seguimiento del estatus y más tarde para el seguimiento de
errores. Jira puede ser utilizado para la gestión de procesos y para la mejora de procesos, gracias a
sus funciones para la organización de flujos de trabajo.
Jira está basado en Java EE que funciona en varias bases de datos y sistemas operativos. La
herramienta dispone también de paneles de control adaptables, filtros de búsqueda, estadı́sticas,
RSS y función de correo electrónico.
Presume ser la herramienta de desarrollo de software lı́der de los equipos ágiles, las metodologı́as
con las que trabaja son SCRUM y Kanban.
Permite la creación de historias de usuario e incidencias, planificar sprints y distribuir tareas
entre un equipo de software.
Cada equipo cuenta un proceso único para lanzar software. Utiliza un workflow predefinido o
adaptado a la forma de trabajar de un equipo[5].
JIRA es una completa herramienta para la gestión de proyectos de software, se basa la filosofı́a
Trello
Potenciadores básicos
Tiene una versión gratuita y dos versiones comerciales, una incorpora aplicaciones integradas,
resúmenes de equipos y mayor seguridad, y otra versión para empresas.
Esta herramienta está diseñada para hacer uso del método Kanban, proporcionando un mejor
flujo de trabajo al dividir un proceso productivo en varias fases perfectamente delimitadas.
Cada tarea es una tarjeta a la cual se le puede dar una puntuación, se le añade un miembro, y se
debe mover a una lista que representará el estado en la que la tarea se encuentra, por ejemplo ”TO
DO”(Para hacer). Una tarea puede cambiar de lista según los estados establecidos. De esta forma
se ve el flujo de trabajo, se puede revisar si se cumplen los requisitos, cuando las tareas (tarjetas)
pasan por las listas.
Las tareas que requieran documentos, imágenes u otros materiales se agregan como adjuntos.
Todos los miembros de una tarjeta reciben notificaciones de actividad de la misma.Se puede usar
las fechas de vencimiento para tareas con un deadline especı́fico.
Trello es una completa y fácil herramienta para la gestión de proyectos sin embargo, la carac-
terı́sta importante en la gestión de proyectos que no está disponible por defecto en Trello es un
gráfico de Gantt. Sin embargo, esta plataforma de trabajo flexible se integra con muchas aplica-
ciones de terceros que ofrecen un diagrama de Gantt para facilitar la planificación, coordinación y
seguimiento de las tareas programadas.
A través de complementos, extensiones o integraciones, Trello compensa su funcionalidad simple
y básica. Al parecer, ahora está siendo utilizado por todo tipo de equipos donde para algunos un
gráfico de Gantt es un componente esencial. Algunos de los complementos gráficos que funcionan
bien con esta herramienta PM son Elegantt10 , Ganttify11 , Placker12 , etc.
Trello junto a los complementos se convierte en alternativa completa para la gestión de requi-
sitos, su version gratuita es bastante fácil de usar siempre en cuando se entiendan los conceptos
que representan las tarjeta y listas en un proyecto. Cumple con las caracterı́sticas que estamos
analizando.
Actualizar cambios.
Subir cambios.
10 Elegantt plugins genera automáticamente gráficos de Gantt para los tableros Trello de un usuario.
11 Ganttify es un complemento gratuito que convierte un tablero Trello en un gráfico de Gantt.
12 Complemente para Trello que tiene una vista de la carta de Gantt que exhibe un tablero, las listas y los detalles
de la tarjetas también. Desde el gráfico de Gantt, los usuarios pueden ajustar fácilmente las fechas de inicio y
finalización, cambiar el porcentaje completado y crear dependencias.
Es una de las mejores practicas que puede llevar a cabo un equipo de desarrolladores. Existen
diversas herramientas que proveen estas funcionalidades:
Ejecuta secuencias de comandos para suministrar registros de operaciones CVS o hacer cum-
plir polı́ticas especı́ficas.
El CVS cliente / servidor permite a los desarrolladores ubicados en diferentes lugares funcionar
como un solo equipo. El historial de versiones se almacena en un único servidor central y las
máquinas cliente tienen una copia de todos los archivos en los que están trabajando los
desarrolladores.
En los casos en que varios desarrolladores o equipos quieren mantener cada uno su propia
versión de los archivos, debido a la geografı́a y / o polı́tica, las ramas de proveedores de CVS
pueden importar una versión de otro equipo (incluso si no usan CVS ) y entonces CVS puede
combinar los cambios de la rama del proveedor con los archivos más recientes si eso es lo que
se desea.
CVS proporciona una base de datos flexible de módulos que proporciona un mapeo simbólico
de nombres a componentes de una distribución de software más grande. Aplica nombres a
colecciones de directorios y archivos. Un solo comando puede manipular toda la colección.
Los servidores CVS se ejecutan en la mayorı́a de las variantes de Unix, y los clientes Windows.
Las limitaciones son que los archivos en el repositorio sobre la plataforma CVS no pueden ser
renombrados, estos deben ser agregados con otro nombre y luego eliminados. El protocolo CVS no
provee una manera de que los directorios puedan ser eliminados o renombrados, cada archivo en
cada subdirectorio debe ser eliminado y re-agregado con el nuevo nombre. Soporte limitado para
archivos Unicode con nombres de archivo no ASCII.
Actualmente CVS es una opción desactualizada. Fue una buena alternativas en su momento
siendo la única alternativa, pero actualmente han sido sobrepasada de largo por otras opciones. Lo
mismo ocurre con Microsoft Visual SourceSafe (VSS), que también es una herramienta de Control
de versiones que forma parte de Microsoft Visual Studio aunque está fue sustituida por Visual
Studio TFS (Team Foundation Server).
El cambio natural entre herramientas serı́a, si se usa CVS pasar a Git, y si se usaba VSS pasar
a TFS, existe la documentación para realizar las migraciones correspondientes.
SVN (Subversión)
Apache Subversión (abreviado frecuentemente como SVN, por el comando svn) es una herra-
mienta de control de versiones open source basada en un repositorio cuyo funcionamiento se asemeja
enormemente al de un sistema de ficheros. Es software libre bajo una licencia de tipo Apache/BSD.
Subversión se desarrolla como un proyecto de la Apache Software Foundation , y como tal forma
parte de una rica comunidad de desarrolladores y usuarios.
La siguiente lista son algunas de las caracterı́sticas de SVN y cómo funcionan los sistemas de
control de versiones en general[25].
Los directorios están versionados. Subversión versiones directorios como objetos de primera
clase, al igual que los archivos.
Impacto del commit. Ninguna parte de un commit tiene efecto hasta que todo el commit haya
tenido éxito. Los números de revisión son por commit, no por archivo, y el mensaje de log de
commit está conectado a su revisión.
Bloqueo de archivos. Subversión soporta (pero no requiere) el bloqueo de archivos para que
los usuarios pueden ser advertidos cuando varias personas intentan editar el mismo archivo.
Un archivo puede ser marcado como requiriendo un bloqueo antes de ser editado, en cuyo caso
Subversión presentará el archivo en modo de sólo lectura hasta que se obtenga un bloqueo.
Opción de servidor de red Apache, con protocolo WebDAV / DeltaV. Subversion puede uti-
lizar el protocolo WebDAV / DeltaV basado en HTTP para las comunicaciones de red y el
servidor web Apache para proporcionar servicio de red del lado del repositorio. Esto da a
Subversion una ventaja sobre CVS en interoperabilidad y permite que ciertas caracterı́sti-
cas (como autenticación, compresión de hilos) sean proporcionadas de una manera que ya es
familiar para los administradores
Git
Git es un sistema de control de versiones distribuidas de código abierto y libre diseñado para
manejar desde proyectos pequeños hasta muy grandes con rapidez y eficiencia. Git es fácil de apren-
der y tiene una huella muy pequeña con un rendimiento rápido .Tiene funciones como ramificación
local barata , áreas de puesta en escena convenientes y múltiples flujos de trabajo.
Posee las funcionalidades de todo SCM, agrega algo importante que es la ramificación y fusión.
Git permite tener múltiples ramas locales que pueden ser totalmente independientes entre sı́.
La creación, la fusión y la supresión de esas lı́neas de desarrollo toma segundos.
Esto significa que se puede hacer cosas como[14]:
Cambio de contexto sin problemas . Se puede crear una rama para probar una idea, comenzar
varias veces, cambiar de nuevo a donde se ramificó, aplicar un parche, cambiar de nuevo a
donde se está experimentando y fı́jar.
Lı́neas de base basadas en funciones, por ejemplo una version que va ala producción, una
versión que va al servidor de pruebas y varias más pequeñas para el trabajo diario.
Flujo de trabajo basado en funciones . Una rama para cada nueva función en la que se trabaje
para cambiar sin problemas entre ellas y la opción de a continuación eliminar cada una de las
çopiasçuando se fusiona con la lı́nea principal.
Experimentación descartable . Crear una rama para experimentar, verificar si funciona, eli-
minarlo, abandonarlo.
Mercurial
Mercurial es una herramienta con licencia GPLv2, gratuita y distribuida de control de versiones
de código fuente. Maneja eficientemente proyectos de cualquier tamaño y ofrece una interfaz fácil e
intuitiva.
Mercurial maneja proyectos de cualquier tamaño y tipo . Cada clon o copia contiene toda la
historia del proyecto, por lo que la mayorı́a de las acciones son locales, rápidas y convenientes.
Soporta una multitud de flujos de trabajo y puede mejorar su funcionalidad con extensiones .
Al ser de arquitectura distribuida y no como Subversión de arquitecturas cliente-servidor con un
servidor central para almacenar las revisiones de un proyecto, Mercurial es realmente distribuido
dando a cada desarrollador una copia local de toda la historia del desarrollo. De esta manera fun-
ciona independientemente del acceso a la red o de un servidor central. Las funciones de ramificación
y fusión son rápidas y baratas.
Es de plataforma independiente, por lo tanto, la mayor parte de Mercurial está escrito en Python,
con una pequeña parte en C portátil por razones de rendimiento. Como resultado, las versiones
binarias están disponibles en todas las plataformas principales.
Algunas de sus caracterı́sticas son[8]:
de los comandos básicos, agregar nuevos comandos y acceder a todas las funciones principales
de Mercurial.
Fácil de usar, cómodo y las acciones potencialmente peligrosas están disponibles a través
de extensiones que necesita habilitar, por lo que la interfaz básica es fácil de usar, fácil de
aprender y difı́cil de romper.
Control de versiones: Permite almacenar y colaborar en códigos con repositorios privados. Usa
GIT para realizar un control distribuido de las versiones o el control de versiones de Team
Foundation (TFVC) para controlar las versiones de forma centralizada.
Herramientas para equipos de Agiles: Capturar, priorizar y realizar un seguimiento del trabajo
con trabajos pendientes y paneles Kanban personalizables.
Integración continua: Compilar, empaquetar, probar, liberar, repetir. Automatizar todas las
implementaciones y realiza un seguimiento con la administración de versiones.
Compatibilidad con Java: Herramienta para desarrollar en cualquier plataforma. Lo que po-
sibilita usar el IDE que se prefiera: Eclipse, IntelliJ, Android Studio, Visual Studio Code, etc.
Luego compilar el código con Ant, Maven y Gradle desde sus repositorios de GIT, Subver-
sion y TFVC. Implemente CI/CD con capacidades nativas o por medio de integraciones con
sistemas como Jenkins14 . También admite lenguajes móviles y multiplataforma, incluidos los
siguientes: C++15 , PHP16 , Python17 , Go18 , Swift19 y muchos más.
13 DevOps es un acrónimo de inglés de development (desarrollo) y operations (operaciones), que se refiere a una
cultura o movimiento centrado en la comunicación, colaboración e integración entre desarrolladores de software y los
profesionales en las tecnologı́as de la información (IT).
14 Jenkins es un software de Integración continua open source escrito en Java.
15 C++ es un lenguaje de programación extendención del lenguaje de programación C, el C++ es un lenguaje
hı́brido.
16 PHP es un lenguaje de programación de propósito general de código del lado del servidor originalmente diseñado
por Google y sus diseñadores iniciales son Robert Griesemer, Rob Pike y Ken Thompson.
19 Swift es un lenguaje de programación multiparadigma creado por Apple enfocado en el desarrollo de aplicaciones
Abierto y extensible: Es muy fácil integrar una herramienta personalizada o servicio de ter-
ceros con Team Foundation Server mediante estándares abiertos, como la API de REST y
OAuth 2.0.
Team Foundation Server Express : Gratis para usuarios individuales y equipos pequeños
Bitbucket
Bitbucket es un servicio de alojamiento basado en web, para los proyectos que utilizan el sistema
de control de revisiones Mercurial y Git. Bitbucket ofrece planes comerciales y gratuitos. El servicio
está escrito en Python.2
Sistema de control de versiones distribuido con modelos de despliegue flexibles para equipos de
cualquier tamaño y con todo tipo de necesidades. Alojado en la nube o en servidores privados.
JUnit
Marco de trabajo para pruebas unitarias creado por Erich Gamma y Kent Beck, herramienta
de código abierto que se ha convertido en el estándar para las pruebas unitarias en Java y que es
soportado por la mayorı́a de los Entorno de Desarrollo Integrado (IDEs), como Eclipse o Net-Beans.
Consiste en un conjunto de clases, fácil de usar y aprender que les permite a los programadores
escribir sus pruebas unitarias en el lenguaje Java. Posee una comunidad mucho mayor que el resto
de los marcos de trabajo de pruebas en Java.
PhpUnit
Marco de trabajo para las pruebas unitarias en especı́fico a PHP, es de licencia BSD. Es uno
mas de los marcos de trabajo de xUnit. Se integra con varias aplicaciones de pruebas. Facilita la
creación de pequeños scripts que ayudan a probar las aplicaciones y analizar los resultados.
NUnit
NUnit es un marco de pruebas unitarias para todos los lenguajes .Net. Inicialmente portado
de JUnit. Es un software de código abierto y NUnit 3 es liberado bajo la licencia del MIT . Las
versiones anteriores usaban la licencia NUnit .
doctest
El marco de prueba doctest es un módulo de Python que viene preenvasado con Python. Permite
la fácil generación de pruebas basadas en la salida del intérprete de estandar de Python.
doctest busca partes de texto que parecen sesiones de Python interactivas y luego ejecuta esas
sesiones para verificar que funcionan exactamente como se muestra. Hay varias maneras comunes
de usar doctest:
Las pruebas unitarias son llamadas en los comentarios. Se escribe la documentación de un
paquete, ampliamente ilustrado con ejemplos de entrada y salida. Dependiendo de si se enfatizan
los ejemplos o el texto expositivo, esto tiene el sabor de ”pruebas alfabetizadas.o ”documentación
ejecutable”[10].
FitNesse
Es una herramienta de colaboración, puesto que FitNesse es un servidor web wiki, tiene una
entrada y una curva de aprendizaje muy baja, lo que la convierte en una excelente herramienta
para colaborar con, por ejemplo, las partes interesadas del negocio. También es una herramienta
de prueba, las páginas de wiki se convierten en pruebas que son ejecutadas. Las especificaciones
pueden ser probadas en contra de la aplicación en sı́, lo que resulta en un viaje de ida y vuelta
entre las especificaciones y la implementación.
Selenium
Selenium WebDriver (Selenium 2): Es hacia donde va el proyecto y la adición más reciente al
conjunto de herramientas Selenium. Esta nueva herramienta de automatización ofrece todo
tipo de caracterı́sticas impresionantes, incluyendo una API más cohesiva y orientada a objetos,
ası́ como una respuesta a las limitaciones de la antigua implementación.
Selenium RC (Remote Control) (Selenium 1): Biblioteca de Javascript que podrı́a impulsar
las interacciones con la página, permitiéndole volver a ejecutar automáticamente pruebas
contra varios navegadores. Esa biblioteca finalmente se convirtió en Selenium Core, que sub-
yace a toda la funcionalidad de Selenium (RC) y Selenium IDE. Selenium RC fue innovador
porque ningún otro producto le permitió controlar un navegador desde un idioma de su elec-
ción. Ahora Selenium 1 está obsoleto y no se admite activamente (sobre todo en modo de
mantenimiento).
Selenium Grid: Permite que la solución Selenium RC sea escalable para grandes suites de
prueba y para suites de prueba que deben ejecutarse en múltiples entornos. Selenium Grid
le permite ejecutar sus pruebas en paralelo, es decir, se pueden ejecutar diferentes pruebas
al mismo tiempo en diferentes máquinas remotas. Esto tiene dos ventajas. En primer lugar,
si tiene una suite de pruebas grande o una suite de pruebas de ejecución lenta, puede au-
mentar considerablemente su rendimiento utilizando Selenium Grid para dividir su suite de
pruebas para ejecutar diferentes pruebas al mismo tiempo utilizando esas diferentes máqui-
nas. Además, si debe ejecutar su suite de pruebas en varios entornos, puede tener distintas
máquinas remotas soportando y ejecutando sus pruebas en ellas al mismo tiempo. En cada
caso, Selenium Grid mejora en gran medida el tiempo que tarda en ejecutar su suite haciendo
uso del procesamiento paralelo.
que se denomina “Pipeline”20 . Despliegue continuo significa entonces que se tiene la capacidad de
realizar despliegues frecuentemente, aunque en general esta acción debe pasar primero por una apro-
bación por parte del negocio, quien determina cuántos y cuándo se hacen efectivos los despliegues
al ambiente productivo.
Para automatizar estos procesos existen algunas herramientas las cuales permiten llevar a cabo
la mayorı́a de las tareas que se ejecutan de forma manual, estas son:
Ant
Apache Ant es una herramienta usada para la realización de tareas mecánicas y repetitivas, nor-
malmente durante la fase de compilación y construcción (build). Es similar a Make pero desarrollado
en lenguaje Java y requiere la plataforma Java.
Esta herramienta, hecha en el lenguaje de programación Java, tiene la ventaja de no depender de
las órdenes del shell de cada sistema operativo, sino que se basa en archivos de configuración XML y
clases Java para la realización de las distintas tareas, siendo idónea como solución multi-plataforma.
Maven
Cruise Control
CruiseControl es una aplicación de código abierto basado en Java que permite la compilación au-
tomática de proyectos Java, utilizando Ant o Maven. Es una herramienta que se utiliza comúnmente,
20 Son cada uno de los pasos que forman el flujo de trabajo de construcción y entrega del software. Cada uno de
estos pasos se ocupa de realizar una tarea concreta, por ejemplo: un primer paso podrı́a ser la descarga de código,
un segundo paso la compilación del código descargado, etc
que en cada cierto tiempo que es configurable o si la indicación es cuando haya cambios obtiene de
un servidor de versiones como CVS o Subversión una copia del código fuente a la cual compila y eje-
cuta los test, o incluso lo que este configurado con Ant o Maven. Una vez terminada este despliegue
de procesos, el resultado puede ser visualizado en HTML o enviado por correo electrónico[15].
Actualmente, existe también una versión de CruiseControl para .Net llamada CruiseControl.Net.
Soporta medios de almacenamiento como por ejemplo servidores Protocolo de Transferencia de
Archivos (FTP) o Web. Su fácil proceso de instalación y configuración a partir de Lenguaje de
Marcas Extensibles (XML), en el que se definen, entre otras cosas, las tareas a realizar en el ciclo
de construcción para cada uno de los proyectos registrados.
Jenkins
Travis-CI
Herramienta que da una forma simplificada de hacer Integración Continua. Travis CI es una
plataforma en la nube que funciona de manera gratuita para repositorios GitHub públicos, también
con planes pagados para repositorios privados, la cual opera asi:
2. Travis CI detecta el git push y analiza el proyecto por una máquina virtual en la nube. Se
construye y se verifica si compila.
21 Comando que sube los cambios hechos en un ambiente de trabajo a una rama de trabajo en un equipo remoto
3. Incorporación de más tareas antes y después de la verificación, por ejemplo tests unitarios
o despliegue de plataformas, todo esto es controlado por el archivo .travis.yml que va en el
directorio raı́z del repo del proyecto.
4. Revisación en la web de Travis CI si el build del proyecto fue exitoso o falló. En caso de falla,
se hará llegar una notificación por correo electrónico.
Heramienta para una inspección continua, SonarQube proporciona la capacidad no sólo para
mostrar la salud de una aplicación, sino también para resaltar los problemas introducidos recien-
temente. Con una puerta de calidad en su lugar, puede arreglar la fuga y por lo tanto mejorar la
calidad del código sistemáticamente.
Los problemas planteados por SonarQube se encuentran en un código incorrectamente demos-
trable o en un código que es más probable que no tenga el comportamiento deseado. Los ejem-
plos incluyen desreferencias, pérdidas de memoria y errores lógicos. Búsqueda de código con ”mal
olor”que hace (probablemente) lo que deberı́a, pero será difı́cil de mantener. Los ejemplos incluyen
código duplicado, código descubierto por pruebas unitarias y código demasiado complejo.
Puede detectar las vulnerabilidades de seguridad en más de 20 lenguajes de programación.
Ofrece informes sobre código duplicado, estándares de codificación , pruebas unitarias, cobertura
de código, la complejidad del código, comentarios, errores y vulnerabilidades de seguridad. Graba
historial de métricas y proporciona gráficos de evolución. El mayor activo de SonarQube es que
proporciona análisis totalmente automatizados e integración con Maven , Ant , Gradle, MSBuild y
herramientas de integración continua ( Atlassian Bamboo , Jenkins , Hudson , etc.).
También se integra con Eclipse , Visual Studio y IntelliJ IDEA entornos de desarrollo a través
de los plugins SonarLint y se integra con herramientas externas como LDAP , Active Directory ,
GitHub , etc.
ReSharper
Guı́a práctica
En capı́tulos anteriores hemos desarrollado las metodologı́as TDD, ATDD, BDD entre otras y
sus variantes, junto a las herramientas para Integración Continua, sus ventajas e inconvenientes de
usarla. Por lo que antes de ir a la parte práctica, se hará una propuesta de Guı́a para la utilización
de TDD. En lo que respecta a CI se recomienda consultar la documentación de cada herramienta
para poder realizar su instalación. El conjunto de herramientas que se eligen en CI depende mucho
del equipo de desarrollo, del conocimiento de los desarrollo en el uso de servidores de versiones,
base de datos, etc.
Partiremos desde una visión general que nos permita evaluar si es conveniente en un caso
particular utilizar las metodologı́as y herramientas explicadas. Y luego los pasos que debemos
abordar para aplicarlas a un ejemplo práctico.
95
Capı́tulo 5. Guı́a práctica
por que simplemente es beneficioso para todos. Es mejor para el cliente, para entenderse mejor,
para evitar malos entendidos, por eso mismo todo equipo tiene el afán de caer en el mal uso de
metodologı́as simplemente por considerar que pueden ser soluciones mágicas. Existe quien dice que
”los equipos que eligieron esta metodologı́a les fue bien”, es una afirmación que puede resultar
peligrosa, es generalizar mucho, intervienen muchos factores en un grupo de personas y en un
momento particular. No hay garantı́as, todos los equipos son distintos.
Entonces debemos evaluar si nuestro equipo cumple con las condiciones necesarias para aplicar
TDD, y de llevar el desarrollo bajo CI. TDD es un conjunto de practicas, es flexible, más bien su
definición es un algoritmo ”primero el test, luego el código, y refactorizamos”. CI es un conjunto de
herramientas, algunas mejores para ciertos proyectos, óptimas en grupos pequeños o no, y muchos
otros puntos para analizar más, pero todas tienen su tiempo de implementación y de conocimiento.
Entonces, algunas de las preguntas que nos debemos hacer son:
Tanto la pregunta 1 como la pregunta 2 están enfocadas al equipo. El equipo deberá entender
la filosofı́a de TDD y además de entenderla .adoptarla”. No es algo fácil, porque TDD supone un
cambio radical en la forma de programar. Se acostumbra a hacer código, ejecutarlo, modificarlo,
agregarle mas funcionalidades, y cuando llega el momento de la entrega recién revisarlo, a buscar
errores, probarlo. Para ese entonces el código es complejo, tiene muchas clases que no se sabe bien
que hacen, para que están, muchos métodos que se llaman entre sı́. Buscar código duplicado ya
no es sencillo, reestructurar un método que es utilizado por varios componentes tampoco, todo
esto si se busca las ventajas que nos da refactorizar. Hay mucha información de TDD, experiencias
personales, técnicas, ”tips”. Lo cierto es que TDD es simple de explicar pero difı́cil de aplicar.
TDD es una disciplina que promueve una forma de desarrollar software con altos niveles de
calidad, simplicidad de diseño y productividad del programador. Dijimos que suena simple, pero
cuando se esta aprendiendo a tomar el enfoque de TDD nos encontramos realmente con lo que
significa tener disciplina, porque es fácil cometer un ”desliz escribir código funcional sin escribir
2
primero una nueva prueba. Una de las ventajas de programar de pares es que la pareja ayuda a
permanecer en el camino. Entonces no es algo que aplicamos “según como nos sentimos”, es algo
que debe formar parte integral de la profesión o arte[48].
En un inicio se acostumbra a ir verificando que el código funciona, sin nada de por medio
que çertifique”que es ası́. Cada vez que el resultado es el esperado aumenta la autoconfianza en
el desarrollador, es una motivación a seguir programando. El problema es que desarrolladores se
confı́an, se disponen a crear código y más código sin ninguna comprobación con el propósito de
optimizar tiempo y además porque, se piensa, el código .esta bien”. Lo que pasa al final es que, ya
no se comprueba por medio de los resultados si el código funciona bien, total lo hizo antes, esto de
comprobar cada rato es para novatos. No es necesario revisar el código[2].
Para la pregunta 3, hay que tener claro el motivo por el que se busca incorporar TDD y
CI. Se puede decir que ambos conceptos buscan lo mismo, el primero se adentra en lo que es
codificación y el otro en la producción, ambos buscan calidad, producción, reducción de riesgos. Si
no existe motivo alguno para aplicar estás metodologı́as, entonces no hay porque seguir. ¿Lo solicito
el Cliente o algún superior?. Si es ası́, lo que corresponderı́a es analizar si es conveniente e informar
la conclusión de esto a quién solicitó el uso de la metodologı́a. Si en cambio se está convencido y
los motivos que se tienen son suficientes para incorporar TDD seguro se irá por buen camino.
La pregunta del punto 4 habla de automatización, cuando se habla de TDD se asume que
hay una parte de automatización, porque las pruebas se corren todas al final de cada nueva imple-
mentación. Pero no es un requisito necesario y obligatorio la utilización de automatización. Aquı́ es
donde se recuerda todo lo que se investigó de Integración Continua.
CI hace foco en dos cosas: una es la ejecución de pruebas cada vez que realiza una integración
o un cambio en el código y por otro lado se resalta la frecuencia con que esto se realiza. Ambos
puntos son sin dudas los ejes principales de esta práctica, ya que ambos en conjuntos son los que
permiten detectar errores lo antes posible de manera de minimizar los riesgos. Como podemos
ver de la definición de automatización lo que estamos haciendo es sustituyendo el esfuerzo fı́sico
humano. Lo importante es aplicar la práctica más allá de la herramienta que sea seleccionada para
tal fin, porque los beneficios son dignos de tener en cuenta: reducción de riesgos de despliegue, mas
flexibilidad al cambio, progreso creı́ble, feedback con el cliente, más tiempo para resolver errores.
Deberı́amos hacer automatización sin importar que metodologı́a sea la que adoptemos, si no estamos
capacitados para aplicarla, debemos comenzar a hacerlo.
Pregunta 5, nos enfoca nuevamente en el equipo. Cuando el equipo es nuevo puede ser algo
bueno o algo no dirı́a malo pero quizás más desafiante. Por un lado si es nuevo hay que conocerse
y aprender a trabajar juntos, la parte buena serı́a que no están .acostumbrados.a trabajar de una
manera, y serı́a mucho más fácil si todos arrancaran desde el inicio con TDD o la metodologı́a
elegida, tengan o no experiencia previa. Si en el equipo hay varios miembros también es relevante,
es mucho más fácil llegar a un acuerdo entre 3 personas que llegar aun acuerdo en una reunión
entre 15 personas.
La pregunta del punto 6 nos acerca a las metodologı́as ágiles. Si el equipo (sea nuevo o
no) tiene experiencia en metodologı́as ágiles es un punto a favor en cuanto al aprendizaje, los
preconceptos podrı́an interferir, pero los paradigmas actuales ya vienen enfocados en la aplicación
de metodologı́as ágiles, lo vemos en la vida laboral cotidiana. La sociedad se ve abrumada con
la cantidad de información y estı́mulos que recibe por los medios digitales, tienes infinidad de
herramientas para aplicar metodologı́as ágiles (no necesariamente en desarrollo de software), y
necesitas aplicarlas a veces para sobrevivir en el trabajo diario.
En la pregunta 7 nos lleva a pensar en el miembro quizás más importante del equipo: el cliente.
Estamos hablando de TDD una metodologı́a ágil como algunos prefieren considerarla o práctica
ágil por otros, pero en lo que si están de acuerdo es que es ”ágil”. Si nos vamos por el camino de
que es una metodologı́a ágil, el manifiesto ágil, en el primero de sus postulados dice Ïndividuos e
interacciones sobre procesos y herramientas..Este valor inspira uno de 12 postulados donde tenemos
:”La prioridad es satisfacer al cliente mediante tempranas y continuas entregas de software que
le aporte un valor. Un proceso es ágil si a las pocas semanas de empezar ya entrega software
que funcione aunque sea rudimentario. El cliente decide si pone en marcha dicho software con la
funcionalidad que ahora le proporciona o simplemente lo revisa e informa de posibles cambios a
realizar.”. Ahora si la vemos como una práctica ágil, estarı́amos yendo por el mismo camino. La
conclusión a esta pregunta es obvia, si aplicamos una metodologı́a ágil o práctica ágil, el cliente es
un ingrediente esencial en la receta, tiene que estar en ella, y ser parte de ella lo más continuamente
posible.
1 Charlie Poole es un desarrollador de software neoyorquino con más de 30 años de experiencia que está considerado
un experto mundial en el desarrollo guiado por pruebas (TTD) e involucrado muy activamente en el proyecto NUnit,
un framework de pruebas unitarias para código de la familia .NET.
Son los más importantes en TDD, incluso son la causa de que muchos confundan TDD con
testing, pero son necesarios.
Todo test unitario debe ser rápido, atómico, inocuo e independiente (F.I.R.S.T)2 , sino cumple
con estas cuatro premisas no es un test unitario[12].
Un test tiene que ser rápido por que no se tendrı́a un feedback inmediato cada vez que se
escribe un test unitario. Lo que implicarı́a que el proceso de aprendizaje del dominio del problema
no marchará bien, también será mucho más probable que ocurra un ”desliz el desarrollador escriba
2
código antes del test. Se ejecutan muchos de ellos todo el tiempo. Tiene que ser inocuo para no
alterar el estado3 del sistema, atómico porque debe probar la mı́nima cantidad de funcionalidad
posible y por último independiente porque no debe depender de otros para su existo o fracaso.
.Esto es, probará un solo comportamiento de un método de una clase. El mismo método pue-
de presentar distintas respuestas ante distintas entradas o distinto contexto. El test unitario se
ocupará exclusivamente de uno de esos comportamientos, es decir, de un único camino de ejecu-
ción”(Carlos Ble,2010,p74)[12].
Se dice que un test unitario tiene ”menor granularidad çuando la llamada al método provoca
que internamente se invoque a otros, se dice que es menos fino [12].
Al ser un test atómico evita tener que usar un debugger4 para encontrar el error en el código que
se está probando puesto que encontrar la causa será más sencillo. El ser estrictos con la atomicidad
de un test puede generar que se tenga que abusar de los dobles de prueba5 .
Para validar la ejecución de un test unitario existen dos formas, validar el estado y validar la
interacción o comportamiento.
hace pasar por un colaborador del ćodigo a probar cuando en realidad no es la entidad que dice ser”(Carlos Ble,
2010,p88).
Los tests de carga6 y de rendimiento7 son de aceptación cuando el cliente los considera ası́.
realiza una tarea en condiciones particulares. La perspectiva en la que se realizan es la de determinar lo rápido y
eficiente en que se realiza una tarea en el sistema
8 Mocks con menor potencia[12]
Pero antes de decidir a usar objetos ficticios o mocks hay que pensarlo dos veces, puede resultar
difı́cil de leer un código lleno de mocks. A veces no se necesitan usar, sino que al test se puede
partir en varios test y/o reescribir una parte del código a comprobar.
Martin Fowler publicó un artı́culo que habla de los mocks “Los mocks no son stubs”(Mocks
Aren’t Stubs), donde habla de los distintos dobles, donde se extrae el siguiente listado de tipos de
doble[36]:
1. Dummy: se pasa como argumento, se usan para llenar listas de argumentos, son ficticios.
2. Fake: tiene una implementación que realmente funciona pero, por lo general, toma algún atajo
o cortocircuito que le hace inapropiado para producción (como una base de datos en memoria
por ejemplo).
3. Stub: son los que reemplazan a objetos reales del sistema, generalmente para generar entradas
de datos.
Composición de métodos
Organización de datos
Generalización
1
2 public void PrintReporte {
3
4 PrintEncabezado () ;
5 /* print footer */
6 console . writeline ( this . TitleFooter ) ;
7 console . writeline ( this . SubtitleFooter ) ;
8
9 }
Claramente el código en donde se imprime el titulo y el subtitulo del pie puede ser agrupado y
extraı́do para integrar un nuevo método.
1
2 public void PrintReporte {
3
4 PrintEncabezado () ;
5 PrintFooter () ;
6
7 }
8
9 public void PrintFooter {
10
11 console . writeline ( this . TitleFooter ) ;
12 console . writeline ( this . SubtitleFooter ) ;
13 }
5. Evaluar el uso de las variables, si deben ser o son modificadas, o son de lectura.
7. Compilar y ejecutar.
Inline Method
Ocurre cuando el cuerpo de un método es tan claro como su nombre. Suele unirse el código,
contrario al método anterior. La solución entonces es eliminar el método trasladando el cuerpo a
sus invocadores.
1
2 public int GetRating {
3
4 return ( MasdeCincoEnvios () ) ? 2:1;
5
6 }
7
8 public boolean MasdeCincoEnvios {
9
10
11 return numeroDeEnvios > 5;
12 }
1
2 public int GetRating {
3
4 return ( numeroDeEnvios > 5) ? 2:1;
5 }
Cuando se usa una variable temporal que es el resultado de una expresión, que además es local
y a veces suele generar métodos extensos. La solución es convertir la expresión en un método y
reemplazar su uso por la invocación correspondiente.
1
2 double totalConsumo = abono + consumoMensual ;
3
4 if ( totalConsumo > 1000)
5 return totalConsumo * 0.21;
6 else
7 return totalConsumo * 0.15;
1
2
3
4 if ( TotalConsumo () > 1000)
5 return TotalConsumo () * 0.21;
6 else
7 return TotalConsumo () * 0.15;
8
9 public double TotalConsumo () {
10
11 return abono + consumoMensual ;
12
13 }
Es cuando se tiene un método que suele ser usado más por otras clases que por la clase a la que
integra. Se crea el método de cuerpo similar en la clase que más lo usa y se elimina o convierte en
una delegación el antiguo método.
Puede ocurrir cuando una clase tiene muchas responsabilidades, o cuando las clases colaboran
demasiado y existe mucho acoplamiento.
Proceso:
8. Compilar y testear
Extract Class
Una clase realiza muchas cosas, tiene varias responsabilidades, suele hacer el trabajo de 2. Se
soluciona creando una clase, moviendo los atributos y metodos relevantes.
Demasiados métodos, muchos datos, exceso de responsabilidades.
Proceso:
2. Crear una nueva clase que exprese esa división (tal vez deban renombrarse ambas).
3. Hacer un link desde la clase vieja a la nueva (tal vez una asociación bidireccional).
4. Usar Move Field y Move Method, y compilar luego de aplicar esas refactorizaciones.
Inline Class
Una clase no hace gran cosa, se suele moverla a otra clase y borrarla. Es la inversa de Ex-
tract Class. En esta refactorización una clase absorve a otra pues esta última no tiene muchas
responsabilidades asociadas.
1
2 private string nombre ;
3
4 public string GetNombre () {
5 return nombre ;
6 }
7 public void SetNombre ( string arg ) {
8 nombre = arg ;
9 }
Es un conjunto de datos que en su momento no fue considerado como un objeto, se suele crear
el nuevo objeto y agregarle este conjunto de datos.
1
2 if ( cliente == null )
3 plan = BillingPlan . basico () ;
4 else
5 plan = cliente . GetPlan (
6 }
1
2 public class Cliente
3
4 {
5 public void GetPlan ()
6 {
7 ....
8 }
9 }
1
2 public class NullCliente
3
4 {
5 public void GetPlan ()
6 {
7 cliente . GetPlan () ;
8 }
9 }
1
2 public class Cliente
3
4 {
5 public void CantidadFacturada ( Date Ini , Date Fin ,...)
6 {
7
8 }
9 public void CantidadPagada ( Date Ini , Date Fin ,...)
10 {
11
12 }
13 }
1
2 public class Cliente
3
4 {
5 public void CantidadFacturada ( DateRango ,...)
6 {
7
8 }
9 public void CantidadPagada ( DateRango ,...)
10 {
11
12 }
13 }
14
15 public class DateRango
16 {
17 Date Inicio ;
18 Date Fin ;
19
20 }
5.3.5. Generalización
Pull up Method
Parte del comportamiento de una clase es relevante sólo a algunas subclases. La solución es
trasladar los métodos a las subclases
Extract Subclass
Una clase tiene aspectos que son usados sólo en algunas instancias. Algunas instancias los usan,
otras no, entonces lo mejor es no mezclarlas y generar clases separadas. La solución es crear subclases
para los subconjuntos de aspectos relevantes a cierta instancias.
Proceso:
5. Aplicar Push Down Method y Push Down Field hasta que ya no sea necesario.
2. Se escriben junto con el cliente los criterios de aceptación de esta historia, desglosándolos
mucho para simplificarlos todo lo posible.
8. Se vuelven a pasar todas las pruebas automatizadas para comprobar que todo sigue funcio-
nando.
9. Volvemos al punto 3 con los criterios de aceptación que falten y repetimos el ciclo una y otra
vez hasta completar nuestra aplicación.
1
2 using System ;
11 NUnit, unittest o JUnit, etc
El código no compila porque todavı́a no se ha creado la clase Tickets. Sin embargo ya estamos
diseñando; decidimos su nombre, como es el constructor, si recibe o no parámetros y el resultado
que devuelve.
En la lı́nea 3 puedes ver que estamos llamando al framework de testing de .Net . Creamos una
clase llamada TestTickets y dentro de ella un método llamado ObtenerNumeroTest. En la lı́nea 17
tenemos la aserción, como se dijo antes es un código que se usa durante el desarrollo, normalmente
una rutina o una macro, que permite que un programa se revise a medida que se ejecuta. Cuando
una afirmación es verdadera, eso significa que todo está funcionando como se esperaba. Cuando es
falso, significa que ha detectado un error inesperado en el código. En nuestro caso la aserción esta
verificando que el numero del ticket no sea nulo.
Luego escribimos el mı́nimo código para que el test unitario recién creado pase (debe compilar
para pasar).
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
10 public string ObtenerNumero ()
11 {
12 return " EXA -001/17 " ;
13 }
14 }
15 }
El código quedo lo mas simple posible. Ahora nuestro primer test pasa. Tal vez no tenga un
buen diseño, podrı́amos haber pensando directamente en hacer el test de la función que crea el
numero de tickets, o quizás la función ObtenerNumero() de la clase Tickets no sea necesaria.
¿Qué esta ocurriendo entonces?, porque me hago tantas preguntas, estamos diseñando y anali-
zando, pensando que funciones se necesitarán. Tal vez debamos volver a nuestro test de aceptación
y ver si una funcionalidad indicada serı́a ObtenerNumero. Otra forma de encarar el diseño podrı́a
haber sido en pensar en la clase Tickets y todos los atributos que deberı́a tener.
Ya comprobado que pasa el test, busco que refactorizar, no encuentro mucho, quizás el nombre
del método ObtenerNumero() no me convenza, esto puede ser algo para refactorizar, poner nombres
indicados.
Un buen nombre para un método es importante, porque con él podemos saber que hace, cual es
su propósito, y además detectar cuando necesita ser refactorizado si vemos código que no deberı́a
estar ahı́.
El código que tenemos hasta ahora es bastante simple. Justo es el momento en cuando uno
tiende a añadir más código, se me ocurre que el número de ticket puede ser un atributo y estoy
tentado a implementar esto. Pero no puedo añadir ninguna funcionalidad más, sin antes crear un
test nuevo.
1 [ TestMethod ]
2 public void CrearTicketTest ()
3 {
4 Tickets ticket = new Tickets () ;
5 Assert . IsTrue (! string . IsNullOrEmpty ( ticket . Numero ) ) ;
6 }
El test unitario CrearTicketTest hace que mi proyecto no compile, no tengo el atributo ”Numero.en
la clase Tickets, tengo que crearlo. Un criterio de aceptación serı́a que un ticket tenga un número
y este nunca pueda ser nulo o vació. El test unitario para esto es el anterior.
Este es el error que obtuvimos ”... ’Tickets’does not contain a definition for Ñumeroánd no
extension method Ñumeroáccepting a first argument of type ’Tickets’could be found”
Solucionando el error:
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
10 public string Numero = string . Empty ;
11
12 public string ObtenerNumero ()
13 {
14 return " EXA -001/17 " ;
15 }
16 }
17 }
El test no pasa (porque aún esta vació el número del ticket) todavı́a aunque el proyecto ya
compila. Tenemos que hacer pasar el test. Entonces seguimos agregando el código necesario.
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
10 public string Numero = string . Empty ;
11
12 public Tickets ()
13 {
14 Numero = " EXA -001/17 " ;
15 }
16 public string ObtenerNumero ()
17 {
18 return " EXA -001/17 " ;
19 }
20 }
21 }
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
10 public string Numero = string . Empty ;
11
12 public Tickets ()
13 {
14 Numero = " EXA -001/17 " ;
15 }
16 public string ObtenerNumero ()
17 {
18 return Numero ;
19 }
20 }
21 }
Lo que hicimos fue en el constructor de la clase darle un valor a Numero, y que la función
ObtenerNumero() devuelva el atributo.
Vamos a ver un caso mas. Los tickets tienen estado, pueden ser Nuevos, Aceptados, En Proceso,
Resuelto y quizás algún otro estado que todavı́a no estoy viendo. Haremos un test para la función
que nos devuelve el estado.
1 using System ;
2 using Microsoft . VisualStudio . TestTools . UnitTesting ;
3 using oysTickets ; // referencia al proyecto que estamos desarrollando
4
5
6 namespace TestTickets
7 {
8 [ TestClass ]
9 public class TestTickets
10 {
11 [ TestMethod ]
12 public void CrearTicketTest ()
13 {
14 Tickets ticket = new Tickets () ;
15 Assert . IsTrue (! string . IsNullOrEmpty ( ticket . Numero ) ) ;
16 }
17
18 [ TestMethod ]
19 public void ObtenerNumeroTest ()
20 {
21 Tickets ticket = new Tickets () ;
22 string numero = ticket . ObtenerNumero () ;
23 Assert . IsNotNull ( numero ) ;
24 }
25
26 [ TestMethod ]
27 public void ObtenerEstadoTest ()
28 {
29 Tickets ticket = new Tickets () ;
30 string estado = ticket . ObtenerEstado () ;
31 Assert . IsTrue (! string . IsNullOrEmpty ( estado ) ) ;
32 }
33 }
34 }
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
Los ejemplos planteados son para tener una idea de como empezar, hay muchas preguntas que
uno puede ir haciéndose a medida que desarrolla con TDD, tener la incertidumbre de como plantear
un test cuando ya ha pensado un diseño. Por ejemplo el valor del estado de un ticket podrı́a ser
una constante de una clase enums.
Me parece que la pregunta de como hacer un test unitario y hacer TDD para implementar
una funcionalidad te la harás muchas veces. Pero a medida que avances tendrás resuelto varias
situaciones de como plantear distintos casos.
1 using System ;
2 using Microsoft . VisualStudio . TestTools . UnitTesting ;
3 using oysTickets ; // referencia al proyecto que estamos desarrollando
4
5
6 namespace TestTickets
7 {
8 [ TestClass ]
9 public class TestTickets
10 {
11 [ TestMethod ]
12 public void CrearTicketTest ()
13 {
14 Tickets ticket = new Tickets () ;
15 Assert . IsTrue (! string . IsNullOrEmpty ( ticket . Numero ) ) ;
16 }
17
18 [ TestMethod ]
19 public void ObtenerNumeroTest ()
20 {
21 Tickets ticket = new Tickets () ;
22 string numero = ticket . ObtenerNumero () ;
23 Assert . IsNotNull ( numero ) ;
24 }
25
26 [ TestMethod ]
27 public void ObtenerEstadoTest ()
28 {
29 Tickets ticket = new Tickets () ;
30 string estado = ticket . ObtenerEstado () ;
31 Assert . IsTrue (! string . IsNullOrEmpty ( estado ) ) ;
32 }
33
34 [ TestMethod ]
35 public void EstadoEsValidoTest ()
36 {
37 Tickets ticket = new Tickets () ;
38 Assert . IsTrue (( Enum . IsDefined ( typeof ( Tickets . EstadosTicket ) ,
ticket . ObtenerEstado () ) )
);
39 }
40 }
41 }}
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
10 public string Numero = string . Empty ;
11
12 public enum EstadosTicket
13 {
14 Nuevo = 1 ,
15 Aceptado = 2 ,
16 EnProceso = 3 ,
17 Rechazado = 4 ,
18 Terminado = 5 ,
19 Pendiente = 6
20 }
21
22 public Tickets ()
23 {
24 Numero = " EXA -001/17 " ;
25 }
26 public string ObtenerNumero ()
27 {
28 return Numero ;
29 }
30 public string ObtenerEstado ()
31 {
32 return " Nuevo " ;
33 }
34 }
35 }
Nuestro test EstadoEsValidoTest no falla por que nuestro método ObtenerEstado devuelve ”Nue-
vo”que si esta como constante en nuestra clase enum. Ahora refactorizamos.
1 using System ;
2 using System . Collections . Generic ;
3 using System . Linq ;
4 using System . Web ;
5
6 namespace oysTickets
7 {
8 public class Tickets
9 {
10 public string Numero = string . Empty ;
11
12 public enum EstadosTicket
13 {
14 Nuevo = 1 ,
15 Aceptado = 2 ,
16 EnProceso = 3 ,
17 Rechazado = 4 ,
18 Terminado = 5 ,
19 Pendiente = 6
20 }
21
22 public Tickets ()
23 {
24 Numero = " EXA -001/17 " ;
25 }
26 public string ObtenerNumero ()
27 {
28 return Numero ;
29 }
30 public string ObtenerEstado ()
31 {
32 return EstadosTicket . Nuevo . ToString () ;
33 }
34 }
35 }
No hemos podido refactorizar mucho. Creo que sigue agregar a Estado como un atributo de
la clase Tickets y este debe ser del tipo enum definido. Y ası́ ir pensando cada test unitario para
cada atributo de nuestra clase. Aquı́ terminamos con los ejemplos. Te invito a ver el código que se
desarrollará en el capı́tulo 7.
A continuación una captura del entorno de trabajo con el IDE Visual Studio 2015. En la figura
podrás ver la lista de los test que fuimos desarrollando y el icono de color verde de que han pasado!.
Sistema de Seguimiento de
Incidentes (Tickets)
6.1. Visión
Sistema de Seguimiento de Incidentes comúnmente llamado ”Sistema de Tickets”, la particulari-
dad de este sistema es que será para una Dependencia de la Universidad Nacional de Salta llamada
Dirección de Obras y Servicios. Esta Dirección tiene a su cargo la inspección de los Servicios de: hi-
giene de espacios exteriores, interiores, mantenimiento de espacios verdes, luminarias y los servicios
en complejo universitario.
La idea con este Sistema de Tickets es poder identificar, controlar y llevar un seguimiento a
las tareas (pedidos) u ordenes de trabajo, que suelen ser de un cierta cantidad que ingresan a la
Dirección. De acuerdo a la temática de cada orden de trabajo puede surgir distintos tratamientos,
dependiendo de la escala y tipo de pedido del cual se trate. Según corresponda se deriva a una
área, las cuales pueden ser Servicios Generales, Dpto de Seguridad, Construcción y Mantenimiento,
y Dirección de Estudios y Proyectos. En Servicios Generales tenemos los talleres como ser el de
Carpinterı́a, Electricista, etc., a todos ellos los llamaremos departamentos.
Los pedidos que ingresan pasan por un criterio de derivación, por que algunos llevan asociado un
tiempo de investigación, relevamiento, documentación e incluso comunicación con los interesados
para poder ofrecer la mejor solución posible.
Algunos de los pedidos pueden terminar incluso en una obra de construcción o de mantenimiento.
Los proyectos que se convierten en Obra, se le asigna un numero de obra que los permite identificar.
El criterio histórico era asignar un número de obra de forma secuencial. El problema de esta forma
de asignación es no poder identificar de forma fácil en el numero dado a que unidad académica e
incluso a que edificio de gestión se trata.
Por lo expuesto, y a fines de comenzar a tomar acciones tendientes a mejorar la calidad de
124
Capı́tulo 6. Sistema de Seguimiento de Incidentes (Tickets)
2. Desarrollar un sistema web que utilice este nuevo sistema de numeración con la idea de
identificar, controlar y monitorear los pedidos que ingresan a la Dirección.
Independencia con personas concretas para llevar a cabo el despliegue. Como resultado la taza de
éxito del proyecto puede verse incrementada.
En resumen muchos de los beneficios obtenidos al utilizar las herramientas son los principios y
prácticas perseguidos por la comunidad ágil.
Tras el estudio de las herramientas para el presente trabajo se han elegido unas en particular, la
primera caracterı́stica buscada es crear un entorno de desarrollo de software open-source, las otras
caracterı́sticas fueron facilidad de uso y conocimiento previo de las mismas.
Git por resultar conocido previamente y ser compatible con los entornos de desarrollos cono-
cido NetBeans.
Redmine,la elección es justificada por ser una herramienta open-source y fácil de usar.
Poder crear un departamento con sus datos relevantes para la registración : Nombre, si es
publico (Para toda la Universidad o Interno), Responsable, Email para Respuesta automática,
fecha de creación, fecha de modificación.
Estos tres criterios de aceptación fueron desarrollados con TDD puro a modo de ejemplo en
PHP, Python y Perl usando Postgresql como base de datos. El código fuente de los ejemplos esta
adjunto a este proyecto.
6.2.3. Conclusión
La principal dificultad que tuve al empezar con TDD fue como formular el primer test, el cual
me orientará a la creación de la clase Departamentos y como trabajarı́a ella. Lo que hice fue, crear
un test que verificará la existencia de la clase, y otro la de sus atributos.En otros tests los métodos
necesarios de forma de ir implementando.
Al hacer refactorización mi código, surge una nueva clase a la que llame SqlLProvider, ya que
los métodos de acceso a la base de datos iban a ser los mismos para todas las clases del sistema.
Las dificultades que tuve fueron, en principio como plasmar en un test el diseño que querı́a para
mi clase, y la falta de seguridad en cuanto a si estaba haciendo la cantidad de test suficientes, o si
mi test debı́a ”meterse”más en el código del método que necesitaba implementar.
En conclusión me costo al principio, debı́a frenarme y no tentarme con las ganas de seguir
agregando código, detenerme a hacer el tests primero correspondiente o mejorar en el que estaba.
Creo que TDD es algo interesante y puede sacarse mucho provecho del hecho que vas teniendo todo
tu código probado, la seguridad que obtenes de ello, solo que cuesta acostumbrarse, y hasta a veces
es frustrante.
Conclusiones
Para algunos autores TDD es una práctica de programación, otros que profundizan más los
pasos del algoritmo de TDD llegan a llamarla metodologı́a ágil de diseño.
A mi modo de verlo, si la vemos como una práctica de desarrollo, es demasiado compleja de llevar
al pie de la letra, además de involucrar en su utilización muchas decisiones de diseño. A medida que
se desarrolla los test, uno tiene que hacerse preguntas de como modularizarás, que nombre darás
a tus clases, que atributos tendrán, que convenciones irás utilizando,¿és necesario implementar tal
función?, decisiones que se toman en el análisis, y en ese momento estás codificando y diseñando.
Además de otros factores que hay que tener en cuenta cómo cuando se refactoriza, usar patrones
de diseño, forzar aún más la reutilización de código, mantener la cohesión, medir el acoplamiento,
etc. Dirı́a que le queda chica la palabra ”práctica”.
Üna metodologı́a me da recetas”1 , TDD por si solo no da recetas, solo nos dice que hacer
en la siguiente interacción de su algoritmo, pero cada paso en el algoritmo trae un montón de
decisiones aparejadas como mencionamos anteriormente. Y si consideramos las variantes de TDD,
ATDD, BDD, etc. y Refactorización, se juntan muchas más recetas, herramientas y métodos, pero
TDD puro no es una metodologı́a ágil. Para considerarla metodologı́a ágil deberı́a darnos métodos
precisos para la parte de análisis, como para las otras etapas del desarrollo del software.
Podrı́amos decir que TDD es un paradigma de programación porque el conjunto de pasos que
tiene me da una forma de programar, una idea a seguir. Programar con TDD es totalmente diferente
a la forma que la mayorı́a viene acostumbrados.
En mi opinión seguir hacer TDD no te asegura calidad en tu software, hay que saber programar,
es fundamental entender y tener claro el dominio del problema, no puedes avanzar si no tienes claro
que tienes que hacer y aún teniéndolo claro puedes no saber plasmarlo, esta observación sirve para
todas las metodologı́as.
Hacer TDD se vuelve complicado cuando descnonoces el dominio del problema, o si no estas
acostumbrado al lenguaje de programación que usarás, si debes hacer TDD también sin tener un
1 Adriana Binda, 2016
128
Capı́tulo 7. Conclusiones
simple bosquejo o mapa conceptual del dominio del problema, si no tienes planes de como quieres
que funcione la aplicación en un futuro, por ejemplo agregar manejo de errores, cosas que despues
pueden llevar tiempo implementar si no las pensaste en un principio.
Además que usar TDD implica tener conocimiento en las herramientas de testing (estar acos-
tumbrado a hacer test), hay que prácticar para crear buenos test, podes hacer muchos de ellos y
no avanzar en buenos diseños. Se puede mejorar si se tiene idea de patrones de diseño, los métodos
de refactorización, saber identificar y buscar los ”malos olores.en el código. Creo que aún sabiendo
lo necesario siempre te queda la duda si generaste buenos tests, si probaste lo necesario.
Con un plugins en Jenkins que me analiza la cobertura de código en los tests pude comprobar
que aún partiendo de test, la cobertura del código no es completa. Cuando creo un test y en él
llamó un método que deberı́a estar en una clase, solo estoy diciendo que deberı́a existir en la clase,
pero no digo nada de como deberı́a hacer su función, no puedo prediseñar como realizará su tarea,
no puedo testear su eficienta, ni evitar que haga más cosas de las que deberı́a hacer, el test solo
asegurá que el resultado tiene que ser el esperado.
Entonces que paso de TDD me ayuda en crear código de calidad?, la refactorización, pero quizas
hay que mirar más a fondo, lo que da más calidad es saber de programación, conocer a fondo el
lenguaje de programación, saber de diseño, de patrones.
Aunque TDD no te asegura calidad, creo que aporta un versión de mayor calidad de tu código
que si no lo hubieras utilizado, ya que te obliga a pensar constantemente como mejorar lo que estas
haciendo, y que no debes hacer.
API La interfaz de programación de aplicaciones, abreviada como API del inglés: Application Pro-
gramming Interface,1 es un conjunto de subrutinas, funciones y procedimientos (o métodos,
en la programación orientada a objetos) que ofrece cierta biblioteca para ser utilizado por
otro software como una capa de abstracción.. 29
ATDD Story Test Driven Development, metodologı́a ágil de desarrollo. Ver capı́tulo 3.. 31
BSD Berkeley Software Distribution ( BSD ) fue un derivado del sistema operativo Unix desarro-
llado y distribuido por el Computer Systems Research Group (CSRG) de la Universidad de
California, Berkeley , de 1977 a 1995. Hoy en dı́a el término ”BSD” se utiliza a menudo no
especı́ficamente para se refieren a cualquiera de los descendientes BSD que juntos forman una
rama de la familia de sistemas operativos tipo Unix. Los sistemas operativos derivados del
código BSD original permanecen activamente desarrollados y ampliamente utilizados.. 90
CASE Computer- Arded Software Enginnering. Ingenierı́a de software asistida por ordenador (
CASE ) es el dominio de las herramientas de software utilizadas para diseñar e implementar
aplicaciones. Las herramientas CASE son similares y se inspiraron parcialmente en las he-
rramientas de diseño asistido por computadora (CAD) utilizadas para diseñar productos de
hardware. Las herramientas CASE se utilizan para desarrollar software de alta calidad, sin
defectos y mantenible. El software CASE se asocia a menudo con métodos para el desarrollo
130
Glosario
DDD Domain Driven Design.Diseño guiado por el dominio, metodologı́a ágil de desarrollo.Ver
capı́tulo 3.. 35
GNU GNU es un sistema operativo de tipo Unix desarrollado por y para el Proyecto GNU, y
auspiciado por la Free Software Foundation. Está formado en su totalidad por software libre,
mayoritariamente bajo términos de copyleft. GNU es el acrónimo recursivo de ”GNU’s Not
Unix” (en español: GNU no es Unix),12 nombre elegido debido a que GNU sigue un diseño
tipo Unix y se mantiene compatible con éste, pero se distingue de Unix por ser software libre
y por no contener código de Unix.. 62
GPL La Licencia Pública General de GNU o más conocida por su nombre en inglés GNU General
Public License (o simplemente sus siglas en inglés GNU GPL) es la licencia de derecho de autor
más ampliamente usada en el mundo del software libre y código abierto,6 y garantiza a los
usuarios finales (personas, organizaciones, compañı́as) la libertad de usar, estudiar, compartir
(copiar) y modificar el software. Su propósito es doble: declarar que el software cubierto
por esta licencia es libre, y protegerlo (mediante una práctica conocida como copyleft) de
intentos de apropiación que restrinjan esas libertades a nuevos usuarios cada vez que la obra
es distribuida, modificada o ampliada. Esta licencia fue creada originalmente por Richard
Stallman fundador de la Free Software Foundation (FSF) para el proyecto GNU... 62
GPLv2 Pública General GNU Versión 2. La Licencia Pública General de GNU o más conocida por
su nombre en inglés GNU General Public License (o simplemente sus siglas en inglés GNU
GPL) es la licencia de derecho de autor más ampliamente usada en el mundo del software
libre y código abierto, y garantiza a los usuarios finales (personas, organizaciones, compañı́as)
la libertad de usar, estudiar, compartir (copiar) y modificar el software. Su propósito es doble:
declarar que el software cubierto por esta licencia es libre, y protegerlo (mediante una práctica
conocida como copyleft) de intentos de apropiación que restrinjan esas libertades a nuevos
usuarios cada vez que la obra es distribuida, modificada o ampliada. Esta licencia fue creada
originalmente por Richard Stallman fundador de la Free Software Foundation (FSF) para el
proyecto GNU.. 87
HTTPD Demonio del servidor Apache desarrollado y mantenido por una comunidad de usuarios
bajo la supervisión de la Apache Software Foundation dentro del proyecto HTTP Server
(httpd).. 86
iOS Sistema operativo móvil de la multinacional Apple Inc. Originalmente desarrollado para el
iPhone (iPhone OS), después se ha usado en dispositivos como el iPod touch y el iPad.En el
año 2015 pasó a ser de código abierto.. 89
NUnit NUnit es un framework open source de Pruebas de unidad para Microsoft .NET y Mono.
Sirve al mismo propósito que JUnit realiza en el mundo Java, y es uno de muchos en la familia
xUnit.. 33, 34
RAD El desarrollo rápido de aplicaciones o RAD (acrónimo en inglés de Rapid Application Deve-
lopment) es un proceso de desarrollo de software, desarrollado inicialmente por James Martin
en 1980. El método comprende el desarrollo interactivo, la construcción de prototipos y el
uso de utilidades CASE (ingenierı́a asistida por computadora). Tradicionalmente, el desarro-
llo rápido de aplicaciones tiende a englobar también la usabilidad, utilidad y la rapidez de
ejecución.. 21
RCS Revision Control System. Es una implementación en software del control de versiones que
automatiza las tareas de guardar, recuperar, registrar, identificar y mezclar versiones de ar-
chivos. RCS es útil para archivos que son modificados frecuentemente, por ejemplo programas
informáticos, documentación, gráficos de procedimientos, monografı́as y cartas. RCS también
puede ser utilizado para manejar archivos binarios, pero con eficacia y eficiencia reducidas.
Las distintas versiones son archivadas mediante la ayuda de la herramienta diff.. 84
RUP El Proceso Racional Unificado o RUP (por sus siglas en inglés de Rational Unified Process)
es un proceso de desarrollo de software desarrollado por la empresa Rational Software, actual-
mente propiedad de IBM. Junto con el Lenguaje Unificado de Modelado (UML), constituye la
metodologı́a estándar más utilizada para el análisis, diseño, implementación y documentación
de sistemas orientados a objetos.. 16
STDD Story Test Driven Development, metodologı́a ágil de desarrollo. Ver capı́tulo 3.. 31
SUnit Un diseño de Kent Beck, implementados originalmente para Smalltalk como SUnit, pero
están ahora disponibles para muchos lenguajes de programación y plataformas.. 34
TDD Test Driven Development, desarrollo guiado por pruebas.ver Capı́tulo 3.. 5, 24
TFVC Team Foundation Version Control (TFVC) es un sistema de control de versiones centrali-
zado. Normalmente, los miembros del equipo sólo tienen una versión de cada archivo en sus
máquinas de dev. Los datos históricos se mantienen únicamente en el servidor. Las sucursales
están basadas en rutas de acceso y creadas en el servidor.. 88
UML El lenguaje unificado de modelado (UML, por sus siglas en inglés, Unified Modeling Lan-
guage) es el lenguaje de modelado de sistemas de software más conocido y utilizado en la
actualidad; está respaldado por el Object Management Group (OMG).. 16
UTDD En castellano se traducirı́a como “Desarrollo guiado por las pruebas unitarias.. 34
WIP Work in Progress, trabajo en proceso, productos en proceso, o inventario en proceso son los
productos parcialmente terminados que esperan la terminación y la venta eventual o el valor
de estos artı́culos.. 23
[1] Gojko Adzic. Bridging the Communication Gap: Specification by Example and Agile Acceptance
Testing. Neuri Consulting Llp, 2009. ISBN 0-9556836-1-0.
[2] Alfredo Chavez. TDD Cómo y porqué: Una guı́a para los no ini-
ciados ·. 2017. URL http://artesanos.de/software/2012/02/13/
tdd-como-y-porque-una-guia-para-los-no-iniciados/.
[3] Alicia Salamon, Francisco Coenda, Patricio Maller, Alejandra Boggio, Natalia Mira, y Sofia
Perez. La integración continua aplicada en el desarrollo de software en el ámbito cientı́fi-
co–técnico. 2014. URL http://sedici.unlp.edu.ar/handle/10915/42358.
[4] Agile Alliance. BDD Learn about Behavior Driven Development. 2015. URL https://www.
agilealliance.org/glossary/bdd/.
[6] Basecamp. Replace all over the place with ONE place. 2017. URL https://basecamp.com.
[7] Kent Beck. Una explicación de la programación extrema: aceptar el cambio. Addison Wesley,
Madrid, 2002. ISBN 978-84-7829-055-0. OCLC: 433200877.
[9] Bob Hartman. Why Unit Test-Driven Development is Important. 2008. URL http:
//agileforall.com/why-unit-test-driven-development-is-important/.
[11] William J Brown, Hays W McCormick, y Scott W Thomas. Anti Patterns Project Management.
John Wiley & Sons, Inc., 2000.
[12] Carlos Blé Jurado. Diseño Ágil con TDD. 2010. URL http://www.carlosble.com/
downloads/disenoAgilConTdd_ebook.pdf.
135
Bibliografı́a
[13] Comunidad Avanet. Charlas en Lı́nea: Esencia y Fundamentos de TDD. 2014. URL https:
//www.youtube.com/watch?v=4t0ZxUXnwN4.
[16] Dan Haywood. Introducción al diseño impulsado por el dominio. 2017. URL http://www.
methodsandtools.com/archive/archive.php?id=97.
[19] David Valverde. Introducción a la Programación Extrema (XP). 2007. URL http://www.
davidvalverde.com/blog/introduccion-a-la-programacion-extrema-xp/.
[20] Ana M del Carmen Garcı́a Oterino. Aprende a implantar integración continua desde cero (I):
¿Por qué integración continua? - Javier Garzás. 2014. URL http://www.javiergarzas.com/
2014/08/implantar-integracion-continua.html.
[21] Paul M Duvall, Steve Matyas, y Andrew Glover. Continuous Integration Improving Software
Quality and Reducing Risk. Pearson Education, Inc., 2008. ISBN 978-0-321-33638-5. URL
https://www.amazon.com/Continuous-Integration-Improving-Software-Reducing/dp/
0321336380.
[23] Eric Evans. Domain Driven Design: Tackling Complexity in the Heart of Software. Addison-
Wesley Professional, Boston, 1 edition edón., 2003. ISBN 978-0-321-12521-7.
[24] Moisés Carlos Fontela. Estado del arte y tendencias en Test-Driven Development. 2012.
[25] Apache Software Foundation. Caracterı́sticas de Apache Subversion. 2017. URL http://
subversion.apache.org/features.html.
[26] Francisco José Gómez y Caldito Viseas. Evaluación de la calidad de código usando TDD en
el desarrollo de la lógica de negocio de un sistema de información para un club deportivo.
2013. URL https://acceda.ulpgc.es:8443/bitstream/10553/11186/1/0693029_00000_
0000.pdf.
[27] Hirotaka Takeuchi y Ikujiro Nonaka. The New New Product Development Game.
1986. URL http://www.wz.uw.edu.pl/pracownicyFiles/id12540-Takeuchi,%20Nonaka%
20-%20The%20new%20product%20development%20game.pdf.
[28] James Highsmith III. Adaptive Software Development. Addison-Wesley, 2013. ISBN 978-0-
932633-40-8. URL http://www.dorsethouse.com/books/asd.html.
[30] Jose Javier Rodrı́guez Álvarez. INVESTIGACIÓN DE LOS MÉTODOS ÁGILES PA-
RA SU IMPLANTACIÓN EN UN LABORATORIO DE SEGURIDAD ELÉCTRICA.
2013. URL https://upcommons.upc.edu/bitstream/handle/2099.1/20733/TFM_metodos%
20agiles.pdf.
[32] La Fundación Apache Software. Maven Welcome to Apache Maven. 2017. URL https:
//maven.apache.org/.
[33] Michele Lanza y Radu Marinescu. Object oriented metrics in practice: using software metrics
to characterize, evaluate, and improve the design of object-oriented systems. Springer Science
& Business Media, 2007.
[34] Patricio Letelier y Ma Carmen Penadés. Métodologı́as ágiles para el desarrollo de software:
eXtreme Programming (XP). 2006. URL http://www.cyta.com.ar/ta0502/v5n2a1.htm.
[38] Naouel Moha. DECOR Détection et correction des défauts dans les systemes orientés objet.
Tesis Doctoral, Université des Sciences et Technologie de Lille-Lille I, 2008.
[39] Hausi A. Müller, Scott R. Tilley, y Kenny Wong. Understanding Software Systems Using
Reverse Engineering Technology Perspectives from the Rigi Project. En Proceedings of the 1993
Conference of the Centre for Advanced Studies on Collaborative Research: Software Engineering
- Volume 1, CASCON ’93, págs. 217–226. IBM Press, Toronto, Ontario, Canada, 1993. URL
http://dl.acm.org/citation.cfm?id=962289.962309.
[40] John Nosek. The Case for Collaborative Programming. Communications of the ACM, 41,
1998.
[41] William F Opdyke. Refactoring A program restructuring aid in designing object-oriented ap-
plication frameworks. Tesis Doctoral, PhD thesis, University of Illinois at Urbana-Champaign,
1992.
[42] OTTONIEL HERNÁNDEZ ISTUPE. Scrum, una alternativa viable para la gestión de pro-
yectos de software. Tesis Doctoral, UNIVERSIDAD RAFAEL LANDÍVAR, 2009. URL http:
//bibliod.url.edu.gt/Tesis/02/08/Hermandez-Ottoniel/Hermandez-Ottoniel.pdf.
[43] Giorgia Paolini. Agile Git CI with TFS. 2016. URL https://www.visualstudio.com/es/
tfs/.
[44] Guı́a PMBOK. Guı́a de los Fundamentos de la Dirección de Proyectos. Project Management
Institute Inc, 2, 2008.
[46] Robert C Martin,, Micah D Martin,, y Patrick Wilson-Galés. FitNesse UserGuide. 2017. URL
http://fitnesse.org/FitNesse.UserGuide.
[48] Scott Wambler. Introduction to Test Driven Development (TDD). 2016. URL http://www.
rivetq.com/wp-content/uploads/2016/08/TDD.pdf.
[50] SoftwareAdvice. Reseñas capturas de pantalla y caracterı́sticas de JIRA. 2017. URL https:
//www.softwareadvice.co/software/4315/atlassian-jira.
[51] Srini Penchikala. Domain Driven Design and Development In Practice. 2008. URL https:
//www.infoq.com/articles/ddd-in-practice.
[53] Tamara Torres. Análisis y adaptación de BDD en un desarrollo semi-ágil: un caso de estudio.
Tesis, Facultad de Informática, 2016. URL http://hdl.handle.net/10915/59101.
[54] Travis CI GmbH. Travis CI Test and Deploy with Confidence. 2017. URL https:
//travis-ci.com/.
[55] Vaca, Pablo y Maldonado, Calixto. Test Driven Development Una aproximación para entender
su utilidad en el proceso de desarrollo de Software. 2017. URL http://www.carlosble.com/
downloads/disenoAgilConTdd_ebook.pdf.
[60] Derek Robert Price y Ximbiot. CVS Open Source Version Control. 2017. URL http://www.
nongnu.org/cvs/.