Vista previa del material en texto
ESCUELA POLITÉCNICA NACIONAL FACULTAD DE INGENIERÍA DE SISTEMAS DESARROLLO DE UNA LIBRERÍA UTILITARIA FUNCIONAL SOBRE UN LENGUAJE ORIENTADO A OBJETOS, APLICADA A UN CASO DE ESTUDIO PROYECTO PREVIO A LA OBTENCIÓN DEL TÍTULO DE INGENIERO EN SISTEMAS INFORMÁTICOS Y DE COMPUTACIÓN SEBASTIÁN ESTRELLA HEREDIA sebas007estrella@gmail.com DIRECTOR: ING. ENRIQUE ANDRÉS LARCO AMPUDIA, MSc. andres.larco@epn.edu.ec Quito, abril 2016 DECLARACIÓN Yo, Sebastián Estrella Heredia, declaro bajo juramento que el trabajo aquı́ descri- to es de mi autorı́a; que no ha sido previamente presentada para ningún grado o calificación profesional; y, que he consultado las referencias bibliográficas que se incluyen en este documento. A través de la presente declaración cedo mis derechos de propiedad intelectual correspondientes a este trabajo, a la Escuela Politécnica Nacional, según lo esta- blecido por la Ley de Propiedad Intelectual, por su Reglamento y por la normatividad institucional vigente. Sebastián Estrella Heredia I CERTIFICACIÓN Certifico que el presente trabajo fue desarrollado por Sebastián Estrella Heredia, bajo mi supervisión. Ing. Enrique Andrés 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 obstáculos sin su apoyo y com- prensión. 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 cariño, 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 más de sus hijos y saber darme sus mejores consejos y guiarme por el camino correcto. A mis primos y primas, por ser mis compañeros de travesuras y ser la nueva gene- ración que nos llena de alegrı́a. A mis suegros, por abrirme las puertas de su hogar y corazón, como uno más de sus hijos. A mis cuñados y cuñada, por su alegrı́a y coraje para siempre seguir adelante y saber luchar las batallas más difı́ciles. III DEDICATORÍA En memoria de mis abuelos, gracias por todo su amor y cariño incondicional. IV CONTENIDO Resumen 1 Presentación 2 1. Marco Teórico 3 1.1. Definición del Paradigma de Programación Funcional . . . . . . . . . 3 1.1.1. Caracterı́sticas Generales . . . . . . . . . . . . . . . . . . . . . 3 1.1.2. Lenguaje de Programación Haskell . . . . . . . . . . . . . . . . 7 1.2. Definición del Paradigma de Programación Orientado a Objetos . . . 8 1.2.1. Caracterı́sticas Generales . . . . . . . . . . . . . . . . . . . . . 8 1.2.2. Lenguaje de Programación Java . . . . . . . . . . . . . . . . . 12 1.3. Comparación entre Paradigmas Funcional y Orientado a Objetos . . . 13 1.3.1. Comparación entre Paradigmas . . . . . . . . . . . . . . . . . 13 1.3.2. Comparación entre Lenguajes . . . . . . . . . . . . . . . . . . 15 1.3.3. Análisis de Resultados . . . . . . . . . . . . . . . . . . . . . . . 17 1.4. Estilo de Programación Funcional sobre un Lenguaje Orientado a Ob- jetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 V VI 1.4.1. Patrones de Diseño Funcionales . . . . . . . . . . . . . . . . . 18 1.4.2. Estado del Arte . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2. Desarrollo de la Librerı́a Utilitaria Funcional 50 2.1. Análisis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 2.1.1. Retrocompatibilidad . . . . . . . . . . . . . . . . . . . . . . . . 55 2.1.2. Limitaciones del Lenguaje de Programación Java . . . . . . . . 56 2.1.3. Análisis de Portabilidad . . . . . . . . . . . . . . . . . . . . . . 62 2.2. Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 2.2.1. Estructura de Código . . . . . . . . . . . . . . . . . . . . . . . 68 2.2.2. Comportamiento . . . . . . . . . . . . . . . . . . . . . . . . . . 71 2.2.3. Documentación del Código . . . . . . . . . . . . . . . . . . . . 74 2.3. Desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 2.3.1. Desarrollo Guiado por Pruebas . . . . . . . . . . . . . . . . . . 76 2.3.2. Integración Continua . . . . . . . . . . . . . . . . . . . . . . . . 79 2.3.3. Técnicas Empleadas . . . . . . . . . . . . . . . . . . . . . . . . 81 2.4. Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 2.4.1. Niveles de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . 86 2.4.2. Tipos de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . . 88 2.4.3. Planificación de Pruebas . . . . . . . . . . . . . . . . . . . . . 90 2.4.4. Cobertura de Pruebas . . . . . . . . . . . . . . . . . . . . . . . 94 VII 2.4.5. Pruebas de Mutación . . . . . . . . . . . . . . . . . . . . . . . 95 2.4.6. Ejemplos de Pruebas . . . . . . . . . . . . . . . . . . . . . . . 97 2.4.7. Reporte de Pruebas . . . . . . . . . . . . . . . . . . . . . . . . 101 3. Aplicación de la Librerı́a Funcional a un Caso de Estudio 103 3.1. Refactorización Funcional de una Aplicación Orientada a Objetos . . 103 3.1.1. Selección del Caso de Estudio . . . . . . . . . . . . . . . . . . 103 3.1.2. Refactorización del Caso de Estudio . . . . . . . . . . . . . . . 112 3.2. Análisis de Resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 3.2.1. Complejidad Ciclomática (CC) . . . . . . . . . . . . . . . . . . 119 3.2.2. Comparación 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. Comparación entre Paradigmas . . . . . . . . . . . . . . . . . . . . . . 15 1.4. Comparación entre Lenguajes . . . . . . . . . . . . . . . . . . . . . . 17 1.5. Estilos de Programación 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 Ejecución - Función Suma . . . . . . . . . . . . . . . . . . 61 2.6. Análisis de Portabilidad . . . . . . . . . . . . . . . . . . . . . . . . . . 67 2.7. Nivelesde 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 Mutación . . . . . . . . . . . . . 100 2.12.Categorı́as de Pruebas - Pruebas de Unitarias . . . . . . . . . . . . . 101 3.1. Interpretación de Métricas . . . . . . . . . . . . . . . . . . . . . . . . . 105 3.2. Número de Lı́neas de Código por Clase . . . . . . . . . . . . . . . . . 113 3.3. Comparación de la Complejidad Ciclomática . . . . . . . . . . . . . . 121 3.4. Comparación 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 Tecnológica 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. Número de Módulos 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 - Planificación de Pruebas . . . . . . . . . . . . . . 94 2.15.Flujo de Trabajo Pruebas de Mutación . . . . . . . . . . . . . . . . . . 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 más 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 Selección . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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 CÓDIGO 1.1. Ejemplo de Función de Orden Superior . . . . . . . . . . . . . . . . . 4 1.2. Ejemplo de Función Pura . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.3. Ejemplo de Función 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 Composición . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.12.Ejemplo de Encapsulamiento Estático . . . . . . . . . . . . . . . . . . 19 1.13.Extracción de Código (Encapsulamiento Estático) . . . . . . . . . . . 20 1.14.Refactorización utilizando Encapsulamiento Estático . . . . . . . . . . 21 1.15.Ejemplo de Objeto como Contenedor . . . . . . . . . . . . . . . . . . 22 1.16.Ejemplo de Código 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. Evaluación Perezosa - Haskell . . . . . . . . . . . . . . . . . . . . . . 58 2.4. Evaluación Perezosa - Java . . . . . . . . . . . . . . . . . . . . . . . . 58 2.5. Ejemplo de Función de Orden Superior . . . . . . . . . . . . . . . . . 59 2.6. Función Suma en Haskell . . . . . . . . . . . . . . . . . . . . . . . . . 59 2.7. Función Suma en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 2.8. Ejemplo de Uso Función Suma en Haskell . . . . . . . . . . . . . . . . 60 2.9. Ejemplo de Uso Función Suma en Java . . . . . . . . . . . . . . . . . 60 2.10.Ejemplo de Aplicación Parcial de Funciones . . . . . . . . . . . . . . . 62 2.11.Módulo Maybe en Haskell . . . . . . . . . . . . . . . . . . . . . . . . . 69 2.12.Interfaz Maybe en Java . . . . . . . . . . . . . . . . . . . . . . . . . . 69 2.13.Módulo 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 Iteración isNothing . . . . . . . . . . . . . . . . . . . . . . . . 78 2.19.Prueba isNothingReturnsFalse . . . . . . . . . . . . . . . . . . . . . . 79 2.20.Segunda Iteración isNothing . . . . . . . . . . . . . . . . . . . . . . . 79 2.21.Estructura de Datos Función . . . . . . . . . . . . . . . . . . . . . . . 82 2.22.Ejemplo de Función de Orden Superior . . . . . . . . . . . . . . . . . 82 2.23.Función Parcialmente Aplicada . . . . . . . . . . . . . . . . . . . . . . 83 2.24.Ejemplo de Uso Función de Orden Superior . . . . . . . . . . . . . . . 83 2.25.Ejemplo de Currying . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 2.26.Ejemplo de Uso de Currying . . . . . . . . . . . . . . . . . . . . . . . . 84 2.27.Ejemplo de Aplicación Parcial de Funciones . . . . . . . . . . . . . . . 85 2.28.Proceso de Construcción de Gradle . . . . . . . . . . . . . . . . . . . 91 XVII 2.29.Ejemplo de Prueba Unitaria . . . . . . . . . . . . . . . . . . . . . . . . 101 3.1. Método fail Antes de la Refactorización . . . . . . . . . . . . . . . . . 113 3.2. Método fail Después de la Refactorización . . . . . . . . . . . . . . . 114 3.3. Método equalsRegardingNull Antes de la Refactorización . . . . . . . 115 3.4. Método equalsRegardingNull Después de la Refactorización . . . . . 115 3.5. Método doubleIsDifferent Antes de la Refactorización . . . . . . . . . 116 3.6. Método floatIsDifferent Antes de la Refactorización . . . . . . . . . . . 116 3.7. Método doubleIsDifferent Después de la Refactorización . . . . . . . 117 3.8. Método floatIsDifferent Después de la Refactorización . . . . . . . . . 117 3.9. Método isDifferent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 3.10.Método formatClassAndValue Antes de la Refactorización . . . . . . . 118 3.11.Método formatClassAndValue Déspues de la Refactorización . . . . . 118 3.12.Método doubleIsDifferent . . . . . . . . . . . . . . . . . . . . . . . . . 120 RESUMEN En el capı́tulo 1, se presenta una breve introducción sobre los paradigmas de pro- gramación funcionales y orientados a objetos, al igual que una introducción sobre los lenguajes de programación Haskell y Java. Una vez definidos dichos paradig- mas y lenguajes de programación, se procedió a realizar una comparación entre ellos. En el capı́tulo 2, se definió el alcance de la librerı́a desarrollada, basándose en algunos criterios, como son las limitaciones del lenguaje y la compatibilidad con versiones anteriores de la JVM (desde la versión 1.6 en adelante). Una vez definido el alcance de la librerı́a se procedió a la implementación utilizando la técnica de desarrollo guiado por pruebas (TDD). En el capı́tulo 3, se seleccionó a JUnit como caso de estudio utilizando criterios de selección previamente definidos: porcentaje de uso, número de problemas reporta- dos y número de solicitudes de cambio. Una vez seleccionado el caso de estudio, se refactorizó el código utilizando la librerı́a desarrollada en el capı́tulo 2, y se midió los resultados obtenidos en término de la complejidad ciclomática, encontrando una mejora mayor al 50 %. Finalmente el capı́tulo 4, contiene las conclusiones y recomendaciones encontradas durante la realización del proyecto. 1 PRESENTACIÓN 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 diseño del software. Un software altamente acopla- do será difı́cil de mantener, ya que cualquier cambio causarı́a una serie de efectos en cascada, volviendo las tareas de mantenimiento y corrección de errores compli- cadas. El paradigma funcional realiza una clara separación entre datos y funcionalidad lo cual permite desarrollar aplicaciones bajamente acopladas, estos conceptos fueron aplicados dentro de una librerı́a funcional para desarrollar aplicaciones fáciles 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 procedió a refactorizar un caso de estudio, el cual fue seleccionado bajo un conjunto de métricas de selección. Una vez seleccionado el caso de estudio, se procedió a evaluar la complejidad ciclomática de la librerı́a antes y después de la refactorización. Los resultados obtenidos indicaron la reducción de la complejidadciclomática en un 50 %. 2 CAPÍTULO 1. MARCO TEÓRICO 1.1 DEFINICIÓN DEL PARADIGMA DE PROGRAMACIÓN FUNCIO- NAL La programación 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 múltiples pun- tos de vista acerca de construir aplicaciones como combinaciones de ecuaciones algebraicas. En la programación funcional los programas son ejecutados mediante la evaluación de expresiones, en contraste con la programación imperativa en donde los progra- mas están compuestos de instrucciones que cambian el estado global cuando se ejecutan. Tı́picamente, la programación funcional evita utilizar estados mutables [7]. 1.1.1 CARACTERÍSTICAS GENERALES A continuación un listado de algunas de las caracterı́sticas principales de la progra- mación funcional: 3 4 Funciones de Orden Superior Son funciones que toman como argumentos a otras funciones. Las funciones de or- den superior son útiles para refactorizar código y reducir el número de repeticiones dentro del código [33]. 1 > map (+1) [ 1 , 2 , 3 ] 2 [2 , 3 , 4 ] Fragmento de Código 1.1: Ejemplo de Función de Orden Superior En el fragmento de código 1.1 anterior la función map toma como argumento a la función (+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 programación 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 continuación dos fragmentos de código 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 Código 1.2: Ejemplo de Función 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 Código 1.3: Ejemplo de Función Impura Como se puede observar en el fragmento de código 1.3, la función sum no solo retorna el resultado de la suma; en la lı́nea de código 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 código 1.2 en donde sólo se retorna el resultado de la suma. Datos Inmutables Un dato inmutable por definición es aquel que no puede ser modificado, en la pro- gramación funcional al trabajar con valores inmutables cada modificación crea una copia del valor original dejando intacto el valor original [14]. A continuación dos fragmentos de código 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 Código 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 Código 1.5: Ejemplo de Datos Mutables Como se puede observar en el fragmento de código 1.5, la lista original definida en la lı́nea de código 1, después de eliminar el elemento 1 ha sido modificada, esto se puede evidenciar en la lı́nea de código 7. Referencia Transparencial Las operaciones puras siempre retornan el mismo resultado cada vez que son in- vocadas, a está propiedad se la conoce como referencia transparencial [20]. A continuación dos fragmentos código 1.6 y 1.7 en donde se puede observar la di- ferencia entre una función con referencia transparencial y una sin referencia trans- parencial: 1 > 1 + 2 2 3 3 > 1 + 2 4 3 Fragmento de Código 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 Código 1.7: Ejemplo Contrario de Referencia Transparencial Como se puede observar en el fragmento de código 1.7, la función currentTimeMillis siempre retorna un resultado diferente, esto se considera una violación al principio de referencia transparencial. 1.1.2 LENGUAJE DE PROGRAMACIÓN HASKELL Haskell es un avanzado lenguaje de programación puramente funcional. Un pro- ducto vanguardista Open-Source con más de 20 años de investigación, permite un desarrollo de software rápido robusto, conciso, y correcto. Posee un alto soporte de integración con otros lenguajes, construido con concurrencia y paralelismo, de- buggers, perfiles, grandes librerı́as y una comunidad muy activa. Haskell permite fácilmente producir software flexible, mantenible y de alta calidad [21]. Caracterı́sticas Principales La tabla 1.1 a continuación lista las principales caracterı́sticas del lenguaje de pro- gramación Haskell: Caracterı́stica Descripción Tipado Estático Cuando se compila un programa, el compilador cono- ce que parte del código es un número, cual es una ca- dena de texto y ası́ sucesivamente. Esto significa que muchos posibles errores son capturados al momento de compilación. 8 Caracterı́stica Descripción Evaluación Perezosa Significa que al menos que no se indique explı́cita- mente, Haskell no ejecutará funciones y calculará va- lores hasta que sea forzado a mostrar un resultado. Tabla 1.1: Caracterı́sticas Principales de Haskell 1.2 DEFINICIÓN DEL PARADIGMA DE PROGRAMACIÓN ORIEN- TADO A OBJETOS El paradigma orientado a objetos no es sólo un estilo de programación, también es un método de diseño para la construcción de sistemas. Los lenguajes orientados a objetos permiten al programador especificar unidades autónomas en forma de objetos, los cuales son construidos de datos y los métodos u operaciones que pueden ser ejecutados sobre el objeto. En la programación orientada a objetos un objeto contiene datos y provee operacio- nes (o métodos) para acceder a los datos. Los datos en un objeto no son visibles directamente, sólo a través de operaciones. En otras palabras las operaciones son la interfaz de un objeto para los usuarios del objeto. 1.2.1 CARACTERÍSTICAS GENERALES A continuación una breve recopilación, sobre las principales caracterı́sticas de la programación orientado a objetos encontrados en la mayorı́a de lenguajes de pro- gramación pertenecientes a este paradigma: 9 Encapsulamiento Procedimiento utilizado para ocultar detalles de implementación de una clase hacia el exterior, también es utilizado para restringir el acceso de otras clases a ciertos atributos y métodos definidos [22]. A continuación un fragmento de código 1.8 en donde la clase User solo expone métodos 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 Código 1.8: Ejemplo de Encapsulamiento Como se puede observar en el fragmento de código 1.8, la clase User solo expone métodos 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 métodos defini- dos en una clase padre, por lo general cuando se tiene una relación del tipo is-a es una buena opción usar herencia de clases [22]. 1 public class Bicyc le { .. . } 2 3 public class MountainBike extends Bicyc le { . . . } Fragmento de Código 1.9: Ejemplo de Herencia Como se puede observar en el fragmento de código 1.9, la clase MountainBike es una especialización de la clase Bicycle, por lo tanto se utiliza herencia para representar está relación. Polimorfismo Dos clases se consideran polimórficas, si por lo menos unos de sus métodos define la misma interfaz, es decir tanto el nombre del método 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 métodos los cuales se comporten diferente dependiendo el contexto de ejecución. A continuación un fragmento de código 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 Código 1.10: Ejemplo de Polimorfismo Como se puede observar en el fragmento de código 1.10, las clases Circle y Square pueden ser dibujadas mediante la implementación del método draw, sin embargo cada una de las clases será dibujado de manera diferente dependiendo la figura a la cual representan. Composición La composición de clases, consiste en construir una clase compleja a partir de pequeñas clases, con el fin de poder separar responsabilidades en diferentes cla- ses [22]. A continuación un fragmento de código 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 Código 1.11: Ejemplo de Composición Como se puede observar en el fragmento de código 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 implementación. 1.2.2 LENGUAJE DE PROGRAMACIÓN JAVA Es un lenguaje orientado a objetos multipropósito utilizado para el desarrollo de diversas aplicaciones, desde aplicaciones de escritorio hasta aplicaciones móvi- les [32]. Caracterı́sticas Generales La tabla 1.2 a continuación lista las caracterı́sticas más destacadas encontradas dentro del lenguaje de programación Java: 13 Caracterı́stica Descripción Independencia de Plataforma Java provee un middleware de software, el cual permi- te que el código escrito en este lenguaje sea portable a través 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 múltiples tareas al mismo tiempo definiendo varios hi- los. La principal ventaja de utilizar múltiples 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 creación de aplicaciones distribuidas, permi- tiendo acceder archivos llamando a métodos de otra máquina a través de la red. Tabla 1.2: Caracterı́sticas de Java 1.3 COMPARACIÓN ENTRE PARADIGMAS FUNCIONAL Y ORIEN- TADO A OBJETOS Una vez descritas tanto las caracterı́sticas del paradigma funcional en la sección 1.1, como las caracterı́sticas del paradigma orientado a objectos en la sección 1.2, se procederá a realizar un análisis comparativo de dichos paradigmas al igual que sus lenguajes Haskell y Java respectivamente. 1.3.1 COMPARACIÓN ENTRE PARADIGMAS La tabla 1.3 a continuación realiza un análisis comparativo entre los diferentes pa- radigmas de programación expuestos anteriormente en las secciones 1.1 y 1.2: 14 Caracterı́stica FP OOP Análisis Comparativo Funciones de Orden Superior Sı́ cumple No cumple No todos los lenguajes orientados a obje- tos soportan esta caracterı́stica, sólo aque- llos que incluyen funciones de primer or- den. Puridad Sı́ cumple No cumple En los lenguajes orientados a objetos no existe ninguna restricción referente a tener efectos secundarios. Datos Inmuta- bles Sı́ cumple No cumple La programación 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 está caracterı́stica no está disponible. Referencia Transparencial Sı́ cumple No cumple Una misma función pura retorna siempre un mismo valor, sin embargo en lenguajes orientados a objetos debido a los efectos secundarios una función 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, métodos 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 Análisis 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. Composición Sı́ cumple Sı́ cumple En los lenguajes funcionales no solo se puede componer estructuras de datos, también es posible realizar composición de funciones. Tabla 1.3: Comparación entre Paradigmas 1.3.2 COMPARACIÓN ENTRE LENGUAJES Una vez realizada la comparación entre los paradigmas de programación Functional Programming (FP) (1.1) y Object Oriented Programming (OOP) (1.2), se procederá a realizar la comparación entre los lenguajes de programación Haskell (1.1.2) y Java (1.2.2): 16 Caracterı́stica Haskell Java Análisis Comparativo Puramente Funcional Sı́ cumple No cumple Haskell es un lenguaje puramente funcio- nal, es decir el desarrollador mediante pro- gramación declarativa indica al computador cómo realizar una acción 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 Estático Sı́ cumple Sı́ cumple Ambos lenguajes son fuertemente tipados, el compilador analiza el código fuente com- probando que los tipos definidos sean co- rrectos, además no existe colisión de tipos, es decir, la conversión de un tipo de dato a otro debe ser explı́cita. Evaluación Pe- rezosa Sı́ cumple No cumple En Java cualquier expresión 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 evaluarán 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 Análisis Comparativo Multihilos Sı́ cumple Sı́ cumple Los dos lenguajes soportan procesamiento multihilos. Distribuidos Sı́ cumple Sı́ cumple Ambos lenguajes son de propósito general y funcionan en ambientes distribuidos. Tabla 1.4: Comparación entre Lenguajes 1.3.3 ANÁLISIS DE RESULTADOS Una vez realizada la comparación entre paradigmas y lenguajes de programación en las secciones 1.3.1 y 1.3.2, se procederá con el análisis 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 diseño ya que no existen cambios de estado. La evaluación perezosa de expresiones permite gestionar los recursos de una manera efectiva, ya que cualquier evaluación se realiza bajo demanda mejo- rando la velocidadde ejecución 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 separación entre funciones puras y aquellas con efectos secundarios, esto mejora tanto la lectura como la escri- tura de pruebas. 18 1.4 ESTILO DE PROGRAMACIÓN FUNCIONAL SOBRE UN LEN- GUAJE ORIENTADO A OBJETOS En la actualidad existen varios lenguajes de programación los cuales incluyen ca- racterı́sticas de la programación funcional, la tabla 1.5 a continuación 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 transformación de listas como map y reduce. JavaScript En JavaScript las funciones son objetos de primer or- den, es decir una función puede ser asignada a una variable, o utilizada como argumentos de otra función. Java (versión 8 en adelante) Incluye funciones de orden superior y métodos 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 Programación Funcional en OOP 1.4.1 PATRONES DE DISEÑO 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 programación funcional. Los patrones de diseño a continuación han sido tomados del libro Beco- ming Functional [4]. 19 Encapsulamiento Estático Con el fin de explicar de una manera práctica el patrón de diseño, se utilizará el siguiente fragmento de código 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 Código 1.12: Ejemplo de Encapsulamiento Estático Como se puede observar en el fragmento de código 1.12, la clase Contact posee las siguientes responsabilidades: Contiene los datos referentes al usuario. Es encargado de enviar correos electrónicos al usuario. A simple vista parece no existir ninguna violación al principio de responsabilidad simple ya que ambas responsabilidades están relacionadas al usuario, sin embargo la manera en la cual se envı́e un correo electrónico debe ser transparente a la clase Contact. 20 La clase Contact necesita enviar un correo electrónico sin conocer sobre detalles de su implementación; es por ello que toda lógica relacionada a enviar un correo electrónico será extraı́da a otra clase. El fragmento de código 1.13, a continuación emplea la técnica de encapsulamiento estático para extraer toda la lógica referente a enviar un correo electrónico 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 Código 1.13: Extracción de Código (Encapsulamiento Estático) Una vez encapsulada la lógica relacionada a enviar correos electrónicos 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 Código 1.14: Refactorización utilizando Encapsulamiento Estático Como se puede observar en el fragmento de código 1.14 la clase Contact des- conoce sobre los detalles de la implementación relacionados a enviar un correo electrónico, ya que toda está responsabilidad ha sido delegada a la clase Email. Objeto como Contenedor Este patrón de diseño es utilizado para encapsular el comportamiento de una fun- ción dentro de atributos de una clase, permitiendo ası́ modificar el comportamiento de la función [4]. Tomando como referencia la clase Email definida anteriormente 1.13, se puede modificar el comportamiento del método send agregando un nuevo atributo a la clase Email como se muestra en el fragmento de código 1.15 a continuación: 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 Código 1.15: Ejemplo de Objeto como Contenedor Como se puede observar en el fragmento de código 1.15 todos los atributos rela- cionados a enviar un correo electrónico han sido encapsulados dentro de la clase Email. Código como Datos Uno de los puntos claves dentro de la programación funcional es tratar a las fun- ciones como datos, es decir una función puede ser asignada a una variable o ser pasada como argumento a otra función, está caracterı́stica permite reutilizar código a un nivel granular [4]. Tomando como punto de partida el siguiente fragmento de código 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 Código 1.16: Ejemplo de Código como Datos Como se puede observar en el fragmento de código 1.16, la clase CommandLineOption tiene como atributos description el cual describe la opción de la lı́nea de comando, y atributo function el cual representa la acción realizada por la opción 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 Código 1.17: Ejemplo de Lı́nea de Comandos Como se puede observar en fragmento de código 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 sección es una breve recopilación sobre el estado actual de la progra- mación 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 últimos años, las universidades han ido incorporando en su pénsum de estudios cursos referentes a la programación funcional. A continuación un listado de algunos de los cursos de programación funcional, dic- tados alrededor del mundo: Paı́s Reino Unido Universidad Universidad de Edinburgh Instructor Philip Wadler Curso Informatics 1 - Functional Programming Año 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 Año 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 Año 2015 Figura 1.3: Curso Universidad de Oxford Fuente: http://www.comlab.ox.ac.uk/igdp/text/course06.html26 Paı́s Argentina Universidad Universidad Tecnológica Nacional Instructor Estudiantes Curso Paradigmas de Programación Año 2015 Figura 1.4: Curso Universidad Tecnológica Nacional Fuente: http://www.pdep.com.ar Paı́s Colombia Universidad Universidad de los Andes Instructor Jorge Ricardo Cuellar Curso Programación Funcional y sus Aplicaciones Año 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 Año 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 creación de herramientas de desarrollo. Empresa Facebook Proyecto Haxl Descripción Es una librerı́a que simplifica el acceso remoto a datos. Entre las principales caracterı́sticas se encuentran: batch de múltiples peticiones a una misma fuente de datos, solicitar datos de múltiples fuentes de datos de manera concurrente y cache de solicitudes anteriores. Año 2014 Figura 1.7: Haxl Fuente: https://code.facebook.com/projects/854888367872565/haxl 28 Empresa Apple Proyecto Swift Descripción Es un lenguaje de programación desarrollado por Apple, a pesar de no ser puramente funcional como Haskell, posee algunos conceptos de la programación funcional como son: funciones de orden, funciones como ciudadanos de primer orden y funciones anónimas. Año 2015 Figura 1.8: Swift Fuente: https://developer.apple.com/swift Empresa Microsoft Proyecto F# Descripción Es un lenguaje de programación desarrollado por Microsoft como parte de .NET framework, entre las principales caracterı́sticas se encuen- tran: inmutabilidad de datos, aplicación parcial de funciones, expresiones de objetos, entre otros. Año 2005 Figura 1.9: F# Fuente: http://fsharp.org 29 Empresa Intel Proyecto Compilador de Haskell Descripción Intel ha desarrollado un compilador en Haskell, como parte de su investigación en paralelismo multinúcleo a escala. Año 2013 Figura 1.10: Intel Fuente: http://www.leafpetersen.com/leaf/publications/hs2013/hrc-paper.pdf Empresa Whatsapp Proyecto Servicio de Mensajerı́a Descripción 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. Año 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 Descripción 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 aproximación para resolver problemas difı́ci- les y complejos de manejar. Año 2014 Figura 1.12: SumAll Fuente: https://sumall.com Lenguajes de Programación La presente sección contiene un listado de lenguajes de programación funcionales, utilizados tanto en la academia como en la construcción de aplicaciones. Rust Rust es un lenguaje de programación de sistemas rápido 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 ejecución [37]. Caracterı́sticas Descripción 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 está tarea. 31 Caracterı́sticas Descripción Genéricos 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 función. Búsqueda de Patrones Al igual que otros lenguajes funcionales, Rust posee la capacidad de comprobar si una determinada secuencia de datos coin- cide con algún patrón definido. Inferencia de Tipos Rust posee la capacidad de deducir au- tomáticamente el tipo de un dato a partir de una expresión. 32 Caracterı́sticas Descripción 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 código de Rust sin ningún costo extra. Esto permite reescribir una aplicación módulo a módulo, una transición paulatina hacia una mejor experiencia de desarrollo. Tabla 1.6: Caracterı́sticas de Rust A continuación un ejemplo de código 1.18 escrito en Rust tomado de la página 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 Código 1.18: Ejemplo de Rust Clojure Clojure es un dialecto de Lisp, comparte con Lisp la filosofı́a de código como datos y un sistema poderoso de macros. Clojure es un lenguaje de programación 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 diseños multihilos limpios y correctos [10]. Caracterı́stica Descripción Desarrollo Dinámico Clojure es dinámico, lo cual significa que solo ejecuta código compilado, también permite la interacción con el lenguaje a par- tir de su REPL. Dicha interacción, permite evaluar código y variables de una manera rápida. Programación Funcional Clojure es un lenguaje de programación funcional. Este provee herramientas para impedir la mutación de estado, provee fun- ciones como objetos de primera clase, y enfatiza la recursión 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 código como datos mucho más allá de las listas entre paréntesis expresiones-s, hasta vectores y mapas. Estos vectores y mapas pueden ser utilizados en el sistema de ma- cros. 34 Caracterı́stica Descripción Polimorfismo en tiempo de Ejecución Los sistemas que utilizan polimorfismo en tiempo de ejecución son fáciles de cambiar y de extender. Clojure soporta polimorfis- mo de muchas maneras diferentes: Muchas de las estructuras de datos principales en tiempo de ejecución de Clojure, son definidas mediante inter- faces de Java. Clojure soporta la generación 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 múltiples métodos. El lenguaje Clojure también soporta un polimorfismo más rápido 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). Programación 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 Descripción Funciona sobre la JVM Clojure está diseñado para ser un lenguaje anfitrión, 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 continuación un ejemplo de código 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 ri s ” ) 5 (= : emai l ” chr is@chr is . com ” ) ) ) ) Fragmento de Código 1.19: Ejemplo de Clojure Elixir Elixir es un lenguaje de programación funcional dinámico, diseñado para la cons- trucción de aplicaciones escalables y mantenibles [11]. Caracterı́stica Descripción Escalabilidad Todo código se ejecuta sobre un pequeño hilo de pro- ceso, el cual es aislado e intercambia información me- diante mensajes. Tolerancia a Fallos Elixir provee supervisores, los cuales describen como reiniciar un parte del sistema cuando algún error se presenta. Programación Funcional Promueve un estilo de programación que ayuda al desarrollador a escribir código pequeño, rápido y mantenible. 36 Caracterı́stica Descripción Ecosistema Creciente Elixir está construido con un gran conjunto de herra- mientas para su fácil desarrollo. Mix es una herra- mienta la cual facilita la creación de proyectos, manejo de tareas, ejecutar pruebas y más. 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 código. Compatible con Erlang Elixir se ejecuta sobre la máquina virtual de Erlang, lo cual permite ejecutar funciones Erlang directamente. Tabla 1.8: Caracterı́stica de Elixir A continuación un ejemplo de código 1.20 escrito en Elixir tomado de la página 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 Código 1.20: Ejemplo de Elixir Scala Scala es un lenguaje de programación multiparadigma, diseñado para expresar pa- trones comunes de una manera concisa, elegante y con seguridad de tipos. De una manera fácil integra caracterı́sticas de orientación a objectos y lenguajes funciona- les [38]. 38 Caracterı́sticas Descripción Orientación 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 través de subclases y una composición flexible basada en mi- xins Mixin. Funcional Scala es un lenguaje funcional en el sentido que cada función es un valor. Scala provee una sintaxis lige- ra para la definición de funciones anónimas, soporta funciones de orden superior, permite que las funcio- nes sean anidadas, y soporta Currying. Tipado Estático 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 genéricas Anotaciones de variantes Lı́mites de tipos superior e inferior Clases internas y tipos abstractos como miem- bros de objetos Tipos compuestos Vistas Métodos polimórficos 39 Caracterı́sticas Descripción Extensible En practica, el desarrollo de aplicaciones de dominio especı́fico por lo general requiere extensiones. Sca- la provee una única combinación de mecanismos del lenguaje la cual permite añadir nuevas caracterı́sticas al lenguaje mediante librerı́as. Tabla 1.9: Caracterı́sticas de Scala A continuación un ejemplo de código 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 Código 1.21: Ejemplo de Scala Erlang Erlang es un lenguaje de programación utilizado para la construcción masiva de software escalable el cual requiera de alta disponibilidad. Algunos de ellos se en- cuentran en uso dentro de las telecomunicaciones, banca, comercio electrónico, y mensajerı́a instantánea [12]. 40 Caracterı́sticas Descripción Concurrencia Los procesos son bastante ligeros, con un tamaño 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 comportará de igual manera en Linux, FreeBSD, Windows y otros sistemas sobre los cuales corre Er- lang. Reemplazo de Código en Caliente En un sistema de tiempo real usualmente no se quiere detener el sistema para reali- zar una actualización de código. En algu- nos sistemas de tiempo real nunca serı́a posible apagar el sistema para realizar una actualización, este tipo de sistemas deben ser diseñados con código dinámico 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 Descripción Soporte Un equipo dedicado de empleados de Ericsson trabajan en Erlang. Soporte co- mercial y servicios están disponibles pa- ra Erlang. También 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 integración 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 código nativo de Windows, Linux o Mac OS X y forma parte de la distribución estándar de Erlang. Tipado Estático, cuando sea necesario Se puede anotar el código con información sobre tipos y utilizar Dialyzer, un podero- so verificador de tipos, el cual asegura la validez del código y mejora el rendimiento. Dialyzer forma parte de Erlang, y soporta tipado gradual el cual ofrece máxima flexi- bilidad. Tabla 1.10: Caracterı́sticas de Erlang A continuación un código de ejemplo 1.22 escrito en Erlang tomado de la página 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 Código 1.22: Ejemplo de Erlang OCaml El gestor de paquetes de OCaml (OPAM) soporta la instalación de múltiples com- piladores, restricciones de paquetes flexibles, y un flujo de trabajo familiar con Git. Los paquetes son automáticamente probados, cualquier notificación es enviada a los mantenedores [31]. Caracterı́sticas Descripción Sistema de Tipos Estático OCaml provee un colección de reglas asignadas a un tipo, las cuales permiten construir variables, expresio- nes, funciones o módulos. Inferencia de Tipos Es la capacidad del compilador de deducir un tipo de- pendiendo del contexto sobre el cual se evalúe. Polimorfismo Paramétrico 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 paramétrico y subtipos. En OCaml, el polimorfismo paramétrico está introdu- cido solo por el uso del constructor let, el cual es lla- mado restricción de valores. 43 Caracterı́sticas Descripción Funtores Los funtores son funciones de módulos a módulos, pueden ser utilizadas para resolver una variedad de problemas de estructura de código: Inyección de dependencias. Autoextensión de módulos. Instanciación de módulos con estado. Tabla 1.11: Caracterı́sticas de OCaml A continuación un ejemplo de código 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 Código 1.23: Ejemplo de OCaml Librerı́asde Programación La presente sección es una breve recopilación, sobre el estado actual de la progra- mación funcional aplicada a lenguajes orientados a objetos. functional.js - 2015 Es una librerı́a funcional de JavaScript. Facilita la programación por medio de Currying y point-free, está metodologı́a ha sido utilizada desde los inicios de la construcción de la librerı́a [16]. 44 Caracterı́stica Descripción Currying fjs.curry permite facilita la creación de funciones de orden superior mediante la invocación parcial de una función existente, sin proveer todos los argumentos de la función original. Aridad La aridad de una función en JavaScript es el núme- ro de argumentos esperados por una función. Con fjs.curry es posible extender la aridad de una función más allá 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- ción, aplicando una función iterador a cada elemento. Esto es muy similar a la función nativa forEach dispo- nible en navegadores modernos, sin embargo facilita la implemetación de fjs.curry. Tabla 1.12: Caracterı́sticas de functional.js El ejemplo 1.24 a continuación 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 Código 1.24: Ejemplo de functional.js 45 Javaslang - 2014 Javaslang es una librerı́a funcional para Java 8 y versiones superiores. Javaslang añade un API y algunas mejores practicas tomadas de lenguajes como Scala, para tomar ventaja sobre las Lambdas en al programación diaria [24]. Caracterı́stica Descripción Núcleo Javaslang viene con una representación de los tipos básicos faltantes o son rudimentarios en Java. Funciones La programación funcional es sobre valores y trans- formaciones de valores utilizando funciones. Colecciones Con Javaslang se ha puesto mucho esfuerzo en el di- seño de la librerı́a de colecciones para Java, la cual cumpla con los requerimientos de la programación funcional, como la inmutabilidad. Tabla 1.13: Caracterı́sticas de Javaslang El ejemplo de código 1.25 a continuación, ha sido tomado de la página 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 Código 1.25: Ejemplo de Javaslang functional-ruby - 2013 La librerı́a funcional-ruby se encuentra inspirada en algunos lenguajes de progra- 46 mación y herramientas como Erlang, Clojure y Functional Java. Caracterı́stica Descripción Especificación de protocolo Especificación 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 búsqueda 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. Ejecución Perezosa La ejecución perezosa con una clase Delay basada en Clojure delay. Estructuras de Valor Estructuras de valor, simples, seguridad de thread, una variación inmutable de las es- tructuras abiertas de Ruby. Tabla 1.14: Caracterı́sticas de functional-ruby El ejemplo de código 1.26 a continuación 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 Código 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 Descripción Arrays Trabaja con arrays y cualquier implementación de Tra- versable Interfaz consistente Provee una interfaz consistente para funciones las cuales toman colecciones y callback, el primer parámetro es siempre una colección, y el segundo el callback. Los Callbacks siempre reciben los paráme- 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 extensión o librerı́a. Tabla 1.15: Caracterı́sticas de functional-php 48 El ejemplo de código 1.27 a continuación 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 Código 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 extensión de cualquier objeto incorporado en el lengua- je [39]. Caracterı́stica Descripción Colecciones Underscore provee algunos métodos los cuales ope- ran sobre colecciones. Arreglos Underscore provee algunas funciones las cuales tra- bajan exclusivamente sobre arerglos. Objetos Underscore provee varios métodos 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 código 1.28 a continuación ha sido tomado de la página 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 Código 1.28: Ejemplo de Underscore.js CAPÍTULO 2. DESARROLLO DE LA LIBRERÍA UTILI- TARIA FUNCIONAL Descripción 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 diseño 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 programación 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 enfocará en dos problemas puntuales, la escalabilidad cau- sada por sistemas altamente acoplados, y la concurrencia causada por el uso de objetos mutables. Descripción de la Solución El presente capı́tulo, describe el análisis, diseño, desarrollo y pruebas de la librerı́a 50 51 funcional construida sobre el lenguaje orientado a objetos Java. Dentro de las sec- ciones a continuación se describe tanto las limitaciones dellenguaje Java sobre Haskell, ası́ como algunas de las técnicas empleadas durante el desarrollo para superar algunas de estás limitaciones. Algunos de los objetivos claves del presente capı́tulo son: Identificar los módulos de Haskell a ser importados. Identificar las limitaciones encontradas al tratar de importar ciertos módulos a Java. Describir las convenciones tanto de documentación, como de estructura de código de la librerı́a. Describir las técnicas 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 continuación, lista las historias de usuario dentro del Product Backlog del proyecto: 52 Fase Historia de Usuario Prioridad Estimación Estado Análisis 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 actualización de versiones del lenguaje. 1 8 Hecho Diseño Como un usuario de la librerı́a, yo quiero tener acceso a la do- cumentación, para tener una re- ferencia del modo de uso de los métodos y clases definidos den- tro de la librerı́a. 2 8 Hecho Diseño Como un contribuidor de la li- brerı́a, yo quiero tener acceso al código 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- ción 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 Estimación 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 continuación: Historia de Usuario Estimación 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 actualización de versiones del lenguaje. 8 Evaluar las versiones de Java más utilizadas en la industrı́a. Identificar las limitaciones del lenguaje Java comparado con Haskell. Analizar la portabilidad de los módulos de Haskell a Java. Como un usuario de la librerı́a, yo quiero tener acceso a la do- cumentación, para tener una re- ferencia del modo de uso de los métodos y clases definidos den- tro de la librerı́a. 5 Documentar el código fuente. Generar la documentación. Subir la documentación a un re- positorio público. Tabla 2.2: Sprint #1 - Spring Backlog 54 Historia de Usuario Estimación Tareas Como un contribuidor de la li- brerı́a, yo quiero tener acceso al código fuente, para poder reali- zar contribuciones al proyecto. 3 Instalar y configurar un sistema de versionamiento. Subir el código 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- ción 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 integración con- tinua. Ejecutar las pruebas utilizando diferentes versiones de la JVM. Generar la documentación co- mo parte de la integración con- tinua. Tabla 2.3: Sprint #2 - Spring Backlog Historia de Usuario Estimación 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 ejecucción de pruebas de mu- tación. Automatizar la ejecucción de pruebas. Generar el reporte de pruebas como parte de la integración continua. Tabla 2.4: Sprint #3 - Spring Backlog Finalmente la figura a continuación 2.1, muestra el progreso realizado a lo largo de 55 todo el desarrollo del proyecto: Figura 2.1: Release Burndown 2.1 ANÁLISIS Antes de proceder con el diseño de la librerı́a funcional, se debe evaluar cada uno de los módulos escritos en Haskell, con el fin de analizar su portabilidad a Java. Adicionalmente se tomarán en cuenta las siguientes consideraciones: Compatibilidad con versiones anteriores de Java Development Kit (JDK). Limitaciones del lenguaje de programación 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 evaluará el porcentaje de uso de las diferentes versiones de Java. La figura 2.2 a continuación muestra el uso de las diferentes versiones de Java en la actualidad: 56 0.1 % 29 % 70 % 0.9 % JDK 8 JDK 7 JDK 6 JDK 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 programación funcional, todavı́a existe un alto porcentaje de uso de la versión 6 de Java. La librerı́a desarrollada será compatible con las siguientes versiones de Java: Java 6 Java 7 Java 8 Cualquier análisis realizado en las secciones a continuación, tomará en cuenta que la librerı́a debe ser compatible con versiones anteriores de Java a partir de la versión 6. 2.1.2 LIMITACIONES DEL LENGUAJE DE PROGRAMACIÓN JAVA Al comparar dos lenguajes de programación, pueden existir ventajas y desventa- jas de un lenguaje sobre otro, sin embargo debido a que se procederá a importar 57 módulos escritos en Haskell a Java, la presente sección se enfocará en describir las limitaciones de Java sobre Haskell las cuales serán consideradas en la fase de diseño 2.2 más adelante. Efectos Secundarios En Java no existe restricción para limitar efectos secundarios en un método a dife- rencia de Haskell, en donde una función debe especificar explı́citamente la presen- cia de efectos secundarios. 1 printMessage : : String −> IO ( ) 2 printMessage m = putStrLn m Fragmento de Código 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 Código 2.2: Efecto Secundario Implı́cito Como se puede observar en el fragmento de código 2.2, no existe ningún indicio en la firma del método printMessage de que tenga algún efecto secundario, a dife- rencia del fragmento de código 2.1 en donde el tipo del retorno de la función IO () indica que la función printMessage tiene algún efecto sobre la entrada y salida de información. Evaluación Perezosa Haskell es perezoso por defecto, es decir, no evalúa una expresión hasta que sea necesario, a continuación un ejemplo: 58 1 > take 3 [ 1 . . ] 2 [ 1 , 2 , 3 ] Fragmento de Código 2.3: Evaluación Perezosa - Haskell Como se puede observar en el fragmento de código 2.3, la función take toma co- mo argumento una lista infinita [1..] , sin embargo para mostrar el resultado en la pantalla, Haskell solo evaluará los 3 primeros elementos de la lista. Analizando el mismo ejemplo en Java, dado que el proceso de evaluación del len- guaje es estricto, evaluar una lista infinita resultarı́a en un error de memoria, como se puede observar