escuela polit ecnica nacional´bibdigital.epn.edu.ec/bitstream/15000/15148/1/cd-6928.pdf ·...
TRANSCRIPT
ESCUELA POLITECNICA NACIONAL
FACULTAD DE INGENIERIA DE SISTEMAS
DESARROLLO DE UNA LIBRERIA UTILITARIA FUNCIONAL
SOBRE UN LENGUAJE ORIENTADO A OBJETOS, APLICADA A
UN CASO DE ESTUDIO
PROYECTO PREVIO A LA OBTENCION DEL TITULO DE INGENIERO EN
SISTEMAS INFORMATICOS Y DE COMPUTACION
SEBASTIAN ESTRELLA HEREDIA
DIRECTOR: ING. ENRIQUE ANDRES LARCO AMPUDIA, MSc.
Quito, abril 2016
DECLARACION
Yo, Sebastian Estrella Heredia, declaro bajo juramento que el trabajo aquı descri-
to es de mi autorıa; que no ha sido previamente presentada para ningun grado o
calificacion profesional; y, que he consultado las referencias bibliograficas que se
incluyen en este documento.
A traves de la presente declaracion cedo mis derechos de propiedad intelectual
correspondientes a este trabajo, a la Escuela Politecnica Nacional, segun lo esta-
blecido por la Ley de Propiedad Intelectual, por su Reglamento y por la normatividad
institucional vigente.
Sebastian Estrella Heredia
I
CERTIFICACION
Certifico que el presente trabajo fue desarrollado por Sebastian Estrella Heredia,
bajo mi supervision.
Ing. Enrique Andres Larco Ampudia, MSc.
Director del Proyecto
II
AGRADECIMIENTOS
A mi esposa, por su amor y apoyo incondicional durante todo este largo camino
recorrido juntos, no habrıa podido superar todos los obstaculos sin su apoyo y com-
prension.
A mi madre, por su ejemplo de fortaleza y voluntad a lo largo de toda su vida, lo
cual me a servido de ejemplo para superar todos los desafıos.
A mis hermanas, por su alegrıa carino, gracias por siempre llenarme de alegrıa y
saber escucharme en aquellos momentos que lo necesitaba.
A mis tıos y tıas, por cuidarme como uno mas de sus hijos y saber darme sus
mejores consejos y guiarme por el camino correcto.
A mis primos y primas, por ser mis companeros de travesuras y ser la nueva gene-
racion que nos llena de alegrıa.
A mis suegros, por abrirme las puertas de su hogar y corazon, como uno mas de
sus hijos.
A mis cunados y cunada, por su alegrıa y coraje para siempre seguir adelante y
saber luchar las batallas mas difıciles.
III
DEDICATORIA
En memoria de mis abuelos, gracias por todo su amor y carino incondicional.
IV
CONTENIDO
Resumen 1
Presentacion 2
1. Marco Teorico 3
1.1. Definicion del Paradigma de Programacion Funcional . . . . . . . . . 3
1.1.1. Caracterısticas Generales . . . . . . . . . . . . . . . . . . . . . 3
1.1.2. Lenguaje de Programacion Haskell . . . . . . . . . . . . . . . . 7
1.2. Definicion del Paradigma de Programacion Orientado a Objetos . . . 8
1.2.1. Caracterısticas Generales . . . . . . . . . . . . . . . . . . . . . 8
1.2.2. Lenguaje de Programacion Java . . . . . . . . . . . . . . . . . 12
1.3. Comparacion entre Paradigmas Funcional y Orientado a Objetos . . . 13
1.3.1. Comparacion entre Paradigmas . . . . . . . . . . . . . . . . . 13
1.3.2. Comparacion entre Lenguajes . . . . . . . . . . . . . . . . . . 15
1.3.3. Analisis de Resultados . . . . . . . . . . . . . . . . . . . . . . . 17
1.4. Estilo de Programacion Funcional sobre un Lenguaje Orientado a Ob-
jetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
V
VI
1.4.1. Patrones de Diseno Funcionales . . . . . . . . . . . . . . . . . 18
1.4.2. Estado del Arte . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2. Desarrollo de la Librerıa Utilitaria Funcional 50
2.1. Analisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.1.1. Retrocompatibilidad . . . . . . . . . . . . . . . . . . . . . . . . 55
2.1.2. Limitaciones del Lenguaje de Programacion Java . . . . . . . . 56
2.1.3. Analisis de Portabilidad . . . . . . . . . . . . . . . . . . . . . . 62
2.2. Diseno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.2.1. Estructura de Codigo . . . . . . . . . . . . . . . . . . . . . . . 68
2.2.2. Comportamiento . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.2.3. Documentacion del Codigo . . . . . . . . . . . . . . . . . . . . 74
2.3. Desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.3.1. Desarrollo Guiado por Pruebas . . . . . . . . . . . . . . . . . . 76
2.3.2. Integracion Continua . . . . . . . . . . . . . . . . . . . . . . . . 79
2.3.3. Tecnicas Empleadas . . . . . . . . . . . . . . . . . . . . . . . . 81
2.4. Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.4.1. Niveles de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . 86
2.4.2. Tipos de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.4.3. Planificacion de Pruebas . . . . . . . . . . . . . . . . . . . . . 90
2.4.4. Cobertura de Pruebas . . . . . . . . . . . . . . . . . . . . . . . 94
VII
2.4.5. Pruebas de Mutacion . . . . . . . . . . . . . . . . . . . . . . . 95
2.4.6. Ejemplos de Pruebas . . . . . . . . . . . . . . . . . . . . . . . 97
2.4.7. Reporte de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . 101
3. Aplicacion de la Librerıa Funcional a un Caso de Estudio 103
3.1. Refactorizacion Funcional de una Aplicacion Orientada a Objetos . . 103
3.1.1. Seleccion del Caso de Estudio . . . . . . . . . . . . . . . . . . 103
3.1.2. Refactorizacion del Caso de Estudio . . . . . . . . . . . . . . . 112
3.2. Analisis de Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
3.2.1. Complejidad Ciclomatica (CC) . . . . . . . . . . . . . . . . . . 119
3.2.2. Comparacion de Resultados . . . . . . . . . . . . . . . . . . . 120
4. Conclusiones y Recomendaciones 123
4.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
4.2. Recomendaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Siglas 126
Glosario 126
Biblografıa 129
Anexos 133
.1. Capturas de Pantalla de GitHub . . . . . . . . . . . . . . . . . . . . . . 133
.2. Capturas de Pantalla de JIRA . . . . . . . . . . . . . . . . . . . . . . . 134
LISTADO DE TABLAS
1.1. Caracterısticas Principales de Haskell . . . . . . . . . . . . . . . . . . 8
1.2. Caracterısticas de Java . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.3. Comparacion entre Paradigmas . . . . . . . . . . . . . . . . . . . . . . 15
1.4. Comparacion entre Lenguajes . . . . . . . . . . . . . . . . . . . . . . 17
1.5. Estilos de Programacion Funcional en OOP . . . . . . . . . . . . . . . 18
1.6. Caracterısticas de Rust . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.7. Caracterısticas de Clojure . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.8. Caracterıstica de Elixir . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.9. Caracterısticas de Scala . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.10.Caracterısticas de Erlang . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.11.Caracterısticas de OCaml . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.12.Caracterısticas de functional.js . . . . . . . . . . . . . . . . . . . . . . 44
1.13.Caracterısticas de Javaslang . . . . . . . . . . . . . . . . . . . . . . . 45
1.14.Caracterısticas de functional-ruby . . . . . . . . . . . . . . . . . . . . 46
1.15.Caracterısticas de functional-php . . . . . . . . . . . . . . . . . . . . . 47
VIII
IX
1.16.Caracterısticas de Underscore.js . . . . . . . . . . . . . . . . . . . . . 48
2.1. Product Backlog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2. Sprint #1 - Spring Backlog . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.3. Sprint #2 - Spring Backlog . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.4. Sprint #3 - Spring Backlog . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.5. Proceso de Ejecucion - Funcion Suma . . . . . . . . . . . . . . . . . . 61
2.6. Analisis de Portabilidad . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.7. Niveles de Pruebas Utilizados . . . . . . . . . . . . . . . . . . . . . . . 88
2.8. Tipos de Pruebas Utilizados . . . . . . . . . . . . . . . . . . . . . . . . 90
2.9. Categorıas de Pruebas - Pruebas de Compatibilidad . . . . . . . . . . 98
2.10.Categorıas de Pruebas - Cobertura de Pruebas . . . . . . . . . . . . . 99
2.11.Categorıas de Pruebas - Pruebas de Mutacion . . . . . . . . . . . . . 100
2.12.Categorıas de Pruebas - Pruebas de Unitarias . . . . . . . . . . . . . 101
3.1. Interpretacion de Metricas . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.2. Numero de Lıneas de Codigo por Clase . . . . . . . . . . . . . . . . . 113
3.3. Comparacion de la Complejidad Ciclomatica . . . . . . . . . . . . . . 121
3.4. Comparacion de Resultados . . . . . . . . . . . . . . . . . . . . . . . 122
LISTADO DE FIGURAS
1.1. Curso Universidad de Edinburgh . . . . . . . . . . . . . . . . . . . . . 24
1.2. Curso Universidad de Nottingham . . . . . . . . . . . . . . . . . . . . 25
1.3. Curso Universidad de Oxford . . . . . . . . . . . . . . . . . . . . . . . 25
1.4. Curso Universidad Tecnologica Nacional . . . . . . . . . . . . . . . . . 26
1.5. Curso Universidad de los Andes . . . . . . . . . . . . . . . . . . . . . 26
1.6. Curso Universidad de Oklahoma . . . . . . . . . . . . . . . . . . . . . 27
1.7. Haxl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.8. Swift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.9. F# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.10.Intel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.11.Whatsapp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.12.SumAll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1. Release Burndown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.2. Uso de las Versiones de JDK . . . . . . . . . . . . . . . . . . . . . . . 56
2.3. Numero de Modulos Importados . . . . . . . . . . . . . . . . . . . . . 68
X
XI
2.4. Estructura de Paquetes . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.5. Diagrama de Actividad - Maybe.maybe . . . . . . . . . . . . . . . . . . 72
2.6. Diagrama de Actividad - Maybe.isNothing . . . . . . . . . . . . . . . . 73
2.7. Diagrama de Actividad - Maybe.isJust . . . . . . . . . . . . . . . . . . 74
2.8. Ejemplo de Javadoc . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.9. Captura de Pantalla de Hackage . . . . . . . . . . . . . . . . . . . . . 75
2.10.Ciclo de Vida - TDD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.11.Diagrama de Actividad - Maybe.isNothing . . . . . . . . . . . . . . . . 77
2.12.Captura de Pantalla de Bitbucket . . . . . . . . . . . . . . . . . . . . . 80
2.13.Captura de Pantalla de Shippable . . . . . . . . . . . . . . . . . . . . 81
2.14.Diagrama de Flujo - Planificacion de Pruebas . . . . . . . . . . . . . . 94
2.15.Flujo de Trabajo Pruebas de Mutacion . . . . . . . . . . . . . . . . . . 96
2.16.Pruebas de Compatibilidad . . . . . . . . . . . . . . . . . . . . . . . . 98
2.17.Resumen de Cobertura de Pruebas . . . . . . . . . . . . . . . . . . . 99
2.18.Resumen de Cobertura de Pruebas . . . . . . . . . . . . . . . . . . . 99
2.19.Mutantes Activos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
2.20.Reporte de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
3.1. Repositorio de JUnit en GitHub . . . . . . . . . . . . . . . . . . . . . . 104
3.2. Top 5 Librerıas de Java mas Utilizadas . . . . . . . . . . . . . . . . . . 106
3.3. Posibles Casos de Estudio (Datos Obtenidos) . . . . . . . . . . . . . . 107
XII
3.4. Posibles Casos de Estudio (Datos Normalizados) . . . . . . . . . . . . 109
3.5. Posibles Casos de Estudio (Datos Ajustados) . . . . . . . . . . . . . . 111
3.6. Criterio de Seleccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
1. Repositorio de Google Guava . . . . . . . . . . . . . . . . . . . . . . . 133
2. Repositorio de JUnit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
3. Repositorio de Log4j . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
4. Repositorio de SLF4J . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
5. Seguimiento de Incidentes de Commons BCEL . . . . . . . . . . . . . 134
6. Seguimiento de Incidentes de Commons BeanUtils . . . . . . . . . . . 134
7. Seguimiento de Incidentes de Commons BSF . . . . . . . . . . . . . . 135
8. Seguimiento de Incidentes de Commons Chain . . . . . . . . . . . . . 135
9. Seguimiento de Incidentes de Commons CLI . . . . . . . . . . . . . . 135
10. Seguimiento de Incidentes de Commons Codec . . . . . . . . . . . . 136
11. Seguimiento de Incidentes de Commons Collections . . . . . . . . . . 136
12. Seguimiento de Incidentes de Commons Compress . . . . . . . . . . 136
13. Seguimiento de Incidentes de Commons Configuration . . . . . . . . 137
14. Seguimiento de Incidentes de Commons CSV . . . . . . . . . . . . . 137
15. Seguimiento de Incidentes de Commons Daemon . . . . . . . . . . . 137
16. Seguimiento de Incidentes de Commons Dbcp . . . . . . . . . . . . . 138
17. Seguimiento de Incidentes de Commons Dbutils . . . . . . . . . . . . 138
XIII
18. Seguimiento de Incidentes de Commons Digester . . . . . . . . . . . 138
19. Seguimiento de Incidentes de Commons Discovery . . . . . . . . . . 139
20. Seguimiento de Incidentes de Commons EL . . . . . . . . . . . . . . . 139
21. Seguimiento de Incidentes de Commons Email . . . . . . . . . . . . . 139
22. Seguimiento de Incidentes de Commons Exec . . . . . . . . . . . . . 140
23. Seguimiento de Incidentes de Commons FileUpload . . . . . . . . . . 140
24. Seguimiento de Incidentes de Commons Functor . . . . . . . . . . . . 140
25. Seguimiento de Incidentes de Commons Imaging . . . . . . . . . . . . 141
26. Seguimiento de Incidentes de Commons IO . . . . . . . . . . . . . . . 141
27. Seguimiento de Incidentes de Commons JCI . . . . . . . . . . . . . . 141
28. Seguimiento de Incidentes de Commons JCS . . . . . . . . . . . . . . 142
29. Seguimiento de Incidentes de Commons Jelly . . . . . . . . . . . . . . 142
30. Seguimiento de Incidentes de Commons JEXL . . . . . . . . . . . . . 142
31. Seguimiento de Incidentes de Commons JXPath . . . . . . . . . . . . 143
32. Seguimiento de Incidentes de Commons JXPath . . . . . . . . . . . . 143
33. Seguimiento de Incidentes de Commons Lang . . . . . . . . . . . . . 143
34. Seguimiento de Incidentes de Commons Launcher . . . . . . . . . . . 144
35. Seguimiento de Incidentes de Commons Log4j . . . . . . . . . . . . . 144
36. Seguimiento de Incidentes de Commons Logging . . . . . . . . . . . . 144
37. Seguimiento de Incidentes de Commons Math . . . . . . . . . . . . . 145
38. Seguimiento de Incidentes de Commons Modeler . . . . . . . . . . . 145
XIV
39. Seguimiento de Incidentes de Commons Net . . . . . . . . . . . . . . 145
40. Seguimiento de Incidentes de Commons OGNL . . . . . . . . . . . . 146
41. Seguimiento de Incidentes de Commons Pool . . . . . . . . . . . . . . 146
42. Seguimiento de Incidentes de Commons Primitives . . . . . . . . . . . 146
43. Seguimiento de Incidentes de Commons Proxy . . . . . . . . . . . . . 147
44. Seguimiento de Incidentes de Commons SCXML . . . . . . . . . . . . 147
45. Seguimiento de Incidentes de Commons Validator . . . . . . . . . . . 147
46. Seguimiento de Incidentes de Commons VFS . . . . . . . . . . . . . . 148
47. Seguimiento de Incidentes de Commons VFS . . . . . . . . . . . . . . 148
48. Seguimiento de Incidentes de Commons Weaver . . . . . . . . . . . . 148
LISTADO DE FRAGMENTOS DE CODIGO
1.1. Ejemplo de Funcion de Orden Superior . . . . . . . . . . . . . . . . . 4
1.2. Ejemplo de Funcion Pura . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3. Ejemplo de Funcion Impura . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4. Ejemplo de Datos Inmutables . . . . . . . . . . . . . . . . . . . . . . . 5
1.5. Ejemplo de Datos Mutables . . . . . . . . . . . . . . . . . . . . . . . . 6
1.6. Ejemplo de Referencia Transparencial . . . . . . . . . . . . . . . . . . 6
1.7. Ejemplo Contrario de Referencia Transparencial . . . . . . . . . . . . 7
1.8. Ejemplo de Encapsulamiento . . . . . . . . . . . . . . . . . . . . . . . 9
1.9. Ejemplo de Herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.10.Ejemplo de Polimorfismo . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.11.Ejemplo de Composicion . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.12.Ejemplo de Encapsulamiento Estatico . . . . . . . . . . . . . . . . . . 19
1.13.Extraccion de Codigo (Encapsulamiento Estatico) . . . . . . . . . . . 20
1.14.Refactorizacion utilizando Encapsulamiento Estatico . . . . . . . . . . 21
1.15.Ejemplo de Objeto como Contenedor . . . . . . . . . . . . . . . . . . 22
1.16.Ejemplo de Codigo como Datos . . . . . . . . . . . . . . . . . . . . . . 23
1.17.Ejemplo de Lınea de Comandos . . . . . . . . . . . . . . . . . . . . . 23
1.18.Ejemplo de Rust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
1.19.Ejemplo de Clojure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.20.Ejemplo de Elixir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
1.21.Ejemplo de Scala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.22.Ejemplo de Erlang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.23.Ejemplo de OCaml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.24.Ejemplo de functional.js . . . . . . . . . . . . . . . . . . . . . . . . . . 44
XV
XVI
1.25.Ejemplo de Javaslang . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.26.Ejemplo de functional-ruby . . . . . . . . . . . . . . . . . . . . . . . . 47
1.27.Ejemplo de functional-php . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.28.Ejemplo de Underscore.js . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.1. Efecto Secundario Explıcito . . . . . . . . . . . . . . . . . . . . . . . . 57
2.2. Efecto Secundario Implıcito . . . . . . . . . . . . . . . . . . . . . . . . 57
2.3. Evaluacion Perezosa - Haskell . . . . . . . . . . . . . . . . . . . . . . 58
2.4. Evaluacion Perezosa - Java . . . . . . . . . . . . . . . . . . . . . . . . 58
2.5. Ejemplo de Funcion de Orden Superior . . . . . . . . . . . . . . . . . 59
2.6. Funcion Suma en Haskell . . . . . . . . . . . . . . . . . . . . . . . . . 59
2.7. Funcion Suma en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.8. Ejemplo de Uso Funcion Suma en Haskell . . . . . . . . . . . . . . . . 60
2.9. Ejemplo de Uso Funcion Suma en Java . . . . . . . . . . . . . . . . . 60
2.10.Ejemplo de Aplicacion Parcial de Funciones . . . . . . . . . . . . . . . 62
2.11.Modulo Maybe en Haskell . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.12.Interfaz Maybe en Java . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.13.Modulo Maybe en Java . . . . . . . . . . . . . . . . . . . . . . . . . . 70
2.14.Ejemplo de Uso - Maybe.maybe . . . . . . . . . . . . . . . . . . . . . 71
2.15.Ejemplo de Uso - Maybe.isNothing . . . . . . . . . . . . . . . . . . . . 72
2.16.Ejemplo de Uso - Maybe.isJust . . . . . . . . . . . . . . . . . . . . . . 73
2.17.Prueba isNothingReturnsTrue . . . . . . . . . . . . . . . . . . . . . . . 78
2.18.Primera Iteracion isNothing . . . . . . . . . . . . . . . . . . . . . . . . 78
2.19.Prueba isNothingReturnsFalse . . . . . . . . . . . . . . . . . . . . . . 79
2.20.Segunda Iteracion isNothing . . . . . . . . . . . . . . . . . . . . . . . 79
2.21.Estructura de Datos Funcion . . . . . . . . . . . . . . . . . . . . . . . 82
2.22.Ejemplo de Funcion de Orden Superior . . . . . . . . . . . . . . . . . 82
2.23.Funcion Parcialmente Aplicada . . . . . . . . . . . . . . . . . . . . . . 83
2.24.Ejemplo de Uso Funcion de Orden Superior . . . . . . . . . . . . . . . 83
2.25.Ejemplo de Currying . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
2.26.Ejemplo de Uso de Currying . . . . . . . . . . . . . . . . . . . . . . . . 84
2.27.Ejemplo de Aplicacion Parcial de Funciones . . . . . . . . . . . . . . . 85
2.28.Proceso de Construccion de Gradle . . . . . . . . . . . . . . . . . . . 91
XVII
2.29.Ejemplo de Prueba Unitaria . . . . . . . . . . . . . . . . . . . . . . . . 101
3.1. Metodo fail Antes de la Refactorizacion . . . . . . . . . . . . . . . . . 113
3.2. Metodo fail Despues de la Refactorizacion . . . . . . . . . . . . . . . 114
3.3. Metodo equalsRegardingNull Antes de la Refactorizacion . . . . . . . 115
3.4. Metodo equalsRegardingNull Despues de la Refactorizacion . . . . . 115
3.5. Metodo doubleIsDifferent Antes de la Refactorizacion . . . . . . . . . 116
3.6. Metodo floatIsDifferent Antes de la Refactorizacion . . . . . . . . . . . 116
3.7. Metodo doubleIsDifferent Despues de la Refactorizacion . . . . . . . 117
3.8. Metodo floatIsDifferent Despues de la Refactorizacion . . . . . . . . . 117
3.9. Metodo isDifferent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
3.10.Metodo formatClassAndValue Antes de la Refactorizacion . . . . . . . 118
3.11.Metodo formatClassAndValue Despues de la Refactorizacion . . . . . 118
3.12.Metodo doubleIsDifferent . . . . . . . . . . . . . . . . . . . . . . . . . 120
RESUMEN
En el capıtulo 1, se presenta una breve introduccion sobre los paradigmas de pro-
gramacion funcionales y orientados a objetos, al igual que una introduccion sobre
los lenguajes de programacion Haskell y Java. Una vez definidos dichos paradig-
mas y lenguajes de programacion, se procedio a realizar una comparacion entre
ellos.
En el capıtulo 2, se definio el alcance de la librerıa desarrollada, basandose en
algunos criterios, como son las limitaciones del lenguaje y la compatibilidad con
versiones anteriores de la JVM (desde la version 1.6 en adelante). Una vez definido
el alcance de la librerıa se procedio a la implementacion utilizando la tecnica de
desarrollo guiado por pruebas (TDD).
En el capıtulo 3, se selecciono a JUnit como caso de estudio utilizando criterios de
seleccion previamente definidos: porcentaje de uso, numero de problemas reporta-
dos y numero de solicitudes de cambio. Una vez seleccionado el caso de estudio,
se refactorizo el codigo utilizando la librerıa desarrollada en el capıtulo 2, y se midio
los resultados obtenidos en termino de la complejidad ciclomatica, encontrando una
mejora mayor al 50 %.
Finalmente el capıtulo 4, contiene las conclusiones y recomendaciones encontradas
durante la realizacion del proyecto.
1
PRESENTACION
La naturaleza del software es evolutiva, ya que se debe ajustar a las necesidades
definidas por los usuarios. Dichos ajustes deben ser realizado con frecuencia, lo
cual depende directamente del diseno del software. Un software altamente acopla-
do sera difıcil de mantener, ya que cualquier cambio causarıa una serie de efectos
en cascada, volviendo las tareas de mantenimiento y correccion de errores compli-
cadas.
El paradigma funcional realiza una clara separacion entre datos y funcionalidad lo
cual permite desarrollar aplicaciones bajamente acopladas, estos conceptos fueron
aplicados dentro de una librerıa funcional para desarrollar aplicaciones faciles de
mantener, lo cual justificarıa el desarrollo del proyecto.
Con el fin de cuantificar las mejoras obtenidas al utilizar la librerıa desarrollada,
se procedio a refactorizar un caso de estudio, el cual fue seleccionado bajo un
conjunto de metricas de seleccion. Una vez seleccionado el caso de estudio, se
procedio a evaluar la complejidad ciclomatica de la librerıa antes y despues de la
refactorizacion. Los resultados obtenidos indicaron la reduccion de la complejidad
ciclomatica en un 50 %.
2
CAPITULO 1. MARCO TEORICO
1.1 DEFINICION DEL PARADIGMA DE PROGRAMACION FUNCIO-
NAL
La programacion funcional inicia con LISP, sin embargo el nombre de paradigma no
fue introducido sino hasta 1.977 por John Backus en su paper ganador del Premio
Turing llamado Can Programming Be Liberated From the von Neumann Style? A
Functional Style and Its Algebra of Programs [5]. Backus menciona multiples pun-
tos de vista acerca de construir aplicaciones como combinaciones de ecuaciones
algebraicas.
En la programacion funcional los programas son ejecutados mediante la evaluacion
de expresiones, en contraste con la programacion imperativa en donde los progra-
mas estan compuestos de instrucciones que cambian el estado global cuando se
ejecutan. Tıpicamente, la programacion funcional evita utilizar estados mutables [7].
1.1.1 CARACTERISTICAS GENERALES
A continuacion un listado de algunas de las caracterısticas principales de la progra-
macion funcional:
3
4
Funciones de Orden Superior
Son funciones que toman como argumentos a otras funciones. Las funciones de or-
den superior son utiles para refactorizar codigo y reducir el numero de repeticiones
dentro del codigo [33].
1 > map (+1) [ 1 , 2 , 3 ]
2 [2 , 3 , 4 ]
Fragmento de Codigo 1.1: Ejemplo de Funcion de Orden Superior
En el fragmento de codigo 1.1 anterior la funcion map toma como argumento a la
funcion (+1), la cual es aplicada a cada uno de los elementos de la lista [1, 2, 3]
obteniendo como resultado [2, 3, 4].
Puridad
Algunos lenguajes de programacion permiten expresiones que lanzan acciones adi-
cionalmente a retornar valores, este tipo de acciones se lo conoce como efectos
secundarios. Los lenguajes que prohıben los efectos secundarios son conocidos
como lenguajes puros [18].
A continuacion dos fragmentos de codigo 1.2 y 1.3, los cuales retornan el mismo
resultado, sin embargo uno de ellos tiene un efecto secundario:
1 sum : : I n t −> I n t −> I n t
2 sum x y = x + y
Fragmento de Codigo 1.2: Ejemplo de Funcion Pura
5
1 public i n t sum( i n t x , i n t y ) {
2 System . out . p r i n t l n ( ” Running . . . ” ) ;
3 return x + y ;
4 }
Fragmento de Codigo 1.3: Ejemplo de Funcion Impura
Como se puede observar en el fragmento de codigo 1.3, la funcion sum no solo
retorna el resultado de la suma; en la lınea de codigo 2 se imprime un mensaje
de texto en la pantalla, lo cual es considerado un efecto secundario debido a que
cambia el estado inicial de la pantalla, a diferencia del fragmento de codigo 1.2 en
donde solo se retorna el resultado de la suma.
Datos Inmutables
Un dato inmutable por definicion es aquel que no puede ser modificado, en la pro-
gramacion funcional al trabajar con valores inmutables cada modificacion crea una
copia del valor original dejando intacto el valor original [14].
A continuacion dos fragmentos de codigo 1.4 y 1.5, en los cuales se puede apreciar
la diferencia entre eliminar un elemento de una lista inmutable en Haskell y una
mutable en Java:
1 > l e t xs = [1 , 2 , 3 ]
2 [1 , 2 , 3 ]
3 > delete 1 xs
4 [2 , 3 ]
5 > xs
6 [1 , 2 , 3 ]
Fragmento de Codigo 1.4: Ejemplo de Datos Inmutables
6
1 > L i s t <In teger> xs = [1 , 2 , 3 ] ;
2 [ 1 , 2 , 3 ]
3 > xs . remove ( 1 ) ;
4 [2 , 3 ]
5 > xs ;
6 [2 , 3 ]
Fragmento de Codigo 1.5: Ejemplo de Datos Mutables
Como se puede observar en el fragmento de codigo 1.5, la lista original definida en
la lınea de codigo 1, despues de eliminar el elemento 1 ha sido modificada, esto se
puede evidenciar en la lınea de codigo 7.
Referencia Transparencial
Las operaciones puras siempre retornan el mismo resultado cada vez que son in-
vocadas, a esta propiedad se la conoce como referencia transparencial [20].
A continuacion dos fragmentos codigo 1.6 y 1.7 en donde se puede observar la di-
ferencia entre una funcion con referencia transparencial y una sin referencia trans-
parencial:
1 > 1 + 2
2 3
3 > 1 + 2
4 3
Fragmento de Codigo 1.6: Ejemplo de Referencia Transparencial
7
1 > System . c u r r e n t T i m e M i l l i s ( ) ;
2 1375025861
3 > System . c u r r e n t T i m e M i l l i s ( ) ;
4 1375025862
Fragmento de Codigo 1.7: Ejemplo Contrario de Referencia Transparencial
Como se puede observar en el fragmento de codigo 1.7, la funcion currentTimeMillis
siempre retorna un resultado diferente, esto se considera una violacion al principio
de referencia transparencial.
1.1.2 LENGUAJE DE PROGRAMACION HASKELL
Haskell es un avanzado lenguaje de programacion puramente funcional. Un pro-
ducto vanguardista Open-Source con mas de 20 anos de investigacion, permite un
desarrollo de software rapido robusto, conciso, y correcto. Posee un alto soporte
de integracion con otros lenguajes, construido con concurrencia y paralelismo, de-
buggers, perfiles, grandes librerıas y una comunidad muy activa. Haskell permite
facilmente producir software flexible, mantenible y de alta calidad [21].
Caracterısticas Principales
La tabla 1.1 a continuacion lista las principales caracterısticas del lenguaje de pro-
gramacion Haskell:
Caracterıstica Descripcion
Tipado Estatico Cuando se compila un programa, el compilador cono-
ce que parte del codigo es un numero, cual es una ca-
dena de texto y ası sucesivamente. Esto significa que
muchos posibles errores son capturados al momento
de compilacion.
8
Caracterıstica Descripcion
Evaluacion Perezosa Significa que al menos que no se indique explıcita-
mente, Haskell no ejecutara funciones y calculara va-
lores hasta que sea forzado a mostrar un resultado.
Tabla 1.1: Caracterısticas Principales de Haskell
1.2 DEFINICION DEL PARADIGMA DE PROGRAMACION ORIEN-
TADO A OBJETOS
El paradigma orientado a objetos no es solo un estilo de programacion, tambien es
un metodo de diseno para la construccion de sistemas.
Los lenguajes orientados a objetos permiten al programador especificar unidades
autonomas en forma de objetos, los cuales son construidos de datos y los metodos
u operaciones que pueden ser ejecutados sobre el objeto.
En la programacion orientada a objetos un objeto contiene datos y provee operacio-
nes (o metodos) para acceder a los datos. Los datos en un objeto no son visibles
directamente, solo a traves de operaciones. En otras palabras las operaciones son
la interfaz de un objeto para los usuarios del objeto.
1.2.1 CARACTERISTICAS GENERALES
A continuacion una breve recopilacion, sobre las principales caracterısticas de la
programacion orientado a objetos encontrados en la mayorıa de lenguajes de pro-
gramacion pertenecientes a este paradigma:
9
Encapsulamiento
Procedimiento utilizado para ocultar detalles de implementacion de una clase hacia
el exterior, tambien es utilizado para restringir el acceso de otras clases a ciertos
atributos y metodos definidos [22].
A continuacion un fragmento de codigo 1.8 en donde la clase User solo expone
metodos de lectura:
1 public class User {
2 private S t r i n g f i rs tName ;
3 private S t r i n g lastName ;
4
5 public User ( S t r i n g f i rstName , S t r i n g lastName ) {
6 th is . f i rs tName = f i rs tName ;
7 th is . lastName = lastName ;
8 }
9
10 public S t r i n g getFirstName ( ) {
11 return f i rs tName ;
12 }
13
14 public S t r i n g getLastName ( ) {
15 return lastName ;
16 }
17 }
Fragmento de Codigo 1.8: Ejemplo de Encapsulamiento
Como se puede observar en el fragmento de codigo 1.8, la clase User solo expone
metodos a otras clases para poder acceder a sus atributos firstName y lastName,
impidiendo que estos atributos sean modificados desde fuera de la clase.
10
Herencia
La herencia de clases puede es utilizada para reutilizar atributos y metodos defini-
dos en una clase padre, por lo general cuando se tiene una relacion del tipo is-a es
una buena opcion usar herencia de clases [22].
1 public class Bicyc le { . . . }
2
3 public class MountainBike extends Bicyc le { . . . }
Fragmento de Codigo 1.9: Ejemplo de Herencia
Como se puede observar en el fragmento de codigo 1.9, la clase MountainBike
es una especializacion de la clase Bicycle, por lo tanto se utiliza herencia para
representar esta relacion.
Polimorfismo
Dos clases se consideran polimorficas, si por lo menos unos de sus metodos define
la misma interfaz, es decir tanto el nombre del metodo como los tipos de datos
recibidos como argumentos y el tipo de dato de retorno son los mismos [22].
El polimorfismo es utilizado para definir metodos los cuales se comporten diferente
dependiendo el contexto de ejecucion. A continuacion un fragmento de codigo 1.10:
11
1 public inter face Shape {
2 void draw ( ) ;
3 }
4
5 public class C i r c l e implements Shape {
6 public void draw ( ) { . . . }
7 }
8
9 public class Square implements Shape {
10 public void draw ( ) { . . . }
11 }
Fragmento de Codigo 1.10: Ejemplo de Polimorfismo
Como se puede observar en el fragmento de codigo 1.10, las clases Circle y Square
pueden ser dibujadas mediante la implementacion del metodo draw, sin embargo
cada una de las clases sera dibujado de manera diferente dependiendo la figura a
la cual representan.
Composicion
La composicion de clases, consiste en construir una clase compleja a partir de
pequenas clases, con el fin de poder separar responsabilidades en diferentes cla-
ses [22].
A continuacion un fragmento de codigo 1.11 de ejemplo:
12
1 public class Engine { . . . }
2
3 public class Car {
4 private Engine engine ;
5
6 public Car ( Engine engine ) {
7 th is . engine = engine ;
8 }
9 }
Fragmento de Codigo 1.11: Ejemplo de Composicion
Como se puede observar en el fragmento de codigo 1.11, la clase Car se encuen-
tra compuesta de un atributo engine del tipo Engine, es decir la clase Car conoce
sobre la existencia de un motor, sin embargo no conoce sobre los detalles de su
implementacion.
1.2.2 LENGUAJE DE PROGRAMACION JAVA
Es un lenguaje orientado a objetos multiproposito utilizado para el desarrollo de
diversas aplicaciones, desde aplicaciones de escritorio hasta aplicaciones movi-
les [32].
Caracterısticas Generales
La tabla 1.2 a continuacion lista las caracterısticas mas destacadas encontradas
dentro del lenguaje de programacion Java:
13
Caracterıstica Descripcion
Independencia de Plataforma Java provee un middleware de software, el cual permi-
te que el codigo escrito en este lenguaje sea portable
a traves de diferentes infraestructuras de hardware.
Portabilidad El bytecode generado por el compilador de Java pue-
de ser importado a cualquier plataforma.
Multihilos En Java se pueden escribir programas que manejen
multiples tareas al mismo tiempo definiendo varios hi-
los. La principal ventaja de utilizar multiples hilos es
que la memoria es compartida.
Distribuido Las tecnologıas de Java Remote Method Invocation
(RMI) y Enterprise Java Beans (EJB) son utilizados
para la creacion de aplicaciones distribuidas, permi-
tiendo acceder archivos llamando a metodos de otra
maquina a traves de la red.
Tabla 1.2: Caracterısticas de Java
1.3 COMPARACION ENTRE PARADIGMAS FUNCIONAL Y ORIEN-
TADO A OBJETOS
Una vez descritas tanto las caracterısticas del paradigma funcional en la seccion 1.1,
como las caracterısticas del paradigma orientado a objectos en la seccion 1.2, se
procedera a realizar un analisis comparativo de dichos paradigmas al igual que sus
lenguajes Haskell y Java respectivamente.
1.3.1 COMPARACION ENTRE PARADIGMAS
La tabla 1.3 a continuacion realiza un analisis comparativo entre los diferentes pa-
radigmas de programacion expuestos anteriormente en las secciones 1.1 y 1.2:
14
Caracterıstica FP OOP Analisis Comparativo
Funciones de
Orden Superior
Sı cumple No cumple No todos los lenguajes orientados a obje-
tos soportan esta caracterıstica, solo aque-
llos que incluyen funciones de primer or-
den.
Puridad Sı cumple No cumple En los lenguajes orientados a objetos no
existe ninguna restriccion referente a tener
efectos secundarios.
Datos Inmuta-
bles
Sı cumple No cumple La programacion orientada a objetos se ba-
sa en el cambio de estado de un objeto por
lo cual al menos que los datos sean defi-
nidos explıcitamente como inmutables esta
caracterıstica no esta disponible.
Referencia
Transparencial
Sı cumple No cumple Una misma funcion pura retorna siempre
un mismo valor, sin embargo en lenguajes
orientados a objetos debido a los efectos
secundarios una funcion puede verse in-
fluenciada por efectos externos que cam-
bien su resultado.
Encapsulamiento Sı cumple Sı cumple En lenguajes funcionales se puede realizar
tanto encapsulamiento de funciones como
de estructura de datos, mientras que en los
lenguajes orientados a objetos se pueden
realizar a nivel de clase, metodos y atribu-
tos.
Herencia No cumple Sı cumple En los lenguajes funcionales no existe he-
rencia de objetos ya que se trabaja con es-
tructuras de datos.
15
Caracterıstica FP OOP Analisis Comparativo
Polimorfismo Sı cumple Sı cumple En lenguajes orientados a objetos existe
polimorfismo a nivel de clases, mientras
que en lenguajes funcionales existen poli-
morfismos de estructuras de datos.
Composicion Sı cumple Sı cumple En los lenguajes funcionales no solo se
puede componer estructuras de datos,
tambien es posible realizar composicion de
funciones.
Tabla 1.3: Comparacion entre Paradigmas
1.3.2 COMPARACION ENTRE LENGUAJES
Una vez realizada la comparacion entre los paradigmas de programacion Functional
Programming (FP) (1.1) y Object Oriented Programming (OOP) (1.2), se procedera
a realizar la comparacion entre los lenguajes de programacion Haskell (1.1.2) y Java
(1.2.2):
16
Caracterıstica Haskell Java Analisis Comparativo
Puramente
Funcional
Sı cumple No cumple Haskell es un lenguaje puramente funcio-
nal, es decir el desarrollador mediante pro-
gramacion declarativa indica al computador
como realizar una accion en lugar de escri-
bir instrucciones secuenciales. En Java los
programas deben describir detalladamente
los pasos que el computador debe realizar
para cumplir el objetivo.
Tipado Estatico Sı cumple Sı cumple Ambos lenguajes son fuertemente tipados,
el compilador analiza el codigo fuente com-
probando que los tipos definidos sean co-
rrectos, ademas no existe colision de tipos,
es decir, la conversion de un tipo de dato a
otro debe ser explıcita.
Evaluacion Pe-
rezosa
Sı cumple No cumple En Java cualquier expresion es evaluada
explıcitamente, es decir si se tiene una lista
de 20 elementos y se desea imprimir los 10
primeros elementos, Java necesita evaluar
la lista completa primero, antes de imprimir
los deseados. En Haskell esto no sucede
solo se evaluaran los 10 primeros elemen-
tos a ser impresos.
Independencia
de Plataforma
Sı cumple Sı cumple Tanto Haskell como Java son independien-
tes de plataforma.
17
Caracterıstica Haskell Java Analisis Comparativo
Multihilos Sı cumple Sı cumple Los dos lenguajes soportan procesamiento
multihilos.
Distribuidos Sı cumple Sı cumple Ambos lenguajes son de proposito general
y funcionan en ambientes distribuidos.
Tabla 1.4: Comparacion entre Lenguajes
1.3.3 ANALISIS DE RESULTADOS
Una vez realizada la comparacion entre paradigmas y lenguajes de programacion
en las secciones 1.3.1 y 1.3.2, se procedera con el analisis de los resultados obte-
nidos:
La inmutabilidad de datos provista por defecto en lenguajes funcionales como
Haskell, permite construir aplicaciones concurrentes de manera natural sin
considerar la concurrencia de datos como parte del diseno ya que no existen
cambios de estado.
La evaluacion perezosa de expresiones permite gestionar los recursos de una
manera efectiva, ya que cualquier evaluacion se realiza bajo demanda mejo-
rando la velocidad de ejecucion y disminuyendo el consumo de recursos.
Tanto la puridad como la referencia transparencial explıcita definida en lengua-
jes como Haskell, permite tener una clara separacion entre funciones puras y
aquellas con efectos secundarios, esto mejora tanto la lectura como la escri-
tura de pruebas.
18
1.4 ESTILO DE PROGRAMACION FUNCIONAL SOBRE UN LEN-
GUAJE ORIENTADO A OBJETOS
En la actualidad existen varios lenguajes de programacion los cuales incluyen ca-
racterısticas de la programacion funcional, la tabla 1.5 a continuacion lista algunos
de estos lenguajes y sus caracterısticas:
Lenguaje Caracterısticas
Ruby Las listas en Ruby proveen funciones de orden su-
perior para la transformacion de listas como map y
reduce.
JavaScript En JavaScript las funciones son objetos de primer or-
den, es decir una funcion puede ser asignada a una
variable, o utilizada como argumentos de otra funcion.
Java (version 8 en adelante) Incluye funciones de orden superior y metodos para
transformar colecciones de una manera funcional, co-
mo por ejemplo map y reduce.
C# / Visual Basic (LINQ [29]) Es un lenguaje integrado de consulta, incluye carac-
terısticas para la consulta de listas y se extiende a
bases de datos.
Tabla 1.5: Estilos de Programacion Funcional en OOP
1.4.1 PATRONES DE DISENO FUNCIONALES
A pesar que el paradigma funcional es diferente del orientado a objetos, es posible
programar en lenguajes orientados a objetos utilizando un estilo de programacion
funcional. Los patrones de diseno a continuacion han sido tomados del libro Beco-
ming Functional [4].
19
Encapsulamiento Estatico
Con el fin de explicar de una manera practica el patron de diseno, se utilizara el
siguiente fragmento de codigo 1.12:
1 public class Contact {
2 private S t r i n g f i rs tName ;
3 private S t r i n g lastName ;
4 private S t r i n g emai l ;
5
6 public void sendEmail ( ) {
7 sendEmail ( ” To : ” + emai l + ” \nSubject : My Subject \
nBody : . . . ” ) ;
8 }
9
10 private void sendEmail ( S t r i n g content ) { . . . }
11 }
Fragmento de Codigo 1.12: Ejemplo de Encapsulamiento Estatico
Como se puede observar en el fragmento de codigo 1.12, la clase Contact posee
las siguientes responsabilidades:
Contiene los datos referentes al usuario.
Es encargado de enviar correos electronicos al usuario.
A simple vista parece no existir ninguna violacion al principio de responsabilidad
simple ya que ambas responsabilidades estan relacionadas al usuario, sin embargo
la manera en la cual se envıe un correo electronico debe ser transparente a la clase
Contact.
20
La clase Contact necesita enviar un correo electronico sin conocer sobre detalles
de su implementacion; es por ello que toda logica relacionada a enviar un correo
electronico sera extraıda a otra clase.
El fragmento de codigo 1.13, a continuacion emplea la tecnica de encapsulamiento
estatico para extraer toda la logica referente a enviar un correo electronico a la clase
Email:
1 public class Email {
2 private S t r i n g address ;
3 private S t r i n g sub jec t ;
4 private S t r i n g body ;
5
6 public s t a t i c void send ( Email emai l ) {
7 . . .
8 }
9 }
Fragmento de Codigo 1.13: Extraccion de Codigo (Encapsulamiento Estatico)
Una vez encapsulada la logica relacionada a enviar correos electronicos en la clase
Email, se puede proceder a refactorizar la clase Contact de la siguiente manera:
21
1 public class Contact {
2 private S t r i n g f i rs tName ;
3 private S t r i n g lastName ;
4 private S t r i n g emai l ;
5
6 public void sendEmail ( ) {
7 Email . send (new Email ( email , ”My Subject ” , ”My Body ” ) )
;
8 }
9 }
Fragmento de Codigo 1.14: Refactorizacion utilizando Encapsulamiento Estatico
Como se puede observar en el fragmento de codigo 1.14 la clase Contact des-
conoce sobre los detalles de la implementacion relacionados a enviar un correo
electronico, ya que toda esta responsabilidad ha sido delegada a la clase Email.
Objeto como Contenedor
Este patron de diseno es utilizado para encapsular el comportamiento de una fun-
cion dentro de atributos de una clase, permitiendo ası modificar el comportamiento
de la funcion [4].
Tomando como referencia la clase Email definida anteriormente 1.13, se puede
modificar el comportamiento del metodo send agregando un nuevo atributo a la
clase Email como se muestra en el fragmento de codigo 1.15 a continuacion:
22
1 public class Email {
2 private boolean dearReader ;
3
4 public s t a t i c void send ( Email emai l ) {
5 i f ( emai l . isDearReader ( ) ) {
6 sendDearEmail ( emai l ) ;
7 } else {
8 sendEmail ( emai l ) ;
9 }
10 }
11
12 private s t a t i c void sendDearEmail ( Email emai l ) { . . . }
13
14 private s t a t i c void sendEmail ( Email emai l ) { . . . }
15 }
Fragmento de Codigo 1.15: Ejemplo de Objeto como Contenedor
Como se puede observar en el fragmento de codigo 1.15 todos los atributos rela-
cionados a enviar un correo electronico han sido encapsulados dentro de la clase
Email.
Codigo como Datos
Uno de los puntos claves dentro de la programacion funcional es tratar a las fun-
ciones como datos, es decir una funcion puede ser asignada a una variable o ser
pasada como argumento a otra funcion, esta caracterıstica permite reutilizar codigo
a un nivel granular [4].
Tomando como punto de partida el siguiente fragmento de codigo 1.16:
23
1 public class CommandLineOption {
2 private S t r i n g d e s c r i p t i o n ;
3 private Runnable f u n c t i o n ;
4 }
Fragmento de Codigo 1.16: Ejemplo de Codigo como Datos
Como se puede observar en el fragmento de codigo 1.16, la clase CommandLineOption
tiene como atributos description el cual describe la opcion de la lınea de comando,
y atributo function el cual representa la accion realizada por la opcion de la lınea de
comandos.
Utilizando la clase CommandLineOption definida anteriormente se puede construir
una lınea de comandos de la siguiente manera:
1 public class CommandLine {
2 public Map<St r ing , CommandLineOption> opt ions ( ) {
3 Map<St r ing , CommandLineOption> opt ions = new HashMap
<>() ;
4 op t ions . put ( ” c ” , createUser ( ) ) ;
5 op t ions . put ( ” d ” , deleteUser ( ) ) ;
6 return opt ions ;
7 }
8
9 private CommandLineOption createUser ( ) { . . . }
10 private CommandLineOption deleteUser ( ) { . . . }
11 }
Fragmento de Codigo 1.17: Ejemplo de Lınea de Comandos
Como se puede observar en fragmento de codigo 1.17, se crea una instancia de la
clase CommandLineOption para representar cada una de las acciones disponibles
24
en la lınea de comandos.
1.4.2 ESTADO DEL ARTE
La presente seccion es una breve recopilacion sobre el estado actual de la progra-
macion funcional en diversos campos:
Universidad
Empresa
Al igual que un listado de lenguajes y librerıas funcionales, utilizados en la actuali-
dad.
Universidad
Durante las ultimos anos, las universidades han ido incorporando en su pensum de
estudios cursos referentes a la programacion funcional.
A continuacion un listado de algunos de los cursos de programacion funcional, dic-
tados alrededor del mundo:
Paıs Reino Unido
Universidad Universidad de Edinburgh
Instructor Philip Wadler
Curso Informatics 1 - Functional Programming
Ano 2015
Figura 1.1: Curso Universidad de Edinburgh
Fuente: http://www.inf.ed.ac.uk/teaching/courses/inf1/fp
25
Paıs Estado Unidos
Universidad Universidad de Nottingham
Instructor Neil Ghani
Curso Functional Programming
Ano 2015
Figura 1.2: Curso Universidad de Nottingham
Fuente: http://www.cs.nott.ac.uk/ gmh/afp.html
Paıs Reino Unido
Universidad Universidad de Oxford
Instructor Jonathan Hill
Curso Functional Programming for the Integrated Graduate Development Pro-
gramme in Software Engineering at Oxford University
Ano 2015
Figura 1.3: Curso Universidad de Oxford
Fuente: http://www.comlab.ox.ac.uk/igdp/text/course06.html
26
Paıs Argentina
Universidad Universidad Tecnologica Nacional
Instructor Estudiantes
Curso Paradigmas de Programacion
Ano 2015
Figura 1.4: Curso Universidad Tecnologica Nacional
Fuente: http://www.pdep.com.ar
Paıs Colombia
Universidad Universidad de los Andes
Instructor Jorge Ricardo Cuellar
Curso Programacion Funcional y sus Aplicaciones
Ano 2015
Figura 1.5: Curso Universidad de los Andes
Fuente: http://matematicas.uniandes.edu.co/eventos/2015/haskell
27
Paıs Estados Unidos
Universidad Universidad de Oklahoma
Instructor Rex Page
Curso Introduction to Computer Programming
Ano 1997
Figura 1.6: Curso Universidad de Oklahoma
Fuente: http://www.cs.ou.edu/ rlpage/fpclassSpring97
Empresa
Empresas alrededor del mundo como Facebook y Apple, han empezado a utilizar
lenguajes funcionales tanto para el desarrollo de nuevos productos, como para la
creacion de herramientas de desarrollo.
Empresa Facebook
Proyecto Haxl
Descripcion Es una librerıa que simplifica el acceso remoto a datos. Entre las
principales caracterısticas se encuentran: batch de multiples peticiones a
una misma fuente de datos, solicitar datos de multiples fuentes de datos
de manera concurrente y cache de solicitudes anteriores.
Ano 2014
Figura 1.7: Haxl
Fuente: https://code.facebook.com/projects/854888367872565/haxl
28
Empresa Apple
Proyecto Swift
Descripcion Es un lenguaje de programacion desarrollado por Apple, a pesar
de no ser puramente funcional como Haskell, posee algunos conceptos de
la programacion funcional como son: funciones de orden, funciones como
ciudadanos de primer orden y funciones anonimas.
Ano 2015
Figura 1.8: Swift
Fuente: https://developer.apple.com/swift
Empresa Microsoft
Proyecto F#
Descripcion Es un lenguaje de programacion desarrollado por Microsoft como
parte de .NET framework, entre las principales caracterısticas se encuen-
tran: inmutabilidad de datos, aplicacion parcial de funciones, expresiones
de objetos, entre otros.
Ano 2005
Figura 1.9: F#
Fuente: http://fsharp.org
29
Empresa Intel
Proyecto Compilador de Haskell
Descripcion Intel ha desarrollado un compilador en Haskell, como parte de su
investigacion en paralelismo multinucleo a escala.
Ano 2013
Figura 1.10: Intel
Fuente: http://www.leafpetersen.com/leaf/publications/hs2013/hrc-paper.pdf
Empresa Whatsapp
Proyecto Servicio de Mensajerıa
Descripcion Whatsapp tiene un promedio de 8 billones de mensajes entrantes
y 12 billones de mensajes de salida por dıa, esto es posible gracias al uso
de Erlang y FreeBSD.
Ano 2013
Figura 1.11: Whatsapp
Fuente: https://www.erlang-solutions.com/about/news/erlang-powered-whatsapp-
exceeds-200-million-monthly-users
30
Empresa SumAll
Proyecto Procesamiento de Datos
Descripcion Agrega varios flujos de datos de redes sociales. Se encuentran el
proceso de reescribir su backend en Haskell. Lo que nos atrajo sobre el
lenguaje es la disciplina y su aproximacion para resolver problemas difıci-
les y complejos de manejar.
Ano 2014
Figura 1.12: SumAll
Fuente: https://sumall.com
Lenguajes de Programacion
La presente seccion contiene un listado de lenguajes de programacion funcionales,
utilizados tanto en la academia como en la construccion de aplicaciones.
Rust
Rust es un lenguaje de programacion de sistemas rapido el cual garantiza segu-
ridad en la memoria y ofrece concurrencia sin complicaciones (sin condiciones de
carrera). No utiliza un recolector de basura y tiene un costo mınimo en tiempo de
ejecucion [37].
Caracterısticas Descripcion
Hilos sin Condiciones de Carrera La caracterıstica de seguridad de memoria
de Rust se aplica a la historia de concu-
rrencia. Los programas en Rust deben ser
seguros de memoria, y no tener condicio-
nes de carrera, el sistema de tipos de Rust
se encuentra listo para esta tarea.
31
Caracterısticas Descripcion
Genericos Basados en Traits Un trait es una caracterıstica del lenguaje
la cual notifica al compilador de Rust que
el tipo debe ser provisto, por el contexto en
donde se ejecute la funcion.
Busqueda de Patrones Al igual que otros lenguajes funcionales,
Rust posee la capacidad de comprobar si
una determinada secuencia de datos coin-
cide con algun patron definido.
Inferencia de Tipos Rust posee la capacidad de deducir au-
tomaticamente el tipo de un dato a partir
de una expresion.
32
Caracterısticas Descripcion
Bindings Eficientes en C Los Foreign Function Interface (FFI) flexi-
bles de Rust proveen bindings de C eficien-
tes los cuales permiten exponer e invocar
codigo de Rust sin ningun costo extra. Esto
permite reescribir una aplicacion modulo a
modulo, una transicion paulatina hacia una
mejor experiencia de desarrollo.
Tabla 1.6: Caracterısticas de Rust
A continuacion un ejemplo de codigo 1.18 escrito en Rust tomado de la pagina
oficial [37]:
1 for token i n program . chars ( ) {
2 match token {
3 ’+ ’ => accumulator += 1 ,
4 ’− ’ => accumulator −= 1 ,
5 ’ ∗ ’ => accumulator ∗= 2 ,
6 ’ / ’ => accumulator /= 2 ,
7 => { /∗ i gnore every th ing e lse ∗ / }
8 }
9 }
Fragmento de Codigo 1.18: Ejemplo de Rust
Clojure
Clojure es un dialecto de Lisp, comparte con Lisp la filosofıa de codigo como datos y
un sistema poderoso de macros. Clojure es un lenguaje de programacion funcional
predominante, y cuenta con basto conjunto de estructuras de datos persistentes
inmutables. Cuando datos mutables son necesitados, Clojure ofrece un sistema de
33
software transaccional y un agente de sistema reactivo el cual asegura disenos
multihilos limpios y correctos [10].
Caracterıstica Descripcion
Desarrollo Dinamico Clojure es dinamico, lo cual significa que
solo ejecuta codigo compilado, tambien
permite la interaccion con el lenguaje a par-
tir de su REPL. Dicha interaccion, permite
evaluar codigo y variables de una manera
rapida.
Programacion Funcional Clojure es un lenguaje de programacion
funcional. Este provee herramientas para
impedir la mutacion de estado, provee fun-
ciones como objetos de primera clase, y
enfatiza la recursion iterativa en lugar de
bucles con efectos secundarios.
Lisp Clojure es un miembro de la familia de Lisp,
sin embargo Clojure extiende el enfoque de
codigo como datos mucho mas alla de las
listas entre parentesis expresiones-s, hasta
vectores y mapas. Estos vectores y mapas
pueden ser utilizados en el sistema de ma-
cros.
34
Caracterıstica Descripcion
Polimorfismo en tiempo de Ejecucion Los sistemas que utilizan polimorfismo en
tiempo de ejecucion son faciles de cambiar
y de extender. Clojure soporta polimorfis-
mo de muchas maneras diferentes:
Muchas de las estructuras de datos
principales en tiempo de ejecucion de
Clojure, son definidas mediante inter-
faces de Java.
Clojure soporta la generacion de im-
plementaciones de interfaces en Java
utilizando proxies proxy.
El lenguaje Clojure soporta polimor-
fismo tanto a lo largo de clases como
de herencia con multiples metodos.
El lenguaje Clojure tambien soporta
un polimorfismo mas rapido mediante
el uso de protocolos (sin embargo se
encuentra limitado solo a polimorfis-
mo a nivel de clases para tomar ven-
taja de las capacidades existentes en
la JVM).
Programacion Concurrente Clojure, es un lenguaje practico, permite
cambiar el estado sin embargo provee me-
canismos para asegurar la consistencia,
mientras elimina la responsabilidad a los
desarrolladores de lidiar manualmente con
bloqueos y resolver conflictos.
35
Caracterıstica Descripcion
Funciona sobre la JVM Clojure esta disenado para ser un lenguaje
anfitrion, compartiendo el sistema de tipos
de la JVM. Compila todas las funciones a
bytecode de la JVM.
Tabla 1.7: Caracterısticas de Clojure
A continuacion un ejemplo de codigo 1.19 escrito en Clojure tomado de GitHub [27]:
1 ( use ’ korma . db )
2
3 ( s e l e c t users
4 ( where ( or (= : username ” c h r i s ” )
5 (= : emai l ” chr is@chr is . com ” ) ) ) )
Fragmento de Codigo 1.19: Ejemplo de Clojure
Elixir
Elixir es un lenguaje de programacion funcional dinamico, disenado para la cons-
truccion de aplicaciones escalables y mantenibles [11].
Caracterıstica Descripcion
Escalabilidad Todo codigo se ejecuta sobre un pequeno hilo de pro-
ceso, el cual es aislado e intercambia informacion me-
diante mensajes.
Tolerancia a Fallos Elixir provee supervisores, los cuales describen como
reiniciar un parte del sistema cuando algun error se
presenta.
Programacion Funcional Promueve un estilo de programacion que ayuda al
desarrollador a escribir codigo pequeno, rapido y
mantenible.
36
Caracterıstica Descripcion
Ecosistema Creciente Elixir esta construido con un gran conjunto de herra-
mientas para su facil desarrollo. Mix es una herra-
mienta la cual facilita la creacion de proyectos, manejo
de tareas, ejecutar pruebas y mas.
Desarrollo Interactivo Herramientas como IEx (shell interactivo de Elixir) per-
miten interactuar con el lenguaje de manera practica,
mediante herramientas como auto-completar, debug-
ging, recarga de codigo.
Compatible con Erlang Elixir se ejecuta sobre la maquina virtual de Erlang, lo
cual permite ejecutar funciones Erlang directamente.
Tabla 1.8: Caracterıstica de Elixir
A continuacion un ejemplo de codigo 1.20 escrito en Elixir tomado de la pagina
oficial [11]:
37
1 def sum( a , b ) when i s i n t e g e r ( a ) and i s i n t e g e r ( b ) do
2 a + b
3 end
4
5 def sum( a , b ) when i s l i s t ( a ) and i s l i s t ( b ) do
6 a ++ b
7 end
8
9 def sum( a , b ) when i s b i n a r y ( a ) and i s b i n a r y ( b ) do
10 a <> b
11 end
12
13 sum 1 , 2
14 #=> 3
15
16 sum [ 1 ] , [ 2 ]
17 #=> [ 1 , 2 ]
18
19 sum ” a ” , ” b ”
20 #=> ” ab ”
Fragmento de Codigo 1.20: Ejemplo de Elixir
Scala
Scala es un lenguaje de programacion multiparadigma, disenado para expresar pa-
trones comunes de una manera concisa, elegante y con seguridad de tipos. De una
manera facil integra caracterısticas de orientacion a objectos y lenguajes funciona-
les [38].
38
Caracterısticas Descripcion
Orientacion a Objetos Scala es un lenguaje puro orientado a objetos en el
sentido que cada valor es un objeto. Los tipos y el
comportamiento de los objetos son descritos por la
clases y traits Trait. Las clases extienden a traves de
subclases y una composicion flexible basada en mi-
xins Mixin.
Funcional Scala es un lenguaje funcional en el sentido que cada
funcion es un valor. Scala provee una sintaxis lige-
ra para la definicion de funciones anonimas, soporta
funciones de orden superior, permite que las funcio-
nes sean anidadas, y soporta Currying.
Tipado Estatico Scala se encuentra equipado con un sistema de tipos
expresivo el cual se encarga de garantizar que las
abstracciones sean utilizadas de una manera cohe-
rente. En particular el sistema de tipos soporta:
Clases genericas
Anotaciones de variantes
Lımites de tipos superior e inferior
Clases internas y tipos abstractos como miem-
bros de objetos
Tipos compuestos
Vistas
Metodos polimorficos
39
Caracterısticas Descripcion
Extensible En practica, el desarrollo de aplicaciones de dominio
especıfico por lo general requiere extensiones. Sca-
la provee una unica combinacion de mecanismos del
lenguaje la cual permite anadir nuevas caracterısticas
al lenguaje mediante librerıas.
Tabla 1.9: Caracterısticas de Scala
A continuacion un ejemplo de codigo 1.21 escrito en el lenguaje Scala [38]:
1 def max( x : I n t , y : I n t ) : I n t = {
2 return x > y ? x : y
3 }
4
5 max(1 , 2) / / => 2
Fragmento de Codigo 1.21: Ejemplo de Scala
Erlang
Erlang es un lenguaje de programacion utilizado para la construccion masiva de
software escalable el cual requiera de alta disponibilidad. Algunos de ellos se en-
cuentran en uso dentro de las telecomunicaciones, banca, comercio electronico, y
mensajerıa instantanea [12].
40
Caracterısticas Descripcion
Concurrencia Los procesos son bastante ligeros, con un
tamano de alrededor de 500 bytes por pro-
ceso. Esto significa que millones de pro-
cesos pueden ser creados, incluso con
computadoras antiguas.
Debido a que los procesos de Erlang son
completamente independientes de sistema
operativo, el programa se comportara de
igual manera en Linux, FreeBSD, Windows
y otros sistemas sobre los cuales corre Er-
lang.
Reemplazo de Codigo en Caliente En un sistema de tiempo real usualmente
no se quiere detener el sistema para reali-
zar una actualizacion de codigo. En algu-
nos sistemas de tiempo real nunca serıa
posible apagar el sistema para realizar una
actualizacion, este tipo de sistemas deben
ser disenados con codigo dinamico actuali-
zable. Un ejemplo de este tipo de sistemas
es el sistema de control X2000 desplegado
por la NASA.
Multiplataforma Erlang corre sobre Linux, FreeBSD, Win-
dows, Solaris, Mac OS X, e incluso sobre
plataformas embebidas como VxWorks.
41
Caracterısticas Descripcion
Soporte Un equipo dedicado de empleados de
Ericsson trabajan en Erlang. Soporte co-
mercial y servicios estan disponibles pa-
ra Erlang. Tambien existe una comunidad
bastante activa alrededor del mundo, cen-
trada alrededor de la lista de correo de
Erlang y su canal de Internet Relay Chat
(IRC).
Juega bien con el Mundo Exterior Provee integracion con Java, .NET, C, Pyt-
hon y Ruby. Existe una interfaz de acuerdo
al sistema operativo deseado.
HiPE El compilador de Erlang puede compilar a
codigo nativo de Windows, Linux o Mac OS
X y forma parte de la distribucion estandar
de Erlang.
Tipado Estatico, cuando sea necesario Se puede anotar el codigo con informacion
sobre tipos y utilizar Dialyzer, un podero-
so verificador de tipos, el cual asegura la
validez del codigo y mejora el rendimiento.
Dialyzer forma parte de Erlang, y soporta
tipado gradual el cual ofrece maxima flexi-
bilidad.
Tabla 1.10: Caracterısticas de Erlang
A continuacion un codigo de ejemplo 1.22 escrito en Erlang tomado de la pagina
oficial [12]:
42
1 connect ( Host , User , Password ) −>
2 { f t p s e r v e r , Host} ! {connect , s e l f ( ) , User , Password } ,
3 rece ive
4 { f t p s e r v e r , Reply} −> Reply ;
5 Other −> Other
6 a f t e r 10000 −> t imeout
7 end
Fragmento de Codigo 1.22: Ejemplo de Erlang
OCaml
El gestor de paquetes de OCaml (OPAM) soporta la instalacion de multiples com-
piladores, restricciones de paquetes flexibles, y un flujo de trabajo familiar con Git.
Los paquetes son automaticamente probados, cualquier notificacion es enviada a
los mantenedores [31].
Caracterısticas Descripcion
Sistema de Tipos Estatico OCaml provee un coleccion de reglas asignadas a un
tipo, las cuales permiten construir variables, expresio-
nes, funciones o modulos.
Inferencia de Tipos Es la capacidad del compilador de deducir un tipo de-
pendiendo del contexto sobre el cual se evalue.
Polimorfismo Parametrico OCaml no soporta la sobrecarga de funciones debido
a que es demasiado complicado tener inferencia de
tipos y sobrecarga de funciones al mismo tiempo. Sin
embargo OCaml soporta polimorfismo parametrico y
subtipos.
En OCaml, el polimorfismo parametrico esta introdu-
cido solo por el uso del constructor let, el cual es lla-
mado restriccion de valores.
43
Caracterısticas Descripcion
Funtores Los funtores son funciones de modulos a modulos,
pueden ser utilizadas para resolver una variedad de
problemas de estructura de codigo:
Inyeccion de dependencias.
Autoextension de modulos.
Instanciacion de modulos con estado.
Tabla 1.11: Caracterısticas de OCaml
A continuacion un ejemplo de codigo 1.23 escrito en el lenguaje OCaml [31]:
1 l e t rec f a c t x = i f x <= 1 then 1 else x ∗ f a c t ( x − 1) ; ;
2 f a c t 5 ; ; − : i n t = 120
Fragmento de Codigo 1.23: Ejemplo de OCaml
Librerıas de Programacion
La presente seccion es una breve recopilacion, sobre el estado actual de la progra-
macion funcional aplicada a lenguajes orientados a objetos.
functional.js - 2015
Es una librerıa funcional de JavaScript. Facilita la programacion por medio de Currying
y point-free, esta metodologıa ha sido utilizada desde los inicios de la construccion
de la librerıa [16].
44
Caracterıstica Descripcion
Currying fjs.curry permite facilita la creacion de funciones de
orden superior mediante la invocacion parcial de una
funcion existente, sin proveer todos los argumentos de
la funcion original.
Aridad La aridad de una funcion en JavaScript es el nume-
ro de argumentos esperados por una funcion. Con
fjs.curry es posible extender la aridad de una funcion
mas alla de su longitud esperada.
Expresiones Lambda fjs permite especificar expresiones lambda de manera
opcional, en lugar de las funciones de JavaScript para
cualquiera de sus funciones que permitan currying.
fjs.each fjs.each permite iterar sobre elementos de una colec-
cion, aplicando una funcion iterador a cada elemento.
Esto es muy similar a la funcion nativa forEach dispo-
nible en navegadores modernos, sin embargo facilita
la implemetacion de fjs.curry.
Tabla 1.12: Caracterısticas de functional.js
El ejemplo 1.24 a continuacion ha sido tomado de GitHub [16]:
1 var add = f j s . cu r ry ( f u n c t i o n ( arg1 , arg2 ) {
2 return arg1 + arg2 ;
3 } ) ;
4
5 var add3 = add ( 3 ) ;
6 add (1 , 2 , 3) ; / / => 6
7 add3 (1 , 2 , 3 , 4 , 5) ; / / => 18
Fragmento de Codigo 1.24: Ejemplo de functional.js
45
Javaslang - 2014
Javaslang es una librerıa funcional para Java 8 y versiones superiores. Javaslang
anade un API y algunas mejores practicas tomadas de lenguajes como Scala, para
tomar ventaja sobre las Lambdas en al programacion diaria [24].
Caracterıstica Descripcion
Nucleo Javaslang viene con una representacion de los tipos
basicos faltantes o son rudimentarios en Java.
Funciones La programacion funcional es sobre valores y trans-
formaciones de valores utilizando funciones.
Colecciones Con Javaslang se ha puesto mucho esfuerzo en el di-
seno de la librerıa de colecciones para Java, la cual
cumpla con los requerimientos de la programacion
funcional, como la inmutabilidad.
Tabla 1.13: Caracterısticas de Javaslang
El ejemplo de codigo 1.25 a continuacion, ha sido tomado de la pagina oficial de
Javaslang [24]:
1 f i n a l Tuple2<St r ing , In teger> java8 = Tuple . o f ( ” Java ” , 8)
;
2
3 f i n a l Tuple2<St r ing , In teger> guessWhat = java8 .map(
4 ( s , i ) −> Tuple . o f ( s + ” slang ” , i / 4)
5 ) ; / / => ( ” Javaslang ” , 2)
Fragmento de Codigo 1.25: Ejemplo de Javaslang
functional-ruby - 2013
La librerıa funcional-ruby se encuentra inspirada en algunos lenguajes de progra-
46
macion y herramientas como Erlang, Clojure y Functional Java.
Caracterıstica Descripcion
Especificacion de protocolo Especificacion de protocolos inspirada por
los protocolos de Clojure, el comporta-
miento de Erlang, y los protocolos de
Objective-C.
Sobrecarga de Funciones La sobrecarga de funciones con un estilo
de Erlang permite la busqueda de patro-
nes.
Threads Seguros Simple, seguridad de threads, estructuras
de datos inmutables, como son registros,
uniones, y tuplas, inspiradas por Clojure,
Erlang, y otros lenguajes funcionales.
Ejecucion Perezosa La ejecucion perezosa con una clase Delay
basada en Clojure delay.
Estructuras de Valor Estructuras de valor, simples, seguridad de
thread, una variacion inmutable de las es-
tructuras abiertas de Ruby.
Tabla 1.14: Caracterısticas de functional-ruby
El ejemplo de codigo 1.26 a continuacion ha sido tomado de GitHub [3]:
47
1 Name = Func t iona l : : Record .new ( : f i r s t , : middle , : l a s t , :
s u f f i x ) do
2 mandatory : f i r s t , : l a s t
3 defaul t : f i r s t , ’ J . ’
4 defaul t : l a s t , ’Doe ’
5 end
6
7 anon = Name.new
8 #=> #<record Name : f i r s t =>” J . ” , . . . >
9 matz = Name.new( f i r s t : ’ Yuk ih i ro ’ , l a s t : ’ Matsumoto ’ )
10 #=> #<record Name : f i r s t =>” Yuk ih i ro ” , . . . >
Fragmento de Codigo 1.26: Ejemplo de functional-ruby
functional-php - 2011
Es un conjunto de primitivos funcionales para PHP, principalmente inspirado por
Scala traversable collection, los arreglos en Dojo y Underscore.js [15].
Caracterıstica Descripcion
Arrays Trabaja con arrays y cualquier implementacion de Tra-
versable
Interfaz consistente Provee una interfaz consistente para funciones las
cuales toman colecciones y callback, el primer
parametro es siempre una coleccion, y el segundo el
callback. Los Callbacks siempre reciben los parame-
tros $value, $index, $collection.
Soporta Closures Es posible utilizar tanto callbacks como closures.
Espacio de Nombres Todas las funciones residen en un mismo espacio de
nombres ”Functional”para evitar cualquier tipo de con-
flictos con cualquier otra extension o librerıa.
Tabla 1.15: Caracterısticas de functional-php
48
El ejemplo de codigo 1.27 a continuacion ha sido tomado de GitHub [15]:
1 use f u n c t i o n Func t iona l \map;
2
3 map( range (0 , 100) , f u n c t i o n (\ $v ) { return \$v + 1 ;} ) ;
Fragmento de Codigo 1.27: Ejemplo de functional-php
Underscore.js - 2008
Underscore es una librerıa de JavaScript la cual provee un completo conjunto de
utilitarios funcionales sin la extension de cualquier objeto incorporado en el lengua-
je [39].
Caracterıstica Descripcion
Colecciones Underscore provee algunos metodos los cuales ope-
ran sobre colecciones.
Arreglos Underscore provee algunas funciones las cuales tra-
bajan exclusivamente sobre arerglos.
Objetos Underscore provee varios metodos para clonar obje-
tos, para extenderlos y manipular objetos.
Funciones Underscore provee funciones las cuales trabajan so-
bre funciones, este permite construir funciones de or-
den superior.
Tabla 1.16: Caracterısticas de Underscore.js
El ejemplo de codigo 1.28 a continuacion ha sido tomado de la pagina oficial:
49
1 .map( [ 1 , 2 , 3 ] , f u n c t i o n (num) { return num ∗ 3; } ) ;
2 / / => [ 3 , 6 , 9 ]
3
4 .map({one : 1 , two : 2 , th ree : 3} , f u n c t i o n (num, key ) {
5 return num ∗ 3;
6 } ) ;
7 / / => [ 3 , 6 , 9 ]
8
9 .map ( [ [ 1 , 2 ] , [ 3 , 4 ] ] , . f i r s t ) ;
10 / / => [ 1 , 3 ]
Fragmento de Codigo 1.28: Ejemplo de Underscore.js
CAPITULO 2. DESARROLLO DE LA LIBRERIA UTILI-
TARIA FUNCIONAL
Descripcion del Problema
La naturaleza del software es evolutiva, se debe ajustar a las necesidades definidas
por los usuarios. Dichos ajustes deben ser realizado con frecuencia, el esfuerzo
involucrado se encuentra directamente relacionado al diseno del software.
Un sistema altamente acoplado es difıcil de mantener, cualquier cambio realizado
causarıa una serie de modificaciones en cadena, incrementando la posibilidad de
introducir nuevos errores o defectos en el sistema.
Dentro de sistemas distribuidos, el manejo de la concurrencia resulta un desafıo. El
cambio constante de estado dentro de la programacion orientada a objetos, puede
causar algunas problemas dentro de la concurrencia como: deadlocks y condiciones
de carrera [34].
La mayorıa de lenguajes orientados a objetos como Java, poseen mecanismos para
el manejo de la concurrencia, sin embargo es el desarrollador quien es responsable
de emplear dichos mecanismos durante el desarrollo.
El presente proyecto se enfocara en dos problemas puntuales, la escalabilidad cau-
sada por sistemas altamente acoplados, y la concurrencia causada por el uso de
objetos mutables.
Descripcion de la Solucion
El presente capıtulo, describe el analisis, diseno, desarrollo y pruebas de la librerıa
50
51
funcional construida sobre el lenguaje orientado a objetos Java. Dentro de las sec-
ciones a continuacion se describe tanto las limitaciones del lenguaje Java sobre
Haskell, ası como algunas de las tecnicas empleadas durante el desarrollo para
superar algunas de estas limitaciones.
Algunos de los objetivos claves del presente capıtulo son:
Identificar los modulos de Haskell a ser importados.
Identificar las limitaciones encontradas al tratar de importar ciertos modulos a
Java.
Describir las convenciones tanto de documentacion, como de estructura de
codigo de la librerıa.
Describir las tecnicas empleadas para superar algunas de las limitaciones en-
contradas en Java.
Describir el proceso de pruebas utilizado durante el desarrollo de la librerıa.
Metodologıa de Desarrollo
Para el desarrollo de la librerıa funcional se ha seleccionado Scrum como metodo-
logıa. La naturaleza iterativa e incremental de Scrum sigue la misma filosofıa del
desarrollo guiado por pruebas, lo cual hace que se integren bien durante las dife-
rentes fases del desarrollo.
La tabla 2.1 a continuacion, lista las historias de usuario dentro del Product Backlog
del proyecto:
52
Fase Historia de Usuario Prioridad Estimacion Estado
Analisis Como un usuario de la librerıa,
yo quiero que la librerıa sea
compatible con diferentes ver-
siones de Java, para que no
existan conflictos en mis proyec-
tos durante la actualizacion de
versiones del lenguaje.
1 8 Hecho
Diseno Como un usuario de la librerıa,
yo quiero tener acceso a la do-
cumentacion, para tener una re-
ferencia del modo de uso de los
metodos y clases definidos den-
tro de la librerıa.
2 8 Hecho
Diseno Como un contribuidor de la li-
brerıa, yo quiero tener acceso al
codigo fuente, para poder reali-
zar contribuciones al proyecto.
3 3 Hecho
Desarrollo Como un contribuidor de la li-
brerıa, yo quiero que el proyec-
to utilice un servicio de integra-
cion continua, para poder detec-
tar defectos y errores introduci-
dos por cambios de una manera
temprana.
4 5 Hecho
53
Fase Historia de Usuario Prioridad Estimacion Estado
Pruebas Como un usuario de la librerıa,
yo quiero utilizar un producto de
software con un alto nivel de co-
bertura de pruebas, para que el
uso de la librerıa no introduzca
errores o defectos dentro de mis
sistemas.
5 8 Hecho
Tabla 2.1: Product Backlog
Las historias de usuario presentadas en el Product Backlog fueron desarrolladas a
lo largo de 3 Sprints, los cuales se describe a continuacion:
Historia de Usuario Estimacion Tareas
Como un usuario de la librerıa,
yo quiero que la librerıa sea
compatible con diferentes ver-
siones de Java, para que no
existan conflictos en mis proyec-
tos durante la actualizacion de
versiones del lenguaje.
8 Evaluar las versiones de Java
mas utilizadas en la industrıa.
Identificar las limitaciones del
lenguaje Java comparado con
Haskell.
Analizar la portabilidad de los
modulos de Haskell a Java.
Como un usuario de la librerıa,
yo quiero tener acceso a la do-
cumentacion, para tener una re-
ferencia del modo de uso de los
metodos y clases definidos den-
tro de la librerıa.
5 Documentar el codigo fuente.
Generar la documentacion.
Subir la documentacion a un re-
positorio publico.
Tabla 2.2: Sprint #1 - Spring Backlog
54
Historia de Usuario Estimacion Tareas
Como un contribuidor de la li-
brerıa, yo quiero tener acceso al
codigo fuente, para poder reali-
zar contribuciones al proyecto.
3 Instalar y configurar un sistema
de versionamiento.
Subir el codigo fuente a un repo-
sitorio en la nube.
Como un contribuidor de la li-
brerıa, yo quiero que el proyec-
to utilice un servicio de integra-
cion continua, para poder detec-
tar defectos y errores introduci-
dos por cambios de una manera
temprana.
5 Ejecutar las pruebas como parte
del proceso de integracion con-
tinua.
Ejecutar las pruebas utilizando
diferentes versiones de la JVM.
Generar la documentacion co-
mo parte de la integracion con-
tinua.
Tabla 2.3: Sprint #2 - Spring Backlog
Historia de Usuario Estimacion Tareas
Como un usuario de la librerıa,
yo quiero utilizar un producto de
software con un alto nivel de co-
bertura de pruebas, para que el
uso de la librerıa no introduzca
errores o defectos dentro de mis
sistemas.
8 Instalar y configurar JUnit en el
proyecto.
Configurar la librerıa PiTest para
la ejecuccion de pruebas de mu-
tacion.
Automatizar la ejecuccion de
pruebas.
Generar el reporte de pruebas
como parte de la integracion
continua.
Tabla 2.4: Sprint #3 - Spring Backlog
Finalmente la figura a continuacion 2.1, muestra el progreso realizado a lo largo de
55
todo el desarrollo del proyecto:
Figura 2.1: Release Burndown
2.1 ANALISIS
Antes de proceder con el diseno de la librerıa funcional, se debe evaluar cada uno
de los modulos escritos en Haskell, con el fin de analizar su portabilidad a Java.
Adicionalmente se tomaran en cuenta las siguientes consideraciones:
Compatibilidad con versiones anteriores de Java Development Kit (JDK).
Limitaciones del lenguaje de programacion Java.
2.1.1 RETROCOMPATIBILIDAD
Uno de los principales objetivos del presente proyecto, es extender el uso de la
librerıa desarrollada, para lo cual se evaluara el porcentaje de uso de las diferentes
versiones de Java.
La figura 2.2 a continuacion muestra el uso de las diferentes versiones de Java en
la actualidad:
56
0.1 %
29 %
70 %
0.9 %
JDK 8JDK 7JDK 6JDK 5
Figura 2.2: Uso de las Versiones de JDK
Fuente: https://plumbr.eu/blog/java/most-popular-java-environments
Como se puede observar en la figura 2.2, a pesar de existir hoy en dıa nuevas
versiones de Java las cuales introducen algunas caracterısticas de la programacion
funcional, todavıa existe un alto porcentaje de uso de la version 6 de Java.
La librerıa desarrollada sera compatible con las siguientes versiones de Java:
Java 6
Java 7
Java 8
Cualquier analisis realizado en las secciones a continuacion, tomara en cuenta que
la librerıa debe ser compatible con versiones anteriores de Java a partir de la version
6.
2.1.2 LIMITACIONES DEL LENGUAJE DE PROGRAMACION JAVA
Al comparar dos lenguajes de programacion, pueden existir ventajas y desventa-
jas de un lenguaje sobre otro, sin embargo debido a que se procedera a importar
57
modulos escritos en Haskell a Java, la presente seccion se enfocara en describir
las limitaciones de Java sobre Haskell las cuales seran consideradas en la fase de
diseno 2.2 mas adelante.
Efectos Secundarios
En Java no existe restriccion para limitar efectos secundarios en un metodo a dife-
rencia de Haskell, en donde una funcion debe especificar explıcitamente la presen-
cia de efectos secundarios.
1 printMessage : : String −> IO ( )
2 printMessage m = putStrLn m
Fragmento de Codigo 2.1: Efecto Secundario Explıcito
1 public void printMessage ( S t r i n g message ) {
2 System . out . p r i n t l n ( message ) ;
3 }
Fragmento de Codigo 2.2: Efecto Secundario Implıcito
Como se puede observar en el fragmento de codigo 2.2, no existe ningun indicio
en la firma del metodo printMessage de que tenga algun efecto secundario, a dife-
rencia del fragmento de codigo 2.1 en donde el tipo del retorno de la funcion IO ()
indica que la funcion printMessage tiene algun efecto sobre la entrada y salida de
informacion.
Evaluacion Perezosa
Haskell es perezoso por defecto, es decir, no evalua una expresion hasta que sea
necesario, a continuacion un ejemplo:
58
1 > take 3 [ 1 . . ]
2 [ 1 , 2 , 3 ]
Fragmento de Codigo 2.3: Evaluacion Perezosa - Haskell
Como se puede observar en el fragmento de codigo 2.3, la funcion take toma co-
mo argumento una lista infinita [1..] , sin embargo para mostrar el resultado en la
pantalla, Haskell solo evaluara los 3 primeros elementos de la lista.
Analizando el mismo ejemplo en Java, dado que el proceso de evaluacion del len-
guaje es estricto, evaluar una lista infinita resultarıa en un error de memoria, como
se puede observar en el fragmento de codigo a continuacion 2.4:
1 take (3 , i n f i n i t e L i s t ) ; / / => OutOfMemoryError
Fragmento de Codigo 2.4: Evaluacion Perezosa - Java
Por lo tanto Java no soporta la evaluacion perezosa de expresiones.
Funciones de Primera Clase
Para que una funcion sea considerada de primera clase, debe cumplir las siguientes
caracterısticas:
Poder ser utilizada como argumento de otra funcion.
Poder ser retornada como resultado de una funcion.
Poder ser asignada a una variable.
Utilizando los criterios mencionados anteriormente, se puede determinar que una
funcion en Java, no puede ser considerado una funcion de primer orden debido a
que no cumple ninguna de las caracterısticas mencionadas.
59
Funciones de Orden Superior
Una funcion que toma como parametro otra funcion, se denomina funcion de orden
superior, esta caracterıstica sin embargo no existe en Java debido a que no existen
funciones de primera clase como se indico en la seccion 2.1.2 anterior.
El fragmento de codigo 2.5 a continuacion muestra un ejemplo de uso de una fun-
cion de orden superior en Haskell:
1 > map (+ 1) [ 1 , 2 , 3 ]
2 [2 , 3 , 4 ]
Fragmento de Codigo 2.5: Ejemplo de Funcion de Orden Superior
Como se puede observar en el fragmento de codigo 2.5, la funcion map toma como
argumento a la funcion (+1), la cual es aplicada a cada uno de los elementos de la
lista [1, 2, 3].
Currying
Currying es el proceso de transformar una funcion que toma n numero de argu-
mentos, en una secuencia de n funciones que toman un solo argumento, la ultima
funcion de la secuencia retorna el resultado final de la funcion.
Con el fin de ilustrar de una manera practica la diferencia entre una funcion con
currying y una sin currying, se procedera a definir una misma funcion escrita tanto
en Haskell como en Java.
1 sum : : I n t −> I n t −> I n t
2 sum x y = x + y
Fragmento de Codigo 2.6: Funcion Suma en Haskell
60
1 public i n t sum( i n t x , i n t y ) {
2 return x + y ;
3 }
Fragmento de Codigo 2.7: Funcion Suma en Java
Como se puede observar en los fragmentos de codigo 2.6 y 2.7, la funcion sum
escrita tanto en Haskell como en Java, toma el mismo numero de argumentos y
retorna el mismo tipo de dato como resultado.
A continuacion un ejemplo de uso de cada una de las funciones definidas anterior-
mente:
1 > sum 1 2
2 3
Fragmento de Codigo 2.8: Ejemplo de Uso Funcion Suma en Haskell
1 > sum(1 , 2) ;
2 3
Fragmento de Codigo 2.9: Ejemplo de Uso Funcion Suma en Java
Como se puede observar en los fragmentos de codigo 2.8 y 2.9, el resultado de
invocar la funcion sum es el mismo tanto en Haskell como en Java, sin embargo el
proceso de ejecucion es diferente.
La tabla 2.5 a continuacion, detalla el proceso de ejecucion para los fragmentos de
codigo 2.8 y 2.9:
61
Haskell Java
1. La funcion sum toma como ar-
gumento el numero 1 y re-
torna como resultado otra fun-
cion, empleando el proceso de
currying.
2. La funcion retornada toma el ar-
gumento faltante, el numero 2 y
retorna el resultado de la suma
el numero 3.
1. La funcion sum toma como ar-
gumento los numeros 1 y 2, y
retorna el resultado de la suma,
el numero 3.
Tabla 2.5: Proceso de Ejecucion - Funcion Suma
Como se puede observar en la tabla 2.5 anterior, Haskell aplica la transformacion
de currying por defecto a todas sus funciones, permitiendo ası invocar a una funcion
con un menor numero de argumentos, mientras que en Java esto no es posible ya
que darıa como resultado un error de compilacion.
Aplicacion Parcial de Funciones
La aplicacion parcial de funciones, es la habilidad de una funcion para tomar un
menor numero de argumentos, y retornar otra funcion la cual tome los argumentos
restantes.
Utilizando la funcion sum definida en la seccion 2.1.2 anterior, el fragmento de codi-
go 2.10 a continuacion, muestra como se puede obtener una funcion parcialmente
aplicada a partir de la funcion definida:
62
1 > l e t addOne = sum 1
2 > addOne 2
3 3
Fragmento de Codigo 2.10: Ejemplo de Aplicacion Parcial de Funciones
Como se puede observar en el fragmento de codigo 2.10, la funcion sum toma
como argumento el numero 1, obteniendo como resultado una funcion parcialmente
aplicada la cual es almacenada en la variable addOne, posteriormente dicha funcion
es invocada con el argumento restante 2, obteniendo como resultado 3.
El ejemplo definido en el fragmento de codigo 2.10, no serıa posible importarlo a
Java debido a las siguientes limitaciones:
Las funciones en Java no son consideras objetos de primera clase, esto im-
pedirıa que una funcion sea asignada a una variable.
Las funciones en Java no son transformadas mediante la tecnica de currying,
esto impedirıa que la funcion sum escrita en Java, sea invocada con un menor
numero de argumentos que el definido por la funcion.
Debido a los puntos mencionados anteriormente, se puede concluir que Java no
soporta la aplicacion parcial de funciones.
2.1.3 ANALISIS DE PORTABILIDAD
Una vez descritas las limitaciones del lenguaje de programacion Java comparado
con Haskell en la seccion 2.1.2, se procedera a realizar un analisis de portabili-
dad para poder determinar que modulos escritos en Haskell, son factibles de ser
importados a Java.
La version de la librerıa base de Haskell utilizada para el analisis de portabilidad
sera la version 4.7.0.2, la cual forma parte del compilador de Haskell ghc en su
version 7.8.4.
63
Antes de proceder con el analisis de portabilidad, se debe destacar que solo se
tomaran en cuenta los modulos definidos dentro de Data, tal y como se especıfico
dentro del alcance del proyecto.
La tabla 2.6 a continuacion, detalla el analisis de portabilidad realizado para cada
uno de los modulos candidatos:
Modulo Importado Justificacion
Data.Bits No Este tipo de operaciones a nivel de bits es
algo comun en aplicaciones especializadas
sin embargo en la mayorıa de aplicaciones
se trabaja con estructuras de datos de mas
alto nivel.
Data.Bool Sı Las operaciones entre booleanos son bas-
tante comunes dentro del desarrollo de
aplicaciones.
Data.Char No A pesar de que trabajar con caracteres
sea un tarea muy comun la mayorıa de la
funcionalidad provista por este modulo en
Haskell ya se encuentra implementada en
la librerıa base de Java.
Data.Coerce No Este modulo provee la capacidad de trans-
formar un valor entre diferentes tipos sin
anadir un costo adicional de procesamien-
to, este concepto es util sin embargo no es
posible aplicarlo en Java debido a que sus
tipos son rıgidos.
Data.Complex No Este modulo es utilizado para manejar ti-
pos de datos algebraicos lo cual no es muy
comun dentro del desarrollo de sistemas
no especializados.
64
Modulo Importado Justificacion
Data.Dynamic No Este modulo provee soporte para tipos
dinamicos en Haskell funcionalidad que no
sera importada en Java ya que involucra
conceptos que no son soportados por el
lenguaje.
Data.Either Sı La estructura de datos definida por este
modulo es util para convertir funciones con
efectos secundarios en funciones puras,
por ejemplo funciones que lanzan excep-
ciones.
Data.Eq No Java ya define como parte del lenguaje
una manera estandar para comparar obje-
tos por lo que se utilizara la misma tecnica.
Data.Fixed No La clase Math definida como parte de la li-
brerıa base de Java cubre la mayorıa de la
funcionalidad definida en este modulo en
Haskell.
Data.Foldable No Este modulo define una manera generica
de representar estructuras plegables como
listas sin embargo el sistema de tipos en
Java no permite implementar esta funcio-
nalidad de una manera sencilla.
Data.Function Sı En versiones anteriores de Java no exis-
te el concepto de una funcion como obje-
to de primer orden por lo que importar este
modulo proporcionara esta caracterıstica.
Data.Functor Sı Solo se definira las instancias de la clase
Functor para aquellas estructuras de datos
que existan en Java.
65
Modulo Importado Justificacion
Data.IORef No Al no ser Java un lenguaje puramente fun-
cional, cualquier funcion es libre de tener
efectos secundarios por lo que no es nece-
sario hacerlo de manera explıcita.
Data.Int No Ya existe un tipo de dato similar en Java
para el manejo de enteros por lo que no es
necesario crear uno nuevo.
Data.Ix Sı En Java no existe el concepto de rango de
datos por lo que sera util introducirlo pa-
ra poder generar listas solamente especifi-
cando el inicio y fin de la misma.
Data.List Sı A pesar de que Java ya posee su propia de-
finicion de una lista su equivalente en Has-
kell provee muchas funciones para trabajar
con este tipo de estructuras de una manera
mas clara y sencilla.
Data.Maybe Sı En Java no existe el concepto de parame-
tros opcionales el introducir esta idea per-
mitira evitar el uso de nulos.
Data.Monoid Sı Sin embargo solo se definira la instancia de
Monoid para las estructuras de datos exis-
tente en el lenguaje Java.
Data.OldTypeable No Actualmente este modulo se encuentra
marcado como deprecado en Haskell.
Data.Ord No En Java ya existe una manera por defecto
de comparar objetos por lo que no es ne-
cesario definir una nueva.
66
Modulo Importado Justificacion
Data.Proxy No El definir una manera estandar de crear un
proxy en Java no es necesario ya que es-
to se puede conseguir de una manera muy
facil empleando composicion de objetos.
Data.Ratio No Este modulo provee funciones para traba-
jar con numeros racionales lo cual no es
una funcionalidad muy utilizada en aplica-
ciones no especializadas.
Data.STRef No Este modulo en Haskell es utilizado pa-
ra crear referencias a objetos mutables sin
embargo en Java todo tipo de dato es mu-
table por defecto por lo que esto no es ne-
cesario.
Data.String Si Las cadenas de texto son parte de la li-
brerıa base de Java sin embargo su equiva-
lente en Haskell provee funcionalidad extra
para trabajar con este tipo de datos.
Data.Traversable No Muchos de los conceptos definidos dentro
de este modulo no pueden ser importados
a Java debido a algunas limitaciones del
lenguaje.
Data.Tuple Sı Una tupla es similar a una lista sin embargo
esta contiene solo dos elementos los cua-
les no necesariamente deben ser del mis-
mo tipo, esto resulta util para poder repre-
sentar conceptos como coordenadas en un
plano cartesiano.
67
Modulo Importado Justificacion
Data.Typeable No Este modulo utiliza algunos de los concep-
tos definidos por otros modulos como Data
.Dynamic y Data.Data los cuales no seran
importados.
Data.Unique No La clase UUID en Java cubre toda la fun-
cionalidad definida por este modulo en
Haskell.
Data.Version Sı Este modulo en Haskell define una mane-
ra estandar de representar una version la
cual resulta util al momento de comprobar
si una version x se encuentra dentro de un
rango de versiones definido.
Data.Word No Este modulo provee funcionalidad para tra-
bajar con enteros sin signo lo cual no es
muy comun dentro del desarrollo de siste-
mas no especializados.
Tabla 2.6: Analisis de Portabilidad
La figura 2.3 muestra un breve resumen, del numero de modulos totales vs el nume-
ro de modulos importados:
68
0 10 20 30 40
Totales
Importados
30
11
Mo
du
los
# de Modulos
Figura 2.3: Numero de Modulos Importados
En resumen un 37 % del total de modulos analizados seran importados a Java,
debido a cada una de las consideraciones expuestas en la tabla 2.6.
2.2 DISENO
Realizado tanto el analisis de limitaciones del lenguaje de programacion Java, como
el de portabilidad de modulos en la seccion anterior 2.1, se procedera al diseno de
la librerıa, la presente seccion tiene como objetivos:
Definir convenciones sobre la estructura de codigo.
Definir convenciones sobre la documentacion.
2.2.1 ESTRUCTURA DE CODIGO
La presente seccion, busca reflejar la relacion existente entre los modulos escritos
en Haskell frente a su equivalente en Java a nivel de estructura de codigo.
A continuacion un modulo de ejemplo escrito en Haskell:
69
1 module Data . Maybe where
2
3 data Maybe a = Nothing | Just a
4
5 isNothing : : Maybe a −> Bool
6 isNothing = . . .
7
8 isJust : : Maybe a −> Bool
9 isJust = . . .
Fragmento de Codigo 2.11: Modulo Maybe en Haskell
El modulo descrito en el fragmento de codigo 2.11, sera importado a Java utilizando
dos clases:
La primera clase sera utilizada para reflejar la estructura de datos definida
dentro del modulo escrito en Haskell.
La segunda clase sera utilizada para anadir todos los metodos utilitarios defi-
nidos en el modulo escrito en Haskell.
Los dos fragmentos de codigo a continuacion 2.12 y 2.13, muestra un ejemplo de
como se verıa el modulo Data.Maybe importado de Haskell a Java.
1 package j p r e l ude . data . maybe ;
2
3 public inter face Maybe<A> {
4 }
Fragmento de Codigo 2.12: Interfaz Maybe en Java
70
1 package j p r e l ude . data . maybe ;
2
3 public class Maybes {
4 public s t a t i c <A> Maybe<A> noth ing ( ) {
5 }
6
7 public s t a t i c <A> Maybe<A> j u s t (A value ) {
8 }
9
10 public s t a t i c <A> boolean i sNoth ing (Maybe<A> x ) {
11 }
12
13 public s t a t i c <A> boolean i s J u s t (Maybe<A> x ) {
14 }
15 }
Fragmento de Codigo 2.13: Modulo Maybe en Java
Como se puede observar en el fragmento de codigo 2.12 el nombre de la inter-
faz coincide con el de la estructura de datos Maybe definida en el fragmento de
codigo 2.11.
Analizando la clase Maybes definida en el fragmento de codigo 2.13, se puede
observar que los nombres de las funciones coinciden con las funciones definidas
en Haskell por el modulo Data.Maybe, esto se debe a que la estructura de la clase
definida en Java busca reflejar la misma estructura de su equivalente en Haskell.
La figura 2.4 a continuacion, muestra la estructura de paquetes para todos los
modulos importados a Java y su equivalente en Haskell:
71
jprelude
data
bool .........................................................Data.Booleither......................................................Data.Eithereq .............................................................Data.Eqfunction.................................................Data.Functionfunctor...................................................Data.Functorix..............................................................Data.Ixlist..........................................................Data.Listmaybe......................................................Data.Maybemonoid ....................................................Data.Monoidord...........................................................Data.Ordstring......................................................Data.Stringtuple.......................................................Data.Tuple
Figura 2.4: Estructura de Paquetes
2.2.2 COMPORTAMIENTO
La presente seccion tiene como objetivo ilustrar el comportamiento de algunas de
las funciones en Haskell, y su equivalente en Java.
Metodo Maybe.maybe
El siguiente fragmento de codigo 2.14, muestra el comportamiento de la funcion
maybe en Haskell:
1 > maybe 0 (+1) Nothing
2 0
3 > maybe 0 (+1) ( Just 2)
4 3
Fragmento de Codigo 2.14: Ejemplo de Uso - Maybe.maybe
La figura 2.5 a continuacion, muestra el comportamiento de la funcion maybe im-
portada a Java:
72
Aplicar f al valor de Just
Retornar el resultado
Aplicar f al valor de Just
Retornar el resultado
Retornar valor por defecto
Es instancia de Just No es instancia de Just
Figura 2.5: Diagrama de Actividad - Maybe.maybe
Metodo Maybe.isNothing
El siguiente fragmento de codigo 2.15, muestra el comportamiento de la funcion
isNothing en Haskell:
1 > isNothing Nothing
2 True
3 > isNothing ( Just 1)
4 False
Fragmento de Codigo 2.15: Ejemplo de Uso - Maybe.isNothing
La figura 2.6 a continuacion, muestra el comportamiento de la funcion isNothing
importada a Java:
73
Retornar verdadero Retornar falso
Es instancia de Nothing No es instancia de Nothing
Figura 2.6: Diagrama de Actividad - Maybe.isNothing
Metodo Maybe.isJust
El siguiente fragmento de codigo 2.16, muestra el comportamiento de la funcion
isJust en Haskell:
1 > isJust Nothing
2 False
3 > isJust ( Just 1)
4 True
Fragmento de Codigo 2.16: Ejemplo de Uso - Maybe.isJust
La figura 2.7 a continuacion, muestra el comportamiento de la funcion isJust impor-
tada a Java:
74
Retornar verdadero Retornar falso
Es instancia de Just No es instancia de Just
Figura 2.7: Diagrama de Actividad - Maybe.isJust
2.2.3 DOCUMENTACION DEL CODIGO
La documentacion del codigo fuente, tiene los siguientes objetivos:
Identificar el comportamiento El desarrollador no debe acceder al codigo fuente
de la funcion para comprender cual es su uso y comportamiento, esto puede
ser especificado en la documentacion.
Identificar su origen en Haskell Debido a que todas las clases en Java seran im-
portados de Haskell, es importante definir el origen de cada una de las clases
y funciones escritas en Java.
Agregar ejemplos Como parte de la definicion del comportamiento de la funcion,
se agregaran ejemplos de uso de la funcion, para que el usuario pueda com-
prender de una manera practica el comportamiento de cada una de las fun-
ciones definidas.
Para la documentacion del codigo fuente se utilizara la herramienta estandar de
Java conocida como Javadoc, dicha herramienta genera documentacion en formato
HyperText Markup Language (HTML), a continuacion una captura de pantalla [13]
de una pagina HTML generada utilizado Javadoc:
75
Figura 2.8: Ejemplo de Javadoc
Fuente: http://jprelude.bitbucket.org/docs
La documentacion de las clases y funciones en Java, sera tomada de su fuente
original escrita en Haskell, dicha informacion se encuentra disponible en Hackage.
Hackage es el repositorio central de paquetes de Haskell, el cual tambien es uti-
lizado para navegar a traves de la documentacion disponible en cada paquete, a
continuacion una captura [19] de pantalla:
Figura 2.9: Captura de Pantalla de Hackage
Fuente: https://hackage.haskell.org
76
2.3 DESARROLLO
Concluido el diseno y el analisis de la librerıa se procedera con el desarrollo para lo
cual se tomaran en cuenta buenas practicas como son los principios de SOLID y el
desarrollo guiados por pruebas.
2.3.1 DESARROLLO GUIADO POR PRUEBAS
El desarrollo guiado por pruebas, mas conocido como Test-Driven Development
(TDD), es una considerada una buena practica de desarrollo de software, en la cual
el desarrollador escribe la prueba primero antes de la implementacion, este proceso
presente algunas ventajas, mismas que se listan a continuacion:
Mantenimiento Cambios introducidos al sistema, los cuales afecten su comporta-
miento, seran detectados por las pruebas existentes. En TDD el porcentaje de
cobertura de pruebas es alto, ya que todo componente desarrollado parte de
escribir una prueba.
Refactorizacion La refatorizacion, permite mejorar el diseno del sistema, gracias
al alto porcentaje de cobertura de pruebas que ofrece TDD, esto simplifica el
mover pedazos de codigo de un componente a otro, sin modificar el compor-
tamiento general del sistema.
TDD es un proceso, iterativo e incremental, es decir se parte de escribir una prueba,
luego la implementacion y a continuacion se refactoriza el diseno una vez que el
comportamiento ya ha sido definido por las pruebas escritas.
Este proceso se repite una y otra vez hasta alcanzar el objetivo deseado, el cual
en el caso del desarrollador, serıa implementar una nueva caracterıstica o arreglar
algun error en el sistema.
El ciclo de vida descrito anteriormente se describe en la figura 2.10 [28] a continua-
cion:
77
Figura 2.10: Ciclo de Vida - TDD
Fuente:
https://peru.wordcamp.org/2014/session/test-driven-development-en-wordpress-2/
Las subsecciones a continuacion describen el proceso de TDD, aplicado de mane-
ra practica para la implementacion de una de las funciones importadas a Java, el
comportamiento de dicha funcion se describe en el diagrama 2.11 a continuacion:
Retornar verdadero Retornar falso
Es instancia de Nothing No es instancia de Nothing
Figura 2.11: Diagrama de Actividad - Maybe.isNothing
78
Primera Iteracion
La prueba 2.17 a continuacion, describe el comportamiento de la funcion isNothing
al recibir como argumento una instancia de la clase Nothing:
1 @Test
2 public void tes t IsNoth ingReturnsTrue ( ) {
3 asser tThat ( i sNoth ing (new Nothing ( ) ) , i s ( true ) ) ;
4 }
Fragmento de Codigo 2.17: Prueba isNothingReturnsTrue
Una vez escrita la prueba, antes de proceder a escribir la implementacion, se debe
verificar que efectivamente la prueba falle debido a las razones adecuadas, es decir
debido a que el metodo todavıa no se encuentra implementado.
TDD al ser un proceso iterativo e incremental, dicta que solo se debe escribir el codi-
go mınimo y necesario durante cada iteracion, es decir para el escenario descrito
en la prueba 2.17, la implementacion 2.18 serıa la siguiente:
1 public s t a t i c boolean i sNoth ing (Maybe<?> maybe) {
2 return true ;
3 }
Fragmento de Codigo 2.18: Primera Iteracion isNothing
Segunda Iteracion
Una vez completada la primera iteracion; la presente iteracion, definira el comporta-
miento de la funcion isNothing al recibir como argumento una instancia de la clase
Just, dicho comportamiento es reflejado en la prueba 2.19 a continuacion.
79
1 @Test
2 public void tes t I sNoth ingReturnsFa lse ( ) {
3 asser tThat ( i sNoth ing ( j u s t ( 1 ) ) , i s ( fa lse ) ) ;
4 }
Fragmento de Codigo 2.19: Prueba isNothingReturnsFalse
Como se indico al inicio de la seccion 2.3.1, TDD es un proceso iterativo e incre-
mental, al ser incremental cualquier comportamiento definido previamente durante
la primera iteracion debe ser tomado en cuenta para la implementacion de la fun-
cion isNothing.
La implementacion final de la funcion isNothing, serıa la siguiente:
1 public s t a t i c boolean i sNoth ing (Maybe<?> maybe) {
2 return maybe instanceof Nothing ;
3 }
Fragmento de Codigo 2.20: Segunda Iteracion isNothing
Finalmente, como se puede observar en el fragmento de codigo 2.20, la version
final de la funcion isNothing cumple con el comportamiento definido por las pruebas
2.17 y 2.19.
2.3.2 INTEGRACION CONTINUA
La integracion continua, es una practica de desarrollo de software en donde los
miembros del equipo integran su trabajo de manera frecuente. Cada integracion
es verificada mediante la construccion automatica del proyecto, dicha construccion
involucra la ejecucion de las pruebas.
80
Herramientas de Versionamiento
El proceso de integracion continua, requiere de un sistema de versionamiento pa-
ra el control de cambios, este permitira revertir cualquier cambio que introduzca
errores en el proyecto.
Para el presente proyecto se utilizara Git junto con Bitbucket para el versionamiento
del proyecto, a continuacion una captura de pantalla [6] de Bitbucket:
Figura 2.12: Captura de Pantalla de Bitbucket
Fuente: https://bitbucket.org
Como se puede observar en la captura de pantalla 2.12, Bitbucket guarda un histo-
rial de todos los cambios realizados.
Herramientas de Integracion Continua
Como herramienta de integracion continua se utilizara Shippable, un servicio en la
nube el cual se integra con Bitbucket para la construccion automatica de proyectos
y generacion de reporte de pruebas.
A continuacion una captura de pantalla [35] de Shippable:
81
Figura 2.13: Captura de Pantalla de Shippable
Fuente: https://app.shippable.com
Como se puede observar en la captura de pantalla 2.13 anterior, Shippable ejecuta
el proceso de construccion utilizando diferentes versiones de Java y almacena los
resultados de las pruebas.
2.3.3 TECNICAS EMPLEADAS
El objetivo de la presente seccion es destacar algunas de las tecnicas de desa-
rrollo empleadas para superar algunas de las limitaciones encontradas dentro del
lenguaje Java descritas anteriormente.
Funciones de Primera Clase
Como se indico en la seccion 2.1.2, una de las principales limitaciones de Java
frente a Haskell, es el no poder utilizar una funcion como un objeto de primer orden,
es decir como una cadena de texto o un numero.
Para poder solventar la limitacion descrita anteriormente, es necesario implementar
una estructura de datos la cual represente una funcion, dicha implementacion debe
ser abstracta ya que si bien la estructura basica de una funcion es la misma - toma
datos de entrada y genera un resultado -, su comportamiento es diferente.
La interfaz descrita en el fragmento de codigo 2.21 a continuacion, sera utilizada a
82
lo largo del proyecto como la representacion de una funcion.
1 public inter face F<A,B> {
2 B c a l l (A x ) ;
3 }
Fragmento de Codigo 2.21: Estructura de Datos Funcion
A simple vista la estructura de datos definida en el fragmento de codigo 2.21 parece
sencilla, sin embargo mas adelante, se podra observar como se utiliza para la cons-
truccion de funciones mas complejas como son las funciones de orden superior.
Funciones de Orden Superior
Una vez definida una estructura de datos para una funcion, es posible utilizarla para
la construccion de funciones de orden superior, a continuacion un ejemplo:
1 public <A, B> L i s t <B> map(F<A, B> f , L i s t <A> xs ) {
2 L i s t <B> r e s u l t = new Ar rayL i s t<B>() ;
3 for (A x : xs ) {
4 r e s u l t . add ( f . c a l l ( x ) ) ;
5 }
6 return r e s u l t ;
7 }
Fragmento de Codigo 2.22: Ejemplo de Funcion de Orden Superior
Como se puede observar en el fragmento de codigo 2.22 anterior, la funcion map to-
ma como argumento una funcion f, la cual es aplicada a cada uno de los elementos
de la lista, por ejemplo dada la siguiente funcion sum:
83
1 public F<In teger , In teger> sum( f i n a l i n t x ) {
2 return new F<In teger , In teger >() {
3 public I n t ege r c a l l ( I n tege r y ) {
4 return x + y ;
5 }
6 } ;
7 }
Fragmento de Codigo 2.23: Funcion Parcialmente Aplicada
La funcion sum definida en el fragmento de codigo 2.23 anterior, puede ser utilizada
como argumento de la funcion map de la siguiente manera:
1 > map(sum( 1 ) , [ 1 , 2 , 3 ] ) ;
2 [ 2 , 3 , 4 ]
Fragmento de Codigo 2.24: Ejemplo de Uso Funcion de Orden Superior
Currying
La estructura de datos creada en la seccion 2.3.3 para representar una funcion,
permite la implementacion de funciones las cuales retornen como resultado otra
funcion en Java.
Dicha caracterıstica permite la implementacion del proceso de currying en Java, sin
embargo a diferencia de Haskell, en donde este proceso es automatico, en Java
sera creado de manera explıcita y empleando sobrecarga de funciones.
El fragmento de codigo 2.25 a continuacion, es un ejemplo de la implementacion
del proceso de currying en Java:
84
1 public i n t sum( i n t x , i n t y ) {
2 return x + y ;
3 }
4
5 public F<In teger , In teger> sum( f i n a l i n t x ) {
6 return new F<In teger , In teger >() {
7 public I n t ege r c a l l ( I n tege r y ) {
8 return sum( x , y ) ;
9 }
10 }
11 }
Fragmento de Codigo 2.25: Ejemplo de Currying
Como se puede observar en el fragmento de codigo 2.25, el uso de sobrecarga
de funciones permite crear diferentes versiones de una funcion, dichas funciones
toman un numero diferente de argumentos, tal y como se puede observar en el
fragmento de codigo 2.26 a continuacion
1 > sum(1 , 2) ;
2 3
3 > sum( 1 ) . c a l l ( 2 ) ;
4 3
Fragmento de Codigo 2.26: Ejemplo de Uso de Currying
Aplicacion Parcial de Funciones
Empleando la tecnica de currying 2.3.3 definida en la seccion anteriormente, se
puede hacer uso de ella, para la creacion de funciones parcialmente aplicadas,
como se indica en el fragmento de codigo 2.27 a continuacion:
85
1 > map(sum( 1 ) , [ 1 , 2 , 3 ] ) ;
2 [ 2 , 3 , 4 ]
Fragmento de Codigo 2.27: Ejemplo de Aplicacion Parcial de Funciones
2.4 PRUEBAS
Para el desarrollo de las pruebas, se utilizaran tanto los niveles como categorıas de
pruebas descritos por International Software Testing Qualifications Board (ISTQB)
el cual es un estandar internacional de pruebas, basta mente utilizado en la industria
de desarrollo de software.
Los niveles y categorıas de pruebas de ISTQB junto con TDD seran utilizados para
elaborar el plan de pruebas el cual cubrira todos los distintos aspectos de la librerıa
ha ser desarrollada, desde las caracterısticas funcionales, hasta las no funcionales
como por ejemplo la compatibilidad con JDK 6.
A continuacion un listado de algunas de las principales razones por las cuales se
prueba el software tomadas de la pagina de ISTQB [9]:
Probar el software es realmente requerido para identificar defectos y errores
realizados durante la etapa de desarrollo.
Es esencial ya que asegura que la confiabilidad y satisfaccion del cliente en la
aplicacion.
Es muy importante para asegurar la calidad del producto. Calidad del producto
entregada al cliente ayuda a ganar su confianza.
Probar es necesario para proveer las facilidades al cliente como le entrega
de un producto de software de alta calidad el cual requiera poco costo de
mantenimiento y por lo tanto resulte mas conveniente, consistente y confiable.
Probar es necesario para un desempeno eficaz del producto de software.
86
Probar es importante para asegurar que una aplicacion no resulte en fracaso
debido a que resulte muy costosa en el futuro o en etapas posteriores del
desarrollo.
Es requerido para mantenerse en el negocio.
2.4.1 NIVELES DE PRUEBAS
Los niveles de pruebas son basicos para identificar areas faltantes y prevenir so-
breescritura y repeticion entre las fases del ciclo de desarrollo. En software el ciclo
de vida por modelos define fases como la obtencion de requerimientos y analisis,
diseno, codificacion o implementacion, pruebas y despliegue [8].
El listado de niveles de pruebas a continuacion, ha sido tomado del programa de
estudio de nivel basico de ISTQB ??:
Pruebas de Componente Tienen por objeto localizar defectos y comprobar el fun-
cionamiento de modulos de software, programas, objetos, clases, etc. que
pueden probarse por separado.
Pruebas de Integracion Las pruebas de integracion se ocupan de probar las in-
terfaces entre los componentes, las interacciones con distintas partes de un
mismo sistema, como el sistema operativo, el sistema de archivos y el hard-
ware, y las interfaces entre varios sistemas.
Pruebas de Sistema Las pruebas de sistema deben estudiar los requisitos fun-
cionales y no funcionales del sistema y las caracterısticas de calidad de los
datos.
Pruebas de Aceptacion El objetivo de las pruebas de aceptacion es crear con-
fianza en el sistema, partes del sistema o caracterısticas especıficas no fun-
cionales del sistema.
Una vez definidos los niveles de pruebas, a continuacion se listan los niveles a ser
utilizados por el presente proyecto:
87
Nivel Utilizado? Descripcion
Pruebas de Componente Sı Como se indico en la seccion 2.3.1,
el desarrollo completo de la librerıa
se realizara utilizado TDD, para lo
cual se partira escribiendo pruebas
de metodos hasta llegar al nivel de
clases.
Pruebas de Integracion Sı Como se indico en la seccion 2.1.1,
la librerıa desarrollada debe ser com-
patible con versiones nuevas y anti-
guas de la JDK, por lo que es necesa-
rio ejecutar las pruebas utilizando di-
ferentes infraestructuras, una por ca-
da version diferente de Java.
Pruebas de Sistema Sı Los requisitos funcionales del siste-
ma son que los modulos migrados a
Java, cumplan con el mismo compor-
tamiento que su par escrito en Has-
kell. Cada modulo de Haskell descri-
be funciones y estructuras de datos
las al ser importadas a Java cuales
seran probados a nivel de componen-
tes.
El unico requisito no funcional del sis-
tema, es que sea compatible con ver-
siones antiguas y nuevas de las JDK,
lo cual se encuentra cubierto por las
pruebas de integracion como se in-
dico anteriormente.
88
Nivel Utilizado? Descripcion
Pruebas de Aceptacion No Debido a que las pruebas de acepta-
cion se enfocan en la entrega y des-
pliegue del sistema, no seran utiliza-
das en el proyecto, ya que la cons-
truccion de una librerıa no involucra
ninguna de las dos actividades men-
cionadas anteriormente.
Tabla 2.7: Niveles de Pruebas Utilizados
2.4.2 TIPOS DE PRUEBAS
Los tipos de pruebas, son categorıas de pruebas utilizados para identificar el objeto
de prueba sobre el cual se enfocan. El listado de tipos de pruebas a continuacion,
ha sido tomado del programa de estudio de nivel basico de ISTQB [23]:
Pruebas Funcionales Las funciones que un sistema, subsistema o componente
debe llevar a cabo pueden describirse en productos de trabajo tales como una
especificacion de requisitos, casos de uso o una especificacion funcional, o
incluso pueden no estar documentadas.
Pruebas No Funcionales Las pruebas no funcionales incluyen, pero sin limitarse
a ello, pruebas de rendimiento, pruebas de carga, pruebas de estres, pruebas
de usabilidad, pruebas de mantenibilidad, pruebas de fiabilidad y pruebas de
portabilidad.
Pruebas Estructurales Las pruebas estructurales (caja blanca) pueden realizar-
se en todos los niveles de prueba. Las tecnicas estructurales son las mas
idoneas, despues de las tecnicas basadas en la especificacion, para ayudar a
medir exhaustividad de las pruebas mediante una evaluacion de la cobertura
de un tipo de estructura.
89
Pruebas de Regresion Las pruebas de regresion son la prueba reiterada de un
programa ya probado, despues de haber sido modificado, con vistas a loca-
lizar defectos surgidos o no descubiertos como resultado del cambio de los
cambios.
A continuacion un listado de los tipos de pruebas, a ser utilizados durante el desa-
rrollo del presente proyecto:
Tipo de Prueba Utilizado? Descripcion
Pruebas Funcionales Sı Como se indico en la seccion 2.1.3, el
comportamiento de las funciones im-
portadas a Java, ya se encuentra de-
finido por su contra parte en Haskell,
por lo que toda prueba funcional de-
be reflejar el comportamiento original
de toda funcion o estructura de datos
escrita originalmente en Haskell.
Pruebas No Funcionales Sı Como se indico en la seccion 2.1.1,
la librerıa desarrollada deber ser com-
patible con diferentes versiones de
Java, para lo cual se utilizaran prue-
bas no funcionales para evaluar la
compatibilidad de la librerıa.
90
Tipo de Prueba Utilizado? Descripcion
Pruebas Estructurales Sı Un nivel alto de cobertura de pruebas
es importante, para realizar un pro-
ceso de refactorizacion sin introducir
nuevos errores al sistema. En la sec-
cion 2.4.4 a continuacion se definiran
algunos de los tipos de cobertura de
pruebas utilizados en el proyecto.
Pruebas de Regresion Sı Como se indico en la seccion 2.3.1
al utilizar TDD, para el desarrollo de
la librerıa, se obtiene un alto nivel
de cobertura de pruebas, por lo tan-
to cualquier cambio en el comporta-
miento del sistema puede ser detec-
tado por las pruebas escritas a lo lar-
go del desarrollo.
Tabla 2.8: Tipos de Pruebas Utilizados
2.4.3 PLANIFICACION DE PRUEBAS
Es importante destacar que dentro de la planificacion, las pruebas del sistema for-
man parte de la etapa de desarrollo misma, ya que se utilizara un desarrollo guiado
por pruebas, mas conocido como TDD el cual involucra disenar el software a partir
de las pruebas.
Herramientas
A lo largo del proceso de desarrollo y pruebas, se utilizara un conjunto de herra-
mientas y servicios externos para la construccion de la librerıa funcional. Dichas
herramientas y servicios externos se listan a continuacion:
91
Gradle 1
Herramienta de lınea de comandos, utilizada para integracion continua de proyectos
escritos en Java. Una de las principales caracterısticas de Gradle es la simplicidad
de su archivo de configuracion, a diferencia de otras herramientas del mismo tipo
como Maven las cuales usan archivos Extensible Markup Language (XML).
La figura 2.28 a continuacion, muestra el proceso de construccion de un proyecto
escrito en Java:
1 > grad le b u i l d
2 : compileJava
3 : processResources
4 : c lasses
5 : j a r
6 : assemble
7 : compileTestJava
8 : processTestResources
9 : tes tC lasses
10 : t e s t
11 : check
12 : b u i l d
Fragmento de Codigo 2.28: Proceso de Construccion de Gradle
A lo largo de la construccion de la librerıa funcional, Gradle sera utilizado para
realizar las siguientes tareas:
Resolucion de dependencias.
Construccion del proyecto.
Ejecucion de pruebas.
1Sitio: https://gradle.org
92
JUnit 2
Es una librerıa para la construccion de pruebas en Java, permite evaluar el compor-
tamiento de metodos y clases mediante la creacion de aserciones. JUnit tambien
posee la capacidad de generar reportes de pruebas en formato HTML.
A continuacion un listado de las tareas que se realizaran utilizando JUnit:
Creacion de pruebas.
Generacion reporte de pruebas.
PiTest 3
A diferencia de JUnit, no es una librerıa utilizada para construccion de pruebas, en
su lugar es utilizada para la generacion de reportes. Dichos reportes de pruebas se
generan a partir de la generacion de pruebas de mutacion, tal y como se indica en la
seccion 2.4.5, una vez ejecutadas dichas pruebas el reporte presenta el porcentaje
de cobertura de codigo.
Las tareas realizadas durante la construccion de la librerıa funcional son las siguien-
tes:
Generacion reporte de cobertura de pruebas.
Bitbucket 4
Es un servicio externo utilizado para el versionamiento de proyectos. Dicho servicio
en lınea permite compartir el proyecto con diferentes miembros de un equipo, co-
mo al igual que mantener un historial de cambios, lo cual resulta util para revertir
cambios que introduzcan errores o conflictos en el proyecto.
2Sitio: http://junit.org3Sitio: http://pitest.org4Sitio: https://bitbucket.org
93
Bitbucket al igual que GitHub, provee integracion con algunas herramientas, princi-
palmente aquellas utilizadas para la integracion continua de proyectos como Travis,
Shippable, entre otros.
Principalmente a lo largo del proyecto, Shippable sera utilizado para las siguientes
tareas:
Control de cambios.
Integracion continua.
Shippable 5
Servicio externo utilizado para la integracion continua 2.3.2 de proyectos de softwa-
re. Shippable provee integracion con repositorios tanto de GitHub, como de Bitbuc-
ket.
A continuacion un listado de las tareas a ser realizadas utilizando Shippable:
Integracion continua.
Ejecucion de pruebas (utilizando diferentes versiones de JDK).
Planificacion
El diagrama a continuacion 2.14, muestra el plan de pruebas para el presente pro-
yecto junto con las herramientas utilizadas en cada etapa del proceso de pruebas.
5Sitio: https://app.shippable.com
94
Crear la prueba
Escribir/Cambiar la implementacion
Ejecutar la prueba (Gradle + JUnit)
Versionar el codigo (Git + Bitbucket)
Integracion continua (Shippable)
Analizar resultados de cobertura (Shippable)
Figura 2.14: Diagrama de Flujo - Planificacion de Pruebas
2.4.4 COBERTURA DE PRUEBAS
Es la manera de medir que cantidad de codigo se encuentra probado, a diferencia
de ejecutar una prueba en donde solo se comprueba que las aserciones defini-
das en la prueba sean las correctas, la cobertura de codigo mide que porcentaje
de lıneas de codigo fue ejecutado durante la prueba a diferencia de comprobar el
comportamiento. Dijkstra una vez dijo:
“Probar nunca prueba la ausencia de una falla, solo demuestra su existencia.”
Antes de poder definir un porcentaje de cobertura de codigo aceptable en el pre-
sente proyecto se deben tomar en cuenta algunas recomendaciones propuestas
por Martin Fowler sobre cuando se hacen suficientes pruebas:
Cuando rara vez se escapan errores a produccion.
95
Cuando rara vez se tiene miedo a cambiar codigo pensando que este produz-
ca un error en produccion.
Los dos puntos mencionados anteriormente encajan perfectamente en el concepto
de confidencia en el codigo. ¿Que es confidencia de codigo? - Es la certeza que
tenemos como desarrolladores en poder realizar modificaciones al codigo sin tener
que preocuparnos por introducir nuevos errores.
Para el presente proyecto se utilizaron dos diferentes maneras de medir la cobertura
de codigo, una tradicional y una que nace a partir de un concepto denominado
pruebas de mutacion.
Cobertura por Lıneas de Codigo
Es una las metricas de cobertura de codigo mas tradicionales y simples. Si una
sentencia de codigo es accionada durante la ejecucion de una prueba se puede
considerar que la sentencia se encuentra cubierta.
Cobertura por Mutacion
En la seccion a continuacion se definira de una manera mas clara el concepto mu-
tacion, sin embargo de momento podemos afirmar que una mutacion es una falla
generada en el sistema la cual podrıa o no ser detectada por las pruebas. La co-
bertura por mutacion se encarga de medir el numero de mutaciones detectadas
por el conjunto de pruebas existentes, es decir a mayor cantidad de mutaciones sin
detectar menor sera el porcentaje de cobertura de codigo.
2.4.5 PRUEBAS DE MUTACION
Las pruebas de mutacion consisten en identificar fallas introducidas en el sistema
utilizando las pruebas definidas en el sistema. Dichas fallas introducidas se las co-
noce como mutaciones, una mutacion se considera muerta cuando por lo menos
96
una prueba falla debido a dicho mutacion caso contrario se considera que la mu-
tacion continua viva es decir no existen suficientes pruebas para identificar la falla
introducida en el sistema.
La figura 2.15 a continuacion describe el proceso de identificacion de mutaciones:
Figura 2.15: Flujo de Trabajo Pruebas de Mutacion
Fuente: http://www3.nd.edu/ rsanteli/pate-sp12/readings/Mutation-survey.pdf
El flujo de la figura 2.15 anterior, se detalla a continuacion:
1. Entrada el programa a ser probado.
2. Crear mutantes.
3. Entradas conjunto de pruebas.
4. Ejecutar la prueba en el programa.
97
5. La prueba del programa se ejecuta correctamente?
5.1. No - Arreglar el programa.
5.2. Sı - Ejecutar las pruebas en cada una de las mutaciones existentes.
5.2.1. Todos las mutaciones han muerto?
5.2.1.1. Sı - Analizar y marcar mutaciones equivalentes, ir al punto 3.
5.2.1.2. No - Salir.
2.4.6 EJEMPLOS DE PRUEBAS
La presente seccion contiene algunos de los resultados obtenidos durante el proce-
so de pruebas, el objetivo principal es relacionar cada uno de las pruebas expuestas
en las subsecciones a continuacion, con los niveles y tipos de pruebas expuestos
en las secciones 2.4.1 y 2.4.2 respectivamente.
Pruebas de Compatibilidad
Durante el proceso de integracion continua, con el fin de garantizar la compatibili-
dad de la librerıa con diferentes versiones de Java, las pruebas fueron ejecutadas
utilizando diferentes configuraciones de entornos, tal y como se puede observar en
la figura 2.16 a continuacion:
98
Figura 2.16: Pruebas de Compatibilidad
Fuente: https://app.shippable.com
Este tipo de pruebas, encaja dentro de las categorıas de prueba listadas en la
tabla 2.9 a continuacion:
Categorıa de Pruebas Pruebas
Nivel Integracion
Nivel Sistema
Tipo No Funcionales
Tabla 2.9: Categorıas de Pruebas - Pruebas de Compatibilidad
Cobertura de Pruebas
Como se indico en la seccion 2.4.4, un alto nivel de cobertura de pruebas tiene una
menor oportunidad de contener errores, al igual que facilita la refactorizacion de
codigo, debido a que existe un mayor numero de pruebas de regresion.
99
La figura 2.17 a continuacion muestra el porcentaje de cobertura de codigo, utilizan-
do los dos metodos descritos en la seccion 2.4.4:
Figura 2.17: Resumen de Cobertura de Pruebas
Fuente: http://jprelude.bitbucket.org/reports
Este tipo de pruebas, encaja dentro de las categorıas de prueba listadas en la
tabla 2.10 a continuacion:
Categorıa de Pruebas Pruebas
Nivel Componente
Tipo Regresion
Tabla 2.10: Categorıas de Pruebas - Cobertura de Pruebas
Pruebas de Mutacion
Como se indico en la seccion 2.4.5, las pruebas de mutacion ayudan a encontrar
areas de codigo sin probar, lo cual permite examinar casos de prueba faltantes e
identifica pruebas faltantes.
La figura 2.18 a continuacion, muestra el porcentaje de cobertura de codigo, por
pruebas de mutacion para la funcion isNothing:
Figura 2.18: Resumen de Cobertura de Pruebas
Fuente: http://jprelude.bitbucket.org/reports/jprelude.data.maybe/Maybes.java.html
En la figura 2.19, a continuacion se muestra listado de las mutaciones utilizadas,
para la pruebas de mutacion de la figura 2.18 anterior:
100
Figura 2.19: Mutantes Activos
Fuente: http://jprelude.bitbucket.org/reports/jprelude.data.maybe/Maybes.java.html
Este tipo de pruebas, encaja dentro de las categorıas de prueba listadas en la
tabla 2.10 a continuacion:
Categorıa de Pruebas Pruebas
Nivel Componente
Tipo No Funcionales
Tipo Estructurales
Tabla 2.11: Categorıas de Pruebas - Pruebas de Mutacion
Pruebas Unitarias
Como se indico en la seccion 2.3.1, a lo largo de todo el desarrollo de la librerıa se
escribira primero la prueba antes que la implementacion, por lo tanto la cobertura de
pruebas sera alta ya que cada prueba definira el comportamiento de las funciones
importadas desde Haskell.
A continuacion un ejemplo 2.29 de las pruebas unitarias, utilizadas para describir el
comportamiento de la funcion isNothing:
101
1 @Test
2 public void tes t IsNoth ingReturnsTrue ( ) {
3 asser tThat ( i sNoth ing (new Nothing ( ) , i s ( true ) ) ;
4 }
5
6 @Test
7 public void tes t I sNoth ingReturnsFa lse ( ) {
8 asser tThat ( i sNoth ing (new Just ( 1 ) , i s ( fa lse ) ) ;
9 }
Fragmento de Codigo 2.29: Ejemplo de Prueba Unitaria
Este tipo de pruebas, encaja dentro de las categorıas de prueba listadas en la
tabla 2.12 a continuacion:
Categorıa de Pruebas Pruebas
Nivel Componente
Tipos Regresion
Tabla 2.12: Categorıas de Pruebas - Pruebas de Unitarias
2.4.7 REPORTE DE PRUEBAS
Como se indico anteriormente se medira el rango de cobertura de codigo utilizando
pruebas de mutacion, para ello se emplea un herramienta que genere reportes de
pruebas de mutacion.
La herramienta utilizada para este proposito se denomina PIT acronimo de PiTest,
es una herramienta escrita en Java la cual ejecuta pruebas de mutacion y genera
reportes en varios formatos incluidos HTML.
La figura 2.20 a continuacion muestra el reporte de pruebas obtenido:
102
Figura 2.20: Reporte de Pruebas
Como se puede observar en la figura 2.20 anterior, existe un 94 % de cobertura de
pruebas y un 97 % de cobertura de mutacion, dichas cifras no solo son un indicador
de los siguientes puntos:
Un 94 % del codigo escrito ha sido ejecutado durante las pruebas.
Un 97 % de cambios en el codigo es detectado por las pruebas escritas.
Durante la refactorizacion del codigo existe un 97 % de detectar errores intro-
ducidos debido a la refactorizacion.
El 94 % del comportamiento de las funciones escritas originalmente en Has-
kell, ha sido capturado por el conjunto de pruebas escrito en Java.
CAPITULO 3. APLICACION DE LA LIBRERIA FUNCIO-
NAL A UN CASO DE ESTUDIO
El presente capıtulo tiene como objetivo evaluar los resultados obtenidos al refacto-
rizar un caso de estudio, utilizando la librerıa funcional desarrollada.
Dichos resultados seran utilizados para demostrar las mejoras obtenidas, al em-
plear patrones de programacion funcional mediante el uso de la librerıa, dentro de
un lenguaje orientado a objetos como es Java.
3.1 REFACTORIZACION FUNCIONAL DE UNA APLICACION ORIEN-
TADA A OBJETOS
Para ilustrar el uso practico de la librerıa desarrollada, se procedera a seleccionar
un caso de estudio, el cual se refactorizara utilizando la librerıa funcional desarro-
llada. Una vez concluido el proceso de refactorizacion se evaluaran los resultados
obtenidos.
3.1.1 SELECCION DEL CASO DE ESTUDIO
Existe una amplia gama de librerıas dentro del mundo de desarrollo de Java, por lo
cual es necesario definir un criterio de seleccion, el cual permita escoger el caso de
estudio, que se ajuste a las necesidades del proyecto.
103
104
Criterio de Seleccion (CS)
Antes de poder seleccionar un caso de estudio, es necesario definir un conjunto de
metricas las cuales permitan seleccionar el caso de estudio de una manera objetiva.
Las metricas utilizadas para la seleccion del caso de estudio se describen a conti-
nuacion:
Porcentaje de Uso (PU) Es el porcentaje de referencias que tiene una librerıa, a
lo largo de los diferentes proyectos almacenados en GitHub.
Numero de Problemas Reportados (PR) Es el numero de problemas o inconve-
nientes encontrados, en un proyecto de software.
Numero de Solicitudes de Cambio (SC) Es el numero de solicitudes de cambio
enviadas a un proyecto de software.
Es importante senalar, que los valores para las metricas mencionadas anteriormen-
te, seran tomados tanto de GitHub como de JIRA, a continuacion un ejemplo:
Figura 3.1: Repositorio de JUnit en GitHub
Como se puede observar en la figura 3.1 anterior, para la librerıa JUnit, existe una
cantidad de 114 Numeros de Problemas Reportados y 31 Numero de Solicitu-
des de Cambio.
Despues de haber definido como seran medidos los valores para cada una de las
metricas de seleccion, es necesario saber interpretar dichos valores, la tabla 3.1 a
continuacion muestra un ejemplo:
105
Metrica Valor Menor Valor Mayor
Porcentaje de Uso Indica un menor interes
por parte de la comuni-
dad de software en la li-
brerıa, ya que existe un
bajo numero de referen-
cias dentro de otros pro-
yectos.
Indica un mayor interes
por parte de la comuni-
dad de software en la li-
brerıa, ya que existe un
alto numero de referen-
cias dentro de otros pro-
yectos.
Numero de Problemas
Reportados
Indica que la librerıa es
mas estable, ya que exis-
te una menor cantidad de
errores reportados.
Indica que la librerıa es
menos estable, ya que
existe una mayor canti-
dad de errores reporta-
dos.
Numero de Solicitudes
de Cambio
Indica un menor interes
por parte de la comuni-
dad de software, en man-
tener la librerıa, como un
proyecto activo de soft-
ware.
Indica un mayor interes
por parte de la comuni-
dad de software, en man-
tener la librerıa, como un
proyecto activo de soft-
ware.
Tabla 3.1: Interpretacion de Metricas
Posibles Casos de Estudio
Como ya se habıa indicado anteriormente, existe una amplıa gama de librerıas en
Java, por lo cual es necesario reducir el alcance de busqueda, para lo cual solo se
tomaran en cuenta aquellas librerıas que cumpla con las siguientes caracterısticas:
Codigo Abierto Debido a que el caso de estudio seleccionado, sera refactorizado,
su codigo original sera modificado, por lo que es necesario asegurarse de no
violar los derechos de autor.
Pruebas Cualquier caso de estudio que no contenga pruebas, sera excluido ya que
106
despues de la refactorizacion, se debe garantizar que el comportamiento del
software sea el mismo, para lo cual se requiere que existen pruebas previas.
La figura 3.2 a continuacion muestra el porcentaje de uso de las 5 librerıas mas
utilizadas en Java:
64 %JUnit
22 %SLF4J
16.76 %Log4j
15.6 %Google Guava
12.63 %Apache Commons
0 % 20 % 40 % 60 % 80 % 100 %Porcentaje de Uso
Figura 3.2: Top 5 Librerıas de Java mas Utilizadas
Fuente: JavaWorld [25]
A continuacion una breve descripcion, de cada una de las librerıas listadas en la
figura 3.2 anterior:
JUnit Es una librerıa para la escritura de pruebas repetibles [26].
SLF4J Sirve como una abstraccion sobre varias librerıas de registro de eventos [36].
Log4j Es una librerıa de registro de eventos [30].
Google Guava Es una librerıa utilitaria, para el manejo de: colecciones, primitivos,
concurrencia, anotaciones,procesamiento de cadenas de texto, IO, etc [17].
Apache Commons Es un proyecto de Apache, enfocado en la reusabilidad de
componentes en Java [1].
107
Seleccion del Caso de Estudio
Una vez definidas tanto las metricas de seleccion en la seccion 3.1.1, como los po-
sibles casos de estudio en la seccion 3.1.1, la presente seccion tiene como objetivo
el determinar el caso de estudio a ser refactorizado.
Para la seleccion del caso de estudio, se usaran todas las metricas previamente de-
finidas en la seccion 3.1.1, la tabla 3.3 a continuacion muestra los valores obtenidos
para cada uno de los posibles casos de estudio:
0 100 200 300 400 500 600 700
JUnit
SLF4J
Log4j
Google Guava
Apache Commons
64
22
16,76
15,6
12,63
114
0
0
584
41
31
44
2
16
0
Numero de Solicitudes de Cambio
Numero de Problemas Reportados
Porcentaje de Uso
Figura 3.3: Posibles Casos de Estudio (Datos Obtenidos)
Como se puede observar en la figura 3.3 anterior, los datos para cada una de las
metricas se encuentran en diferentes escalas, sin embargo con el fin de comparar
los valores obtenidos es necesario normalizarlos, para lo cual se utilizara la ecua-
108
cion 3.1 a continuacion:
X ′ = 100×X −Xmin
Xmax −Xmin
(3.1)
En donde, X ′ es el valor normalizado, X es el valor de la metrica (porcentaje de
uso, numero de problemas reportados o numero de solicitudes de cambio), Xmin es
el valor mınimo de la metrica y Xmax es el valor maximo de la metrica.
A continuacion un ejemplo de normalizacion de datos, aplicado a los datos previa-
mente obtenidos (ver figura 3.3) de la librerıa SLF4J:
PU ′ = 100×22− 12,63
64− 12,63
= 18,24
(3.2)
PR′ = 100×0− 0
584− 0
= 0
(3.3)
SC ′ = 100×44− 0
44− 0
= 100
(3.4)
La figura 3.4 a continuacion, muestra los resultados obtenidos al normalizar todos
los valores previamente obtenidos (ver figura 3.3), para cada uno de los posibles
casos de estudio:
109
0 10 20 30 40 50 60 70 80 90 100
JUnit
SLF4J
Log4j
Google Guava
Apache Commons
100
18,14
8,04
5,78
0
20
0
0
100
7
70
100
4
36
0
Numero de Solicitudes de Cambio
Numero de Problemas Reportados
Porcentaje de Uso
Figura 3.4: Posibles Casos de Estudio (Datos Normalizados)
Antes de utilizar los valores normalizados de la figura 3.4 es necesario ajustarlos,
ya que como se indico en la seccion 3.1.1 la interpretacion de un valor, difiere de-
pendiendo la metrica de seleccion sobre la cual sea evaluada.
Dicho esto los valores de la metrica numero de problemas reportados deben ser
ajustados, para que su interpretacion coincida con la de las otras metricas existen-
tes, ya que a diferencia del porcentaje de uso o el numero de solicitudes de cambio,
un valor mas alto no representa un mejor criterio de seleccion, al contrario significa
que la librerıa es mas inestable comparada con las otras.
El ajuste de datos se realizara solo sobre la metrica numero de problemas reporta-
110
dos, para lo cual se utilizara la ecuacion 3.5 a continuacion:
PR′′ = PRmax − PR′ (3.5)
En donde, PR′′ es el numero de problemas reportados ajustado y PR′ es el numero
de problemas reportados normalizado.
A continuacion un ejemplo de ajuste de datos, aplicado a los datos previamente
normalizados (ver figura 3.4) de la librerıa JUnit :
PR′′ = 100− 20
= 80(3.6)
La figura 3.5 a continuacion, muestra los valores ajustados para todos los casos de
estudio evaluados:
111
0 10 20 30 40 50 60 70 80 90 100
JUnit
SLF4J
Log4j
Google Guava
Apache Commons
100
18,14
8,04
5,78
0
80
100
100
0
93
70
100
4
36
0
Numero de Solicitudes de Cambio
Numero de Problemas Reportados
Porcentaje de Uso
Figura 3.5: Posibles Casos de Estudio (Datos Ajustados)
Una vez obtenidos normalizados y ajustados los valores para cada una de las metri-
cas en la figura 3.5, se procedera a calcular el valor del criterio de seleccion para
cada uno de los casos de estudio, utilizando la ecuacion 3.7 a continuacion:
CS =PU ′′ + PR′′ + SC ′′
3(3.7)
En donde, CS es el criterio de seleccion, PU ′′ es el porcentaje de uso normalizado,
PR′′ es el numero de problemas reportados, y SC ′′ es el numero de solicitudes de
cambio.
Como se puede observar en la ecuacion 3.7 anterior, el valor del criterio de selec-
cion es el promedio de las tres metricas (porcentaje de uso, numero de problemas
reportados y numero de solicitudes de cambio).
112
La figura 3.6 a continuacion muestra el valor del criterio de seleccion para cada uno
de los posibles casos de estudio evaluados:
35.01 %
30.45 %
15.69 % 5.87 %
12.98 %
JUnitSLF4JLog4jGoogle GuavaApache Commons
Figura 3.6: Criterio de Seleccion
Como se puede observar en la figura 3.6, la librerıa que se ajusta mejor al criterio
de seleccion es JUnit con un 35.01 %, por lo tanto sera la librerıa utilizada como
caso de estudio.
3.1.2 REFACTORIZACION DEL CASO DE ESTUDIO
Una vez seleccionado el caso de estudio, es necesario definir el alcance de la refac-
torizacion, para lo cual se utilizara como criterio de seleccion el numero de lıneas
de codigo (LOC) de cada clase.
La tabla 3.2 a continuacion muestra el listado de las 5 clases con mayor numero de
lıneas de codigo dentro de la librerıa JUnit :
113
Clase Lıneas de Codigo
org.junit.Assert 316
org.junit.runners.ParentRunner 261
org.junit.runners.BlockJUnit4ClassRunner 234
org.junit.experimental.categories.Categories 233
org.junit.runners.model.TestClass 233
Tabla 3.2: Numero de Lıneas de Codigo por Clase
Como se puede observar en la tabla 3.2 anterior, la clase con mayor numero de
lıneas de codigo es Assert. Es importante resaltar que la version de JUnit sobre la
cual se trabajo es la version 4.12 (ultima version a la fecha 24/12/2015).
A continuacion se listan 5 metodos de la librerıa JUnit refactorizados, el resto se en-
cuentran en el siguiente repositorio https://bitbucket.org/jprelude/junit en BitBucket:
Metodo fail
El metodo fail es ejecutado para lanzar una excepcion, tomando un mensaje de
error como argumento. Si el mensaje de error pasado como argumento es nulo,
fail lanza una excepcion sin mensaje de error, caso contrario lanza una excepcion
utilizando el mensaje de error pasado como argumento.
El fragmento de codigo 3.1 a continuacion, muestra el codigo fuente original del
metodo fail :
1 s t a t i c public void f a i l ( S t r i n g message ) {
2 i f ( message == nul l ) {
3 throw new Asse r t i onEr ro r ( ) ;
4 }
5 throw new Asse r t i onEr ro r ( message ) ;
6 }
Fragmento de Codigo 3.1: Metodo fail Antes de la Refactorizacion
114
Una vez refactorizado el fragmento de codigo 3.1 original, el resultado obtenido es
el siguiente:
1 s t a t i c public void f a i l ( S t r i n g message ) {
2 throw maybe(new Asse r t i onEr ro r ( ) , new F<St r ing ,
Asser t ionEr ro r >() {
3 public Asse r t i onEr ro r c a l l ( S t r i n g message ) {
4 return new Asse r t i onEr ro r ( message ) ;
5 }
6 } , j u s t ( message ) ) ;
7 }
Fragmento de Codigo 3.2: Metodo fail Despues de la Refactorizacion
Comparando los dos fragmentos de codigo 3.1 y 3.2, se puede observar que se ha
eliminado el condicional existente.
Metodo equalsRegardingNull
El metodo equalsRegardingNull es utilizado para comparar dos objetos, indistin-
tamente, si son nulos o no. Si el primero objeto pasado como argumento es nulo
y el segundo objeto es nulo, los objetos son iguales, caso contrario se procede a
comparalos.
El fragmento de codigo 3.3 a continuacion, muestra el codigo fuente original del
metodo equalsRegardingNull :
115
1 private s t a t i c boolean equalsRegardingNul l ( Object
expected , Object ac tua l ) {
2 i f ( expected == nul l ) {
3 return ac tua l == nul l ;
4 }
5
6 return i sEquals ( expected , ac tua l ) ;
7 }
Fragmento de Codigo 3.3: Metodo equalsRegardingNull Antes de la Refactorizacion
Una vez refactorizado el fragmento de codigo 3.3 original, el resultado obtenido es
el siguiente:
1 private s t a t i c boolean equalsRegardingNul l ( Object
expected , Object ac tua l ) {
2 return maybe( ac tua l == null , new F<Object , Boolean >() {
3 public Boolean c a l l ( Object expected ) {
4 return i sEquals ( expected , ac tua l ) ;
5 }
6 } , j u s t ( expected ) ) ;
7 }
Fragmento de Codigo 3.4: Metodo equalsRegardingNull Despues de la
Refactorizacion
Comparando los dos fragmentos de codigo 3.3 y 3.4, se puede observar que se ha
eliminado el condicional existente.
Metodos doubleIsDifferent y floatIsDifferent
Los metodos doubleIsDifferent y floatIsDifferent, comparan si dos numeros del tipo
Double o Float son diferentes, primero compara dichos numeros utilizando el meto-
do compare, si dichos numeros son iguales comprueba si la diferencia del valor
116
absoluto de dichos numeros no es menor o igual al valor de desviacion delta.
Los fragmentos de codigo 3.5, 3.6 y 3.9 a continuacion, muestra el codigo fuente
original de los metodos doubleIsDifferent y floatIsDifferent :
1 s t a t i c pr ivate boolean d o u b l e I s D i f f e r e n t ( double d1 ,
double d2 , double d e l t a ) {
2 i f ( Double . compare ( d1 , d2 ) == 0) {
3 return fa lse ;
4 }
5 i f ( ( Math . abs ( d1 − d2 ) <= d e l t a ) ) {
6 return fa lse ;
7 }
8 return true ;
9 }
Fragmento de Codigo 3.5: Metodo doubleIsDifferent Antes de la Refactorizacion
1 s t a t i c pr ivate boolean f l o a t I s D i f f e r e n t ( f l o a t f1 , f l o a t
f2 , f l o a t d e l t a ) {
2 i f ( F loa t . compare ( f1 , f2 ) == 0) {
3 return fa lse ;
4 }
5 i f ( ( Math . abs ( f1 − f2 ) <= d e l t a ) ) {
6 return fa lse ;
7 }
8 return true ;
9 }
Fragmento de Codigo 3.6: Metodo floatIsDifferent Antes de la Refactorizacion
Una vez refactorizados los fragmentos de codigo 3.5 y 3.6 originales, el resultado
obtenido es el siguiente:
117
1 s t a t i c pr ivate boolean d o u b l e I s D i f f e r e n t ( double d1 ,
double d2 , double d e l t a ) {
2 return i s D i f f e r e n t (Nums.DOUBLE, d1 , d2 , d e l t a ) ;
3 }
Fragmento de Codigo 3.7: Metodo doubleIsDifferent Despues de la Refactorizacion
1 s t a t i c pr ivate boolean f l o a t I s D i f f e r e n t ( f l o a t f1 , f l o a t
f2 , f l o a t d e l t a ) {
2 return i s D i f f e r e n t (Nums.FLOAT, f1 , f2 , d e l t a ) ;
3 }
Fragmento de Codigo 3.8: Metodo floatIsDifferent Despues de la Refactorizacion
Tanto la funcion doubleIsDifferent, como la funcion floatIsDifferent reutilizan la
funcion isDifferent definida en el fragmento de codigo 3.9 a continuacion:
1 s t a t i c pr ivate <T extends Comparable<T>> boolean
i s D i f f e r e n t (Num<T> num, T n1 , T n2 , T de l t a ) {
2 return ! ( n1 . equals ( n2 ) | | num. abs (num. s u b t r a c t i o n ( n1 ,
n2 ) ) . compareTo ( d e l t a ) <= 0) ;
3 }
Fragmento de Codigo 3.9: Metodo isDifferent
Como se puede observar en los fragmentos de codigo anteriores, no solo se han
eliminado todos los condicionales, se ha extraıdo todo el codigo duplicado de los
metodos doubleIsDifferent y floatIsDifferent al metodo isDifferent.
Metodo formatClassAndValue
El fragmento de codigo 3.10 a continuacion, muestra el codigo fuente original del
metodo formatClassAndValue:
118
1 private s t a t i c S t r i n g formatClassAndValue ( Object value ,
S t r i n g va lueS t r i ng ) {
2 S t r i n g className = value == nul l ? ” n u l l ” : value .
getClass ( ) . getName ( ) ;
3 return className + ”<” + va lueS t r i ng + ”>” ;
4 }
Fragmento de Codigo 3.10: Metodo formatClassAndValue Antes de la
Refactorizacion
Una vez refactorizado el fragmento de codigo 3.10 original, el resultado obtenido es
el siguiente:
1 private s t a t i c S t r i n g formatClassAndValue ( Object value ,
S t r i n g va lueS t r i ng ) {
2 S t r i n g className = maybe( ” n u l l ” , new F<Object , S t r ing
>() {
3 public S t r i n g c a l l ( Object value ) {
4 return value . getClass ( ) . getName ( ) ;
5 }
6 } , j u s t ( value ) ) ;
7 return className + ”<” + va lueS t r i ng + ”>” ;
8 }
Fragmento de Codigo 3.11: Metodo formatClassAndValue Despues de la
Refactorizacion
3.2 ANALISIS DE RESULTADOS
Antes de poder realizar un analisis de resultados, es necesario cuantificar los resul-
tados obtenidos antes y despues del proceso de refactorizacion, con el fin de poder
analizar los resultados obtenidos.
119
El analisis de resultados, se lo realizara comparando la complejidad del codigo an-
tes y despues de la refactorizacion. La complejidad del codigo sera medida utilizan-
do la metrica complejidad ciclomatica.
3.2.1 COMPLEJIDAD CICLOMATICA (CC)
La complejidad ciclomatica, mide la cantidad de logica de decision dentro de un
modulo de software [2]. El calculo de la complejidad ciclomatica, se lo realiza en
funcion de las metricas que se describen a continuacion:
Numero de Condiciones Es el numero de condiciones dentro de una funcion.
Numero de Retornos o Salidas Es el numero de retornos dentro de una funcion
o salidas, por ejemplo el lanzamiento de una excepcion.
Como se habıa mencionado anteriormente, el calculo de la complejidad ciclomatica
se lo realiza en funcion de otras metricas, tal y como se describe en la ecuacion 3.8
a continuacion:
CC = C +RoS (3.8)
En donde CC es la complejidad ciclomatica, C es el numero de condiciones, y RoS
es el numero de retornos o salidas de una funcion:
A continuacion un ejemplo de calculo de la complejidad ciclomatica para el metodo
doubleIsDifferent definido dentro de la clase Assert :
120
1 s t a t i c pr ivate boolean d o u b l e I s D i f f e r e n t ( double d1 ,
double d2 , double d e l t a ) {
2 i f ( Double . compare ( d1 , d2 ) == 0) {
3 return fa lse ;
4 }
5 i f ( ( Math . abs ( d1 − d2 ) <= d e l t a ) ) {
6 return fa lse ;
7 }
8 return true ;
9 }
Fragmento de Codigo 3.12: Metodo doubleIsDifferent
Como se puede observar en el fragmento de codigo 3.12 anterior, existen 2 con-
diciones (lıneas 2 y 5) y 3 retornos (lıneas 3, 6 y 8). La ecuacion a continuacion,
muestra el calculo paso a paso de la complejidad ciclomatica para el metodo dou-
bleIsDifferent :
CC = C +RoS
= 2 + 3
= 5
(3.9)
Por lo tanto la complejidad ciclomatica para el metodo doubleIsDifferent, definido
en el fragmento de codigo 3.12 es de 5, tal y como se puede observar en la ecua-
cion 3.9.
3.2.2 COMPARACION DE RESULTADOS
Una vez definida la metrica sobre la cual se va a realizar la comparacion de resulta-
dos, se procedera a calcular la complejidad ciclomatica para los metodos de clase
Assert refactorizados en la seccion 3.1.2.
121
La tabla 3.3 a continuacion muestra los resultados obtenidos antes y despues de la
refactorizacion:
Metodo CC - Antes CC - Despues
fail 3 1
equalsRegardingNull 3 1
failsEquals 1 0
doubleIsDifferent 5 1
floatIsDifferent 5 1
failNotNull 1 0
failSame 1 0
failNotSame 1 0
format 4 1
formatClassAndValue 2 0
Tabla 3.3: Comparacion de la Complejidad Ciclomatica
Es importante resaltar que en la tabla anterior, solo se encuentran los valores para
los metodos de la clase Assert refactorizados, ya que la complejidad ciclomatica
para el resto de metodos no ha cambiado, debido a que dichos metodos no han
sido modificados.
A continuacion, utilizando los valores previamente obtenidos, se procedera a calcu-
lar el valor de la complejidad ciclomatica de la clase Assert, utilizando las siguientes
ecuaciones 3.10 y 3.11:
CC =n∑
i=1
CCn (3.10)
CC ′ =n∑
i=1
CC ′
n(3.11)
En donde, CC es el valor de la complejidad ciclomatica de la clase antes de la re-
factorizacion, CCn es el valor de la complejidad ciclomatica de cada metodo antes
122
de la refactorizacion, CC ′ es el valor de la complejidad ciclomatica de la clase des-
pues de la refactorizacion y CC ′
nes el valor de la complejidad ciclomatica de cada
metodo despues de la refactorizacion.
P = 100−(CC ′ ∗ 100)
CC(3.12)
La tabla 3.4 a continuacion, muestra el porcentaje de mejora obtenido para cada una
de las metricas definidas dentro de la presente seccion, comparando los resultados
antes y despues de la refactorizacion:
Metrica Antes Despues Porcentaje de Reduccion
Numero de Condiciones 26 12 54 %
Numero de Retornos 19 9 53 %
Complejidad Ciclomatica 45 21 53 %
Tabla 3.4: Comparacion de Resultados
Como se puede observar en la tabla 3.4 anterior, se ha reducido la complejidad
ciclomatica de la clase Assert en un 53 %. Dicho valor demuestra que la refacto-
rizacion realizada, empleado la librerıa desarrollada, resulto ser efectiva, ya que
como se puede observar en los valores de comparacion de la tabla anterior, en
todas las metricas se obtuvo un porcentaje de mejora mayor al 50 %.
CAPITULO 4. CONCLUSIONES Y RECOMENDACIONES
4.1 CONCLUSIONES
Durante la realizacion de la ingenierıa inversa al modulo DATA de la librerıa base
de Haskell, se encontro que algunas de las funciones definidas en Haskell no pue-
den ser exportadas a Java debido a las limitaciones del lenguaje. Un claro ejemplo
es la evaluacion perezosa en Haskell la cual permite tomar elementos de una lis-
ta infinita, esto no es posible en Java debido a que la lista necesita ser evaluada
completamente primero antes de poder acceder a sus elementos.
El crear una convencion de nombres entre Haskell y Java previa a la migracion de
modulos, ayudo a que sea facil comprender la relacion que existe entre las funcio-
nes escritas en Java y sus semejantes en Haskell.
La documentacion en Haskell de las funciones exportadas a Java fue fundamental
durante el proceso de TDD, ya que se consiguio definir claramente el comporta-
miento de las funciones a ser importadas antes de ser implementadas en Java
garantizado ası que el comportamiento sea el mismo en ambos lenguajes.
Una vez elaborada la librerıa funcional, se refactorizo la librerıa JUnit demostrando
mediante metricas las mejoras obtenidas en el codigo, como la disminucion del
numero de bucles y condicionales en el codigo.
Antes de proceder con la refactorizacion, es muy importante tomar en cuenta el tipo
de licencia del proyecto, de no ser un proyecto de codigo abierto (OSS), se estarıa
violando la ley al modificar el codigo. Adicionalmente se debe tomar en cuenta que
123
124
la refactorizacion consiste en la mejora del diseno del codigo, sin la modificacion del
comportamiento previo, para lo cual es importante que exista pruebas de regresion,
que nos ayuden a garantizar que despues de la refactorizacion el comportamiento
sea el mismo.
Durante el desarrollo de la librerıa funcional, se encontro varios proyectos similares
para otros lenguajes orientados a objetos, adicionalmente hoy en dıa muchos len-
guajes - incluyendo java - han incluido caracterısticas funcionales como son el uso
de lambdas y patrones de busqueda, esto sin duda junto con la creciente cantidad
de librerıas funcionales, indican una tendencia dentro de la comunidad de desarrollo
de moverse hacia una paradigma funcional.
4.2 RECOMENDACIONES
La librerıa funcional desarrollada en el presente proyecto, serıa un aporte a la co-
munidad de software libre, cuando la Escuela Politecnica Nacional cree un reposi-
torio de codigo publico en donde se puedan publicar todos los trabajos de software
elaborados, cumpliendo ası su rol de vinculacion y responsabilidad social como uni-
versidad.
Utilizar patrones de diseno funcionales, dentro de lenguajes orientados a objetos
ayuda a disminuir la complejidad ciclomatica del codigo, permitiendo ası facilitar su
lectura y mantenimiento.
Para la refactorizacion de un producto de software se debe tomar en cuenta dos
criterios claves: el tipo de licencia del producto de software, y la existencia de prue-
bas. Dichos criterios son necesarios, debido a que el modificar software sin el previo
consentimiento del autor puedo llegar a causar problemas legales. Con respecto a
la existencia de pruebas, una vez refactorizado el codigo, las pruebas son las encar-
gadas de verificar que el comportamiento del software, no se vea afectado debido
a la refactorizacion.
Antes de proceder a evaluar cualquier mejora de un producto de software, es nece-
125
sario definir un conjunto de metricas sobre las cuales se pueda realizar una compa-
racion del codigo fuente original contra el codigo modificado. Dichas modificaciones
deben ser realizadas sobre un sistema de control de cambios, para poder regresar
a un punto seguro en caso de haber introducido algun error durante la modificacion
del codigo.
Dentro del campo profesional, se debe considerar que el costo de inversion en
desarrollar una aplicacion funcional, puede ser mayor debido a que no existe un
conjunto tan basto de librerıas como el de lenguajes orientados a objetos. Sin em-
bargo el costo de mantenimiento es menor debido a que el sistema de tipos y las
semanticas de los lenguajes funcionales permiten escribir codigo menos propenso
a errores.
SIGLAS
EJB Enterprise Java Beans. 13
FFI Foreign Function Interface. 32
FP Functional Programming. 15
HTML HyperText Markup Language. 74, 92, 101
IRC Internet Relay Chat. 41
ISTQB International Software Testing Qualifications Board. 85
JDK Java Development Kit. 55, 87
OOP Object Oriented Programming. 15
RMI Remote Method Invocation. 13
TDD Test-Driven Development. 76–79, 85, 87, 90
XML Extensible Markup Language. 91
126
GLOSARIO
batch Consiste en la ejecuccion de una serie de programas en una computadora
sin la necesidad de intervencion manual. 27
bindings Es la asociacion existente entre objetos e implementaciones con nom-
bres dentro de un lenguaje de programacion. 32
Bitbucket Bitbucket es un servicio web utilizado para el almacenamiento de pro-
yectos tanto en Git como en Mercurial. 80
cache Es un componente de software, utilizado para almacenar datos los cuales
son solicitados con frecuencia. La segunda vez que los datos sean solicitados
seran obtenidos mas rapidamente debido a que se encontraran previamente
cargados en memoria. 27
callback Es utilizado en el desarrollo de software, para el manejo de llamadas
asıncronas, es decir se ejecuta un proceso y la respuesta es manejada por
un callback cuando este proceso termine. 47
Closures Es una tecnica de programacion utilizada para crear funciones asociadas
a un contexto de ejecuccion. 47
Currying Termino matematico, introducido por Moses Schonfinkel y desarrollado
por Haskell Curry. 38, 43
debugging Es el proceso de ubicacion y correcion de un error dentro de programa
de computacion. 36
127
128
delay Es una caracterıstica muy importante a ser tomado en cuenta en diseno de
sistemas distribuidos, se trata del retraso existente entre una solucitud y un
respuesta. 46
Dijkstra Cientıfico de la Computacion y Matematico Holandes. Fısico teorico por
entrenamiento, el trabajo como programador en el Centro Matematico de Ams-
terdam desde 1952 hasta 1962. Trabajo como profesor de matematicas en la
universidad de Eindhoven (1962-1984) y como investigador en la corporacion
de Burroughs (1973-1984). 94
Git Git es un proyecto de codigo abierto, utilizado para el control de versionamiento.
42, 80
GitHub GitHub es un servicio web utilizado por alrededor de 10 millones de perso-
nas, para el desarrollo de proyectos de software. 93, 104
JIRA Es una aplicacion web, utilizada para el seguimiento de errores, incidentes y
para la gestion de proyectos. 104
LISP Es el segundo lenguaje de programacion mas viejo, su principal caracterıstica
radica en la representacion de la mayorıa de los datos como listas, incluyen-
do su codigo. Esto facilita la creacion de lenguajes de dominio especıficos,
mediante el uso de su sistema de macros. 3
Martin Fowler Ingeniero de software britanico, realiza conferencias publicas sobre
desarrollo de software, programacion orientada a objetos, analisis y diseno.
94
Maven Es una herramienta para la construccion automatica de proyectos en Java.
Incluye manejo de dependencias contrario a su predecesor Ant. 91
Mixin Es una clase la cual contiene metodos referenciados por otras clases, es una
alternativa al uso de herencia para la reutilizacion de codigo. 38
Open-Source Es el nombre denominado a proyectos de software y hardware de
libre distribucion. 7
129
point-free Dentro de la programacion funcional es la tecnica utilizada para la com-
posicion de funciones sin la necesidad de mencionar los argumentos que
seran aplicados. 43
Premio Turing Es un premio de las Ciencias de la Computacion otorgado a quie-
nes hayan contribuido de manera trascendental al campo de las ciencias de
la computacion. 3
protocolo Define un estandar para el intercambio de datos entre computadoras a
traves de la red. 46
proxy Es una clase la cual actual como una interfaz, sobre un objeto al cual delega
la invocacion de metodos. Un proxy posee la caracterıstica de anadir funcio-
nalidad extra alrededor de un metodo antes de que se invoque la llamada al
objeto asociado. 34
shell Es una interfaz de usuario la cual permite acceso a los servicios del sistema
operativo. 36
Shippable Shippable es un servicio web, utilizado para la integracion continua de
proyectos, al igual que el despliegue y pruebas de proyectos tanto en GitHub
como en Bitbucket. 80
Trait Conjunto de metodos utilizados para extender la funcionalidad de una clase.
38
Travis Servicio de integracion continua de codigo abierto, utilizado para la cons-
truccion y prueba de proyectos almacenados en GitHub. 93
BIBLIOGRAFIA
[1] Apache. Apache Commons. URL: https : / / commons . apache . org (visitado
01-08-2015).
[2] Thomas J. McCabe Arthur H. Watson. NIST Special Publication 500-235. URL:
http://www.mccabe.com/pdf/mccabe-nist235r.pdf (visitado 01-08-2015).
[3] Jeremy Ashkenas. Functional Ruby. URL: https://github.com/jdantonio/functional-
ruby (visitado 01-07-2015).
[4] Joshua Backfield. Becoming Functional: Steps for Transforming Into a Fun-
ctional Programmer. First. O’Reilly Media, 2014.
[5] John Backus. Can Programming Be Liberated from the von Neumann Style?
A Functional Style and Its Algebra of Programs. URL: https://www.cs.cmu.edu/
∼crary/819-f09/Backus78.pdf (visitado 01-07-2015).
[6] Bitbucket. URL: https://bitbucket.org (visitado 01-07-2015).
[7] Don Stewart Bryan O’Sullivan John Goerzen. Real World: Haskell. First. O’Reilly
Media, 2009.
[8] ISTQB Exan Certification. What are Software Testing Levels? URL: http : / /
istqbexamcertification.com/what-are-software-testing-levels (visitado 01-10-2015).
[9] ISTQB Exan Certification. Why is Testing Necessary. URL: http://istqbexamcertification.
com/why-is-testing-necessary (visitado 01-10-2015).
[10] Clojure - home. URL: http://clojure.org (visitado 01-07-2015).
[11] Elixir. URL: http://elixir-lang.org (visitado 01-07-2015).
[12] Erlang Programming Language. URL: http://www.erlang.org (visitado 01-07-2015).
130
131
[13] Sebastian Estrella. JPrelude. URL: http://jprelude.bitbucket.org/docs (visitado
01-06-2015).
[14] Neil Ford. Functional Thinking: Paradigm Over Syntax. First. O’Reilly Media,
2014.
[15] Functional PHP. URL: https : / / github. com / lstrojny / functional - php (visitado
01-07-2015).
[16] functional.js: The functional JavaScript library. URL: http : / / functionaljs . com
(visitado 01-07-2015).
[17] Guava. Guava. URL: https : / / code . google . com / p / guava - libraries (visitado
01-08-2015).
[18] Haskell. Functional programming. URL: https : / /wiki .haskell .org /Functional
programming (visitado 01-05-2015).
[19] Haskell. Hackage. URL: https://hackage.haskell.org (visitado 01-05-2015).
[20] Haskell. Referential transparency. URL: https: / /wiki .haskell .org/Referential
transparency (visitado 01-05-2015).
[21] Haskell Language. URL: https://www.haskell.org (visitado 01-07-2015).
[22] Gaston C. Hillar. Learning Object-Oriented Programming. Packt, 2015.
[23] ISTQB. Programa de Estudio de Nivel Basico. URL: http : / / www. istqb. org
(visitado 01-06-2015).
[24] Javaslang. Javaslang. URL: http://javaslang.com (visitado 01-07-2015).
[25] JavaWorld. Java’s top 20: The most used Java libraries on GitHub. URL: http:
//www.javaworld.com/article/2924315/open-source-tools/javas-top-20-the-
most-used-java-libraries-on-github.html (visitado 01-06-2015).
[26] JUnit. JUnit. URL: http://junit.org (visitado 01-08-2015).
[27] Korma. URL: http://sqlkorma.com (visitado 01-07-2015).
[28] WordCamp Lima. TDD Circle of Life. URL: https://peru.wordcamp.org/2014/
files/2014/08/tdd-circle-of-life.png (visitado 01-05-2015).
[29] LINQ. URL: https://msdn.microsoft.com/es-ec/library/bb397926.aspx (visitado
01-07-2015).
132
[30] Log4j. Log4j. URL: http://logging.apache.org/log4j/2.x (visitado 01-08-2015).
[31] OCaml – OCaml. URL: https://ocaml.org (visitado 01-07-2015).
[32] Oracle. ¿Que es Java? URL: https://www.java.com/es/about/whatis java.jsp
(visitado 01-06-2015).
[33] Bryan O’Sullivan. Higher order functions. URL: http:// learnyouahaskell.com/
higher-order-functions (visitado 01-05-2015).
[34] M. Papalthomas. Concurrency Issues in Object-Oriented Programming Lan-
guages. URL: http://asg.unige.ch/site/papers/Papa89a.pdf (visitado 01-05-2015).
[35] Shippable. URL: https://app.shippable.com (visitado 01-07-2015).
[36] SLF4J. SLF4J. URL: http://www.slf4j.org (visitado 01-08-2015).
[37] The Rust Programming Language. URL: https://www.rust- lang.org (visitado
01-07-2015).
[38] The Scala Programming Language. URL: http://www.scala-lang.org (visitado
01-07-2015).
[39] Underscore.js. URL: http://underscorejs.org (visitado 01-07-2015).
ANEXOS
.1 CAPTURAS DE PANTALLA DE GITHUB
Figura 1: Repositorio de Google Guava
Figura 2: Repositorio de JUnit
Figura 3: Repositorio de Log4j
133
134
Figura 4: Repositorio de SLF4J
.2 CAPTURAS DE PANTALLA DE JIRA
Figura 5: Seguimiento de Incidentes de Commons BCEL
Figura 6: Seguimiento de Incidentes de Commons BeanUtils
135
Figura 7: Seguimiento de Incidentes de Commons BSF
Figura 8: Seguimiento de Incidentes de Commons Chain
Figura 9: Seguimiento de Incidentes de Commons CLI
136
Figura 10: Seguimiento de Incidentes de Commons Codec
Figura 11: Seguimiento de Incidentes de Commons Collections
Figura 12: Seguimiento de Incidentes de Commons Compress
137
Figura 13: Seguimiento de Incidentes de Commons Configuration
Figura 14: Seguimiento de Incidentes de Commons CSV
Figura 15: Seguimiento de Incidentes de Commons Daemon
138
Figura 16: Seguimiento de Incidentes de Commons Dbcp
Figura 17: Seguimiento de Incidentes de Commons Dbutils
Figura 18: Seguimiento de Incidentes de Commons Digester
139
Figura 19: Seguimiento de Incidentes de Commons Discovery
Figura 20: Seguimiento de Incidentes de Commons EL
Figura 21: Seguimiento de Incidentes de Commons Email
140
Figura 22: Seguimiento de Incidentes de Commons Exec
Figura 23: Seguimiento de Incidentes de Commons FileUpload
Figura 24: Seguimiento de Incidentes de Commons Functor
141
Figura 25: Seguimiento de Incidentes de Commons Imaging
Figura 26: Seguimiento de Incidentes de Commons IO
Figura 27: Seguimiento de Incidentes de Commons JCI
142
Figura 28: Seguimiento de Incidentes de Commons JCS
Figura 29: Seguimiento de Incidentes de Commons Jelly
Figura 30: Seguimiento de Incidentes de Commons JEXL
143
Figura 31: Seguimiento de Incidentes de Commons JXPath
Figura 32: Seguimiento de Incidentes de Commons JXPath
Figura 33: Seguimiento de Incidentes de Commons Lang
144
Figura 34: Seguimiento de Incidentes de Commons Launcher
Figura 35: Seguimiento de Incidentes de Commons Log4j
Figura 36: Seguimiento de Incidentes de Commons Logging
145
Figura 37: Seguimiento de Incidentes de Commons Math
Figura 38: Seguimiento de Incidentes de Commons Modeler
Figura 39: Seguimiento de Incidentes de Commons Net
146
Figura 40: Seguimiento de Incidentes de Commons OGNL
Figura 41: Seguimiento de Incidentes de Commons Pool
Figura 42: Seguimiento de Incidentes de Commons Primitives
147
Figura 43: Seguimiento de Incidentes de Commons Proxy
Figura 44: Seguimiento de Incidentes de Commons SCXML
Figura 45: Seguimiento de Incidentes de Commons Validator
148
Figura 46: Seguimiento de Incidentes de Commons VFS
Figura 47: Seguimiento de Incidentes de Commons VFS
Figura 48: Seguimiento de Incidentes de Commons Weaver