scieee AI-readable full text Open interactive document viewer

Aplicación Android para la gestión de la compra

Chica Oosterbaan, Rafael

Full text

Título: Aplicación Android para la gestión de la lista de la compra Autor: Rafael Chica Oosterbaan Director: Javier Béjar Alonso Titulación: Ingeniería Informática (EI) Centro: Facultad de Informática de Barcelona (FIB) Fecha: 9 de diciembre de 2014 Índice 1. Introducción................................................................................................................. 1 1.1. Motivación .................................................................................................................... 3 1.2. Objetivos del proyecto .................................................................................................. 4 1.2.1. Objetivo principal .................................................................................................. 4 1.2.2. Objetivos específicos ............................................................................................. 6 2. Estudio de tecnologías usadas ...................................................................................... 9 2.1. Dispositivo: Android ...................................................................................................... 9 2.2. Lenguaje de programación: Java ................................................................................. 10 2.3. Eclipse + ADT ............................................................................................................... 12 2.3.1. Eclipse .................................................................................................................. 12 2.3.2. ADT ...................................................................................................................... 13 2.4. Base de datos: Lenguaje SQL + MySQL WorkBench .................................................... 14 2.5. Servidor: Wamp........................................................................................................... 15 2.6. JDBC ............................................................................................................................. 16 2.7. Librerías externas usadas ............................................................................................ 17 2.7.1. ZXing .................................................................................................................... 17 2.7.2. Google Play Services ............................................................................................ 18 2.7.3. AIMA .................................................................................................................... 19 3. Estudio de algoritmos de inteligencia artificial ............................................................ 21 3.1. Sistema recomendador ............................................................................................... 22 3.2. Algoritmo de optimización de ruta ............................................................................. 29 4. Funcionalidades y requisitos de la aplicación .............................................................. 37 4.1. Estudio de antecedentes ............................................................................................. 37 4.1.1. Aplicaciones escogidas ........................................................................................ 38 4.1.2. Análisis de antecedentes ..................................................................................... 38 4.2. Funcionalidades ........................................................................................................... 48 4.3. Requisitos .................................................................................................................... 55 5. Diseño e implementación de la aplicación ................................................................... 59 5.1. Estructura de la aplicación .......................................................................................... 59 5.1.1. Capa de presentación .......................................................................................... 60 5.1.2. Capa de dominio el problema ............................................................................. 63 5.1.3. Capa de datos ...................................................................................................... 66 5.2. Estructura de la base de datos .................................................................................... 67 5.3. Implementación de la aplicación ................................................................................ 68 5.3.1. Capa de presentación .......................................................................................... 68 5.3.2. Capa de dominio ................................................................................................. 75 5.3.3. Capa de datos ...................................................................................................... 87 5.4. Diseño de la interfaz de la aplicación y estudio de la usabilidad ................................ 92 6. Validación y Tests ....................................................................................................... 97 6.1. Gestión de usuarios: Registro ..................................................................................... 98 6.2. Gestión de usuarios: Amistades ................................................................................ 100 6.3. Despensa virtual ........................................................................................................ 102 6.4. Gestión de listas de la compra: operaciones básicas ................................................ 103 6.5. Gestión de listas de la compra: compartir lista ......................................................... 105 6.6. Realizar compra ......................................................................................................... 107 6.7. Planificación de rutas y compra ................................................................................ 108 6.8. Sistema de recomendaciones ................................................................................... 110 7. Planificación y presupuesto ...................................................................................... 113 7.1. Diagrama de Gantt .................................................................................................... 114 7.2. Tareas realizadas ....................................................................................................... 114 7.3. Recursos humanos .................................................................................................... 118 7.4. Presupuesto del proyecto ......................................................................................... 119 8. Conclusiones ............................................................................................................ 121 8.1. Conclusiones del proyecto ............................................................................................. 121 8.2. Valoración personal del proyecto ............................................................................. 122 8.3. Futuras líneas de trabajo ........................................................................................... 123 9. Bibliografía .............................................................................................................. 127 10. Anexo .................................................................................................................... 129 1 1. Introducción Esta memoria refleja el trabajo de investigación, estudio y desarrollo de un prototipo de aplicación Android para gestionar un acto tan cotidiano como es hacer la lista de la compra. La aplicación incorpora inteligencia artificial para hacer un sistema recomendador de productos y un sistema que te calcula la ruta óptima entre supermercados para hacer la compra de la manera más eficiente posible, en cuanto a tiempo y dinero. Con lo cual, una vez hecha la lista de la compra, la aplicación te proporciona un mapa con la ruta, y una lista detallada con los productos que tienes que comprar en cada lugar. La aplicación es capaz de hacer esto porque guarda información en una base de datos de con diferentes productos, en qué supermercados se encuentran, y a qué precio estimado. Se considera una aplicación ‘social’ porque tanto la información proporcionada por la aplicación, como el precio de los productos, se calcula a través de las compras de los usuarios, con las ventajas y desventajas que eso supone y que en este documento se detallaran. Además de poder hacer la lista de la compra seleccionando entre los productos de la base de datos, los productos que has comprado alguna vez, y recomendaciones, el sistema te da la posibilidad de compartir estas listas de la compra entre usuarios amigos. Para ello, hay un sistema de relaciones de amistad entre los usuarios de la aplicación, similar al que tiene Facebook. Puedes buscar a los usuarios mediante su nombre de usuario, y mandarles una solicitud de amistad para que posteriormente te la acepten. 2 Lo que se ha implementado es un prototipo de la aplicación ya que no se dispone de datos reales en cuanto a precios y supermercados. Para hacer el sistema recomendador de productos se necesitaban muchos datos y que mucha gente usara la aplicación. Esto, por tiempo y recursos, no era posible. Por lo tanto, se ha partido de la base de datos de usuarios y productos ficticios. Como se puede ver, es un problema complicado de abordar, ya que se puede abordar de muchas maneras distintas. Además, como ya se ha comentado, está el problema añadido de la gran cantidad de datos que hay que manejar para que el prototipo sea realista. Hay muchos detalles a la hora de la implementación a tener en cuenta, como por ejemplo los algoritmos de IA que se usaran, o los diferentes tipos de diseño para hacer que la aplicación sea mucho más manejable por el usuario. Por lo tanto, esta memoria refleja el estudio y desarrollo de los siguientes conceptos en los que se profundizará más adelante:  Representación de la optimización de una tarea cotidiana: La mejor manera de representar esta optimización, en este caso, es con un mapa que te muestre la ruta más corta entre diferentes supermercados para hacer la lista de la compra. Para confeccionar este mapa, se han estudiado diferentes algoritmos de Inteligencia Artificial relacionados con la optimización para, posteriormente, escoger el más adecuado para el proyecto.  Extracción de información para poder crear sistema de recomendación: Para poder crear y representar un sistema de recomendación, se han estudiado varios algoritmos de Inteligencia Artificial relacionados con este ámbito para, posteriormente, escoger el que se creía más adecuado para el proyecto. Para ello, se ha estudiado el problema para averiguar de qué información disponemos, de qué información podríamos disponer, y como solucionar la falta de información, ya que como se explica en otro punto, se necesita una gran cantidad de información para este punto.  Tratamiento masivo de información: Se necesita una gran cantidad de información para que las recomendaciones extraídas por la inteligencia artificial del programa tenga validez y sea creíble. De otra forma, no se puede hacer un sistema de recomendación coherente. Estos tratamientos conllevan utilizar información inventada, ya que debido al ámbito del proyecto, no es posible utilizar información real de todos los supermercados, o congregar al suficiente número de usuarios para que la inteligencia artificial, en cuanto al cálculo de precios de los productos o al sistema de recomendación, sea válido.  Creación de una aplicación Android: Se han estudiado las tecnologías para poder desarrollar una aplicación Android, así como diferentes posibles estrategias en cuanto al diseño, tanto gráfico como interno, para poder hacer una aplicación eficiente en cuanto a términos, sobretodo, de usabilidad. 3  Estudio de tecnologías: Se han estudiado diferentes tecnologías para intentar escoger la que proporcione más eficiencia o la que sea más adecuada para el proyecto. Estas tecnologías se basan en tecnologías de desarrollo de una aplicación Android, conexiones eficientes entre el cliente y el servidor, y en la creación de Base de Datos adecuada para el problema que se plantea. En este documento se plantea en primer lugar el problema que queremos resolver, y el motivo que nos lleva a realizar esta aplicación, así como objetivos secundarios del proyecto también. A continuación, se definirán diversas herramientas y tecnologías que se han estudiado para llevarlos a cabo. Por otro lado, también se mostrará el diseño e implementación de la aplicación, así como decisiones tomadas durante el proyecto y su justificación, y ejemplos de los resultados obtenidos que justifiquen su buen funcionamiento. En este documento, también se incorporará un manual de usuario para que sea más sencillo de entender el funcionamiento de la aplicación desarrollada. Por último y como conclusión del documento, se explicaran diferentes utilidades y ampliaciones que se podrían llevar a cabo con el proyecto, así como la justificación de los objetivos conseguidos fijados inicialmente. 1.1. Motivación Hay diversos motivos para realizar este proyecto, pero uno de los más importantes es la investigación del mundo Android en plena efervescencia de los SmartPhones, la investigación en el campo de la inteligencia artificial de diferentes algoritmos de optimización y recomendación, y la posibilidad de resolver un problema, o agilizar una tarea tediosa que nos puede quitar bastante tiempo en el día a día. Como se ha comentado, una de las motivaciones del proyecto era resolver un problema cotidiano, y es que se pierde demasiado tiempo en hacer tareas rutinarias, cuando se podría emplear el tiempo en hacer otras cosas. La tarea escogida en este caso ha sido hacer la lista de la compra. Es algo que hace todo el mundo y es inevitable hacerlo, pero que requiere cierto tiempo. Muchas veces, con las prisas, nos olvidamos de algo y tenemos que volver a ir al supermercado, o simplemente lo compramos en el primer sitio que vemos el producto deseado, sin comparar precios, porque es lo más cómodo. En otros casos, vamos a un supermercado donde ni siquiera se encuentra el producto, y tenemos que perder aún más tiempo buscándolo en otro supermercado. 4 En plena efervescencia de todo el tema de redes sociales, en las que está todo el mundo conectado, y de aplicaciones móviles, es interesante aplicar estos conceptos a la hora de resolver el problema planteado. Por ello, la intención desde el principio era crear una aplicación en la que todo el mundo colaborara en cierta medida, asegurando el buen funcionamiento de ésta, y que no supusiera al usuario un gran esfuerzo utilizarla, ya que el objetivo principal es el de ahorrar trabajo en esta tarea cotidiana. Después de comparar diferentes aplicaciones con intenciones similares de diferentes supermercados, se ha llegado a la conclusión que faltaba un sistema unificado, que no englobara únicamente los productos del supermercado correspondiente a la aplicación. Además, ninguna de las aplicaciones descargadas tenía el componente social de compartir listas de la compra y agregar a tus amigos/conocidos, que es uno de los mayores atractivos de este proyecto. Aunque algunas de las aplicaciones estudiadas incorporan información de donde se sitúan los supermercados, y del precio de los productos, no incorporan una visión amplia que te permita comparar, ya que generalmente, las aplicaciones se basan en una misma cadena de supermercados, tal y como hemos comentado antes. Alguna de las aplicaciones estudiadas que no pertenecen a ningún supermercado concreto, no incorpora ni lista de precios, ni mapas con ubicaciones de los supermercados. Simplemente permiten hacer una lista de compra como si fuera un bloc de notas, o marcar el precio máximo a gastar. Por todo ello, las funcionalidades de este proyecto van más allá de las aplicaciones más conocidas dentro de este ámbito que hay ahora en el mercado, incorporando las funcionalidades que ya tienen pero desde otro punto de vista más global, e incorporando factores y funcionalidades nuevas que hacen que esta aplicación y este proyecto sean más atractivos. 1.2. Objetivos del proyecto 1.2.1. Objetivo principal El objetivo principal de este proyecto, tal y como se ha comentado anteriormente, surge de la necesidad de solucionar un problema cotidiano, que es la pérdida de tiempo y dinero a la hora de hacer la compra de productos necesarios en el hogar. A menudo, cuando haces la lista de la compra a papel y bolígrafo, se te olvidan productos. O simplemente, vas a la tienda y cuando llegas a casa te das cuenta que te has dejado algo. O, en otros casos, te encuentras con que lo compras en el primer sitio que encuentras cuando en realidad en otro supermercado cercano el precio para ese mismo producto es inferior. 5 En otros casos, si compartes piso, te puedes encontrar con que no se hace un reparto equitativo en los gastos de productos en común para la casa, o que cuando faltan varios productos, varios integrantes del piso, por un mal entendido, compran el mismo producto. Te encuentras con que un producto lo tienes dos veces, y otros productos que te faltan no eres consciente de que faltan. Por eso mismo el proyecto se basa en el desarrollo de una aplicación que te permita solucionar todos estos problemas. La aplicación te permite optimizar en tiempo y dinero la gestión de la lista de la compra, con funcionalidades como la de calcular la ruta óptima entre supermercados para gastar el menos tiempo y dinero posible, o con funcionalidades como la de compartir la lista de la compra para que todos los integrantes que puedan ver esa lista de la compra puedan saber qué productos faltan, y qué persona ha comprado cada producto a la hora de hacer cuentas para un reparto equitativo. Así, el sistema incorpora estas funcionalidades:  Gestión de usuarios. El usuario es capaz de crear su propia cuenta, de mandar solicitudes de amistad a usuarios conocidos buscándoles en un buscador a partir de su nombre de usuario, de aceptar solicitudes que le envíen, y de ver qué usuarios tiene agregados. Gracias a esto, posteriormente podrá compartir listas de compra con usuarios amigos.  Creación de listas de compra y modificación de las mismas. Los usuarios son capaces de crear listas de compras a través de listas de productos que se le ofrecen. Estas listas de productos pueden incorporar todos los productos, productos comprados anteriormente por el usuario, o recomendaciones. Además, se incorpora un buscador de productos. Por otra parte, estas listas de compra se pueden consultar y modificar. Cualquier usuario con el que se comparta la lista puede ver que productos quedan pendientes de comprar, y puede añadir productos, y sólo el usuario creador puede marcar la lista como finalizada, para que no se puedan añadir más productos ni marcar los que ya hay como comprados.  Recomendaciones de productos. Como se ha comentado anteriormente, a la hora de hacer la lista de la compra, al usuario se le ofrecerán productos recomendados por su afinidad con otros usuarios que suelen comprar cosas parecidas. Estas recomendaciones se reciben tanto cuando se está haciendo la lista de la compra como cuando abres la aplicación, en un apartado específico para las recomendaciones.  Calculo de la ruta óptima. Una vez está una lista creada, cualquier usuario con quién es compartida la lista puede calcular la ruta óptima para comprar los productos pendientes aún de comprar de la lista. La lista de la compra te muestra un mapa con la ruta más óptima entre supermercados, y una lista detallada de qué productos tienes que comprar en cada uno de los supermercados, y a qué precio están. 12 2.3. Eclipse + ADT Una vez escogimos el sistema operativo y dispositivo para implementar la aplicación, el siguiente paso era escoger el entorno de desarrollo de ésta. 2.3.1. Eclipse Eclipse es un programa informático que proporciona herramientas de programación de código abierto multiplataforma para el desarrollo de aplicaciones. Ésta plataforma es un entorno de desarrollo integrado (IDE). Un IDE es un software que proporciona facilidades a los programadores de software. Normalmente un IDE consiste en un editor de texto, y herramientas de compilación, intérpretes, así como herramientas para debugar la aplicación. Así, Eclipse no sólo proporciona un editor de texto, sino herramientas de compilación en tiempo real, intérpretes, herramientas para debugar la aplicación, herramientas para refactorización, herramientas para completar código… Gracias a todas estas características, es mucho más sencillo trabajar con Eclipse que con un editor de texto normal, aunque también sea posible. Además, dispone de resaltado de sintaxis, lo que lo hace mucho más ameno para encontrar las partes del código que buscas. Por otra parte, dispone de pruebas unitarias con JUnit, que es un conjunto de bibliotecas utilizadas en programación para hacer pruebas unitarias de aplicaciones Java. Así, permite realizar la ejecución de clases Java de manera controlada para poder evaluar el funcionamiento de cada uno de los métodos de la clase, y así comprobar que se comporta como se espera. Eclipse dispone también de control de versiones con CVS, de manera que se puede mantener el registro de todo el trabajo y los cambios en los ficheros que forman un proyecto. Eclipse también proporciona herramientas para la realización de tareas mecánicas y repetitivas, normalmente durante la fase de compilación y construcción. Por lo tanto, mediante la integración con Ant (Apache Ant), se automatiza la compilación. Debido a que Ant está desarrollado en Java, es más apropiado para la construcción de proyectos Java. Es otra de las razones para haber escogido Eclipse para desarrollar el proyecto. Otra de las características de Eclipse es que proporciona asistentes para la creación de proyectos, clases, tests,… De esta manera, es mucho más sencillo y fácil que hacerlo todo mediante un editor de texto normal. Aunque con él se pueden desarrollar aplicaciones basadas en otros lenguajes de programación, Eclipse está escrito en Java, lo que lo hace más atractivo aún para escogerlo como entorno de desarrollo. 13 Por otra parte, Eclipse incluye JDK (Java Development Kit), que facilita la programación de una aplicación en Java. JDK es un entorno de desarrollo que incluye herramientas para desarrollar y testear programas escritos en Java y ejecutarlos en plataforma Java. La versión usada para compilar el proyecto es JDK 1.6. Así, para el proyecto hemos usado el SDK de Eclipse. SDK es “Software development kit”, que es un conjunto de herramientas software que permiten el desarrollo de aplicaciones para cierto framework, hardware, sistema operativo, o plataforma similar. Para finalizar, Eclipse dispone de muchas versiones. La versión de Eclipse que se ha usado es el SDK de Eclipse Kepler, una de las últimas versiones de la aplicación (4.3), lanzada en Junio de 2013. 2.3.2. ADT ADT son las siglas de Android Development Toolkit. Es un plugin para el IDE de Eclipse que está diseñado para proporcionar al usuario un potente e integrado entorno de desarrollo en el que construir aplicaciones Android. ADT extiende las capacidades de Eclipse para proporcionarte una manera rápida para crear nuevos proyectos Android y crear la interfaz de la aplicación. Además, añade paquetes y librerías basados en Android Framework API. Por otro lado, proporciona herramientas Android SDK para poder debugar las aplicaciones y poder exportar los .apk para poder probar y distribuir tu aplicación. Es altamente recomendado usar ADT con Eclipse para desarrollar aplicaciones Android, ya que dispone de mucha información en internet en caso de errores o dudas. Es la manera más rápida de empezar a crear aplicaciones Android. Esto es debido a que proporciona una configuración guiada de los proyectos, así como integración de herramientas, editores XML personalizados y un panel de salida para debugar la aplicación. Hay que destacar que ADT proporciona también “Android SDK Manager”, de manera que con este plugin es mucho más fácil instalar las dependencias o versiones que te hagan falta para poder desarrollar la aplicación. Por otra parte, en caso de no disponer dispositivo Android, también ofrece el AVD (Android Virtual Device) Manager. Con él, aunque no dispongamos de un dispositivo Android, podemos probar la aplicación en el ordenador. Esto último no es muy recomendable. Aunque te lo proporcione la fuente oficial de desarrolladores de Android, en la primera parte del proyecto se usó y dio bastantes 14 problemas. Algunos de los problemas que proporcionó fueron el tiempo de ejecución, o la imposibilidad de ver mapas o usar la cámara. Tardaba mucho en iniciarse y en ejecutarse cualquiera de las tareas del programa y, cómo se ha comentado, algunas de las características de la aplicación no se podían testear. Por estas razones, finalmente se decidió prescindir del AVD y testear la aplicación en el dispositivo Android mencionado anteriormente. La versión Android SDK Tools utilizada es la 23.0.4, que permite usar la API nivel 19, que corresponde a una versión 4.3 de Android. El proyecto está configurado para que compile desde API nivel 9 (que corresponde a una versión de Android 2.3 aproximadamente) hasta 19. Aun así, y como se detalla en la parte de la memoria que habla de requisitos, únicamente se ha testeado profundamente en una versión de Android 4.3. 2.4. Base de datos: Lenguaje SQL + MySQL WorkBench Una vez decidido el entorno de desarrollo y el lenguaje de programación, la siguiente tarea consistía en escoger cómo íbamos a guardar y a representar los datos. Hay dos grandes tipos de bases de datos: relaciones y no relacionales. Una base de datos relacional es una base de datos que cumple con el modelo relacional, que es el más utilizado para implementar bases de datos ya planificadas. Se escogió este tipo de base de datos para la implementación del proyecto porque permiten establecer interconexiones y relaciones entre los datos, guardados en tablas, y a través de dichas conexiones podemos relacionar los datos de ambas tablas. En cuanto a las bases de datos no relacionales, se han ido haciendo populares a medida que pasan los años. Permiten una estructura de almacenamiento más versátil, y una alta escabilidad y versatilidad, pero por el contrario tienen ausencia de esquema en los registros de datos. Había razones para decantarse por cualquiera de los dos tipos, pero finalmente, debido a que conceptualmente los datos en nuestra aplicación están relacionados (productos que están en supermercados, que visitan los usuarios…), parecía una buena opción utilizar una base de datos relacional. Una vez escogido el tipo de datos, había que escoger la base de datos que usaríamos para diseñar y crear la base de datos. Al final, esta elección acabó siendo MySQL Workbench. MySQL Workbench es una herramienta visual de diseño de bases de datos que integra desarrollo de software, administración de bases de datos, diseño de bases de datos, creación y mantenimiento para el sistema de bases de datos MySQL. 15 MySQL el sistema de gestión de bases de datos relacional que hemos usado. El hecho de que varios lenguajes de programación, Java incluido, permitan a las aplicaciones acceder a una base de datos MySQL era una baza importante para escoger este tipo de base de datos también. De esta manera, con MySQL Workbench, hemos diseñado y creado el esquema de base de datos, además de arrancar la base de datos a nivel local. MySQL Workbench incorpora editor de SQL, modelado de datos, administración de la base de datos para iniciarla o parar instancias de la base de datos, así como su configuración. La versión con la que se ha trabajado a lo largo del proyecto es con MySQL Workbench 6.0 CE y con MySQL Server 5.6. En cuanto al lenguaje para relacionarse con las bases de datos, el estándar para bases de datos relacionales es el SQL. Por lo tanto, fue el escogido sin plantearse ninguna otra posibilidad. SQL es un lenguaje declarativo de acceso a bases de datos relacionales que permite especificar diferentes tipos de operaciones en ellas. Algunas características son, por ejemplo, el manejo del álgebra y el cálculo relacional para efectuar consultas para recuperar de forma sencilla la información necesaria. Otra de las ventajas del lenguaje SQL es la integridad: incluye comandos para especificar las restricciones de integridad que deben cumplir los datos almacenados. Además, se pueden definir vistas y transacciones y dispone de varios tipos de datos que se pueden guardar, desde un número o un carácter alfanumérico hasta una fecha. Como desventaja, tiene que el orden de ejecución interno en una sentencia puede afectar la eficiencia, por lo que a veces es necesaria una optimización. A veces, el uso de índices acelera una instrucción de consulta pero realentiza la actualización de datos. Estos detalles hay que tenerlos en cuenta dependiendo del uso de la aplicación. Por otra parte, la optimización difiere en cada motor de base de datos y depende de muchos otros factores. 2.5. Servidor: Wamp Una vez escogida la base de datos, únicamente quedaba incorporarla a un servidor. El servidor escogido es un servidor local WAMP. Se decidió que el servidor fuera local porque, al ser un prototipo de aplicación, creímos que escoger otro tipo de servidor podía salirse del ámbito del proyecto y restar tiempo en objetivos más primordiales. Wamp utiliza Windows como sistema operativo, Apache como servidor web, MySQL como gestor de bases de datos, y luego puede usar diferentes lenguajes de programación. 16 ¿Por qué WAMP y no otro tipo de servidor local? Desde un principio, por motivos de sistema operativo disponible para realizar el proyecto, se decidió desarrollarlo todo en Windows. Esto ya descartaba otros servidores locales como LAMP. Por otra parte, el servidor WAMP es bastante completo en cuanto a funcionalidades y es muy fácil de usar. Con unos pocos clics, el usuario es capaz de manejar los servidios Apache y MySQL, así como arrancar el servidor o pararlo, o manejar la configuración del servidor, así como disponer de acceso a los logs. Esta facilidad de uso fue la que hizo que nos decantaramos por WAMP y no por cualquier otro servidor. 2.6. JDBC Las siglas JDBC significan Java Database Connectivity. Es una API que permite la ejecución de operaciones sobre bases de datos desde el lenguaje de programación Java, sin tener en cuenta el sistema operativo desde el que se ejecuta o la base de datos a la cual se accede, aunque usando el dialecto SQL del modelo de base de datos que se utilice. La API es una colección de interfaces Java y métodos de gestión de manejadores de conexión hacia un modelo específico de base de datos. Una vez teníamos la base de datos, el servidor, y el entorno de desarrollo, lo único que quedaba es conectar cliente y servidor; conectar la aplicación Android con la base de datos desarrollada. Para ello, escogimos JDBC. Una vez barajadas distintas maneras de conectarse a la base de datos, se escogió JDBC porque es una interfaz Java, que es el lenguaje que utilizamos para el proyecto, y eso hacía más sencilla la integración con el proyecto. Por otra parte, para usar una base de datos particular, el usuario ejecuta su programa con la biblioteca de conexión apropiada al modelo de su base de datos, y de esta manera establece una conexión. Una vez realizada dicha conexión, se puede realizar cualquier operación con la base de datos de la que se disponga permiso: desde consultar alguna tabla, hasta actualizar, crear, modificar e incluso barrar registros o tablas de la base de datos. Por otra parte, también se pueden ejecutar procedimientos almacenados en la base de datos. Lo más interesante que ofrece JDBC es el paquete “java.sql”. Este paquete incluye clases muy útiles para trabajar con bases de datos. Por ejemplo, incluye manejadores de Driver, clases para establecer conexiones, clases para ejecutar sentencias SQL y mandar las peticiones a la BBDD, o clases para almacenar el resultado de una consulta cómodamente. 17 Todo ello hizo que nos decantáramos por JDBC como conector cliente-servidor. 2.7. Librerías externas usadas Como se ha comentado, una de las ventajas de Java es el uso de librerías con las cuales se puede reutilizar código. Estas librerías pueden ser internas, cómo las que te proporcionan métodos para trabajar con listas, o pueden ser externas, creadas por algún otro usuario. En este apartado hablaremos de éstas últimas, ya que las primeras no tienen mayor relevancia salvo en implementación. Hemos utilizado tres librerías externas para implementar algunas de las funcionalidades del proyecto: ZXing, Google-play-services y AIMA. 2.7.1. ZXing Existen algunas particularidades a la hora de escanear un código de barras. Es algo que podríamos haber implementado por nosotros mismos, pero probablemente habría supuesto horas y esfuerzo para realizar otro proyecto. Aun así, la funcionalidad de poder escanear un código de barras y de ahí obtener información del producto parecía muy interesante. De esta manera, se optó por usar la librería externa ZXing modificándola para que actuara como a nosotros nos interesaba al leer un código de barras. ZXing permite es una librería de código abierto que permite al usuario escanear tanto códigos de barra 1-D como 2-D. En nuestro caso, nos interesaba el tipo de código de barras 1-D, que es el que se usa en libros, ropa, DVDs y otros muchos productos comerciales cómo el caso que nos ocupa: comida y los diferentes productos de un supermercado. La librería soporta integración con el escáner de códigos de barra vía Intent, que es cómo lo hacemos en nuestra aplicación, tal y como se detalla más adelante. Los detalles de los cambios implementados en la librería son mínimos, pero se detallan en la sección de Diseño e implementación de la aplicación. Es una de las librerías más conocidas para este tipo de aplicaciones, y de las más usadas. Su alta usabilidad y documentación disponible a la hora de integrarlo con diferentes sistemas, hizo que nos decantáramos por esta librería para implementar la funcionalidad mencionada. 18 2.7.2. Google Play Services La librería de Google Play Services tiene muchas propiedades y características que pueden hacer más interesantes las aplicaciones desarrolladas por el usuario, debido a la potencia de Google. Desde Google+, a mapas, a Drive, son algunos de los productos de Google que se pueden utilizar gracias a esta librería. En nuestro caso, hemos usado la librería para la integración de mapas en la aplicación, así como para poder obtener fácilmente la localización del usuario. Una de las ventajas de Google Play Services es que está totalmente integrado con el sistema operativo de Android, con lo cual en un principio parecía ser fácil de integrar en la aplicación, además de disponer de una gran documentación sobre la librería debido a que pertenece a una de las empresas más grandes del mundo. Las librerías de las que dispone proporcionan al usuario herramientas para implementar la funcionalidad que el usuario requiera de manera rápida y sencilla. Google Play Services contiene las interfaces con los servicios individuales de Google, y le permite obtener la autorización de los usuarios para acceder a estos servicios con sus credenciales. Además, contiene APIs que le permiten resolver cualquier problema en tiempo de ejecución. Otra de las ventajas es que no supone un impacto negativo en el tamaño del archivo de la aplicación, debido a sus características. Además, no hay que preocuparse por la compatibilidad de los dispositivos, ya que las actualizaciones de los servicios de Google Play se distribuyen automáticamente por la tienda Google Play y las nuevas versiones de la biblioteca cliente se entregan a través del Administrador de Android SDK. Para finalizar, destacar que la parte de la biblioteca Google Play Services que hemos usado es la versión 2 de Google Maps Android API. Esta API te permite explorar el mundo con mapas proporcionados por Google, identificar localizaciones añadiendo marcadores al mapa, pintar líneas sobre el mapa, añadir imágenes, entre otras cosas. La capacidad de marcar localizaciones y pintar líneas sobre el mapa es lo que a nosotros nos interesaba desde un principio para poder señalar los supermercados y pintar la ruta óptima desde la posición actual en el mapa. 19 2.7.3. AIMA AIMA es una librería externa usada para la implementación del sistema que calcula la ruta óptima entre supermercados teniendo en cuenta tanto el precio de los productos pendientes a comprar como la distancia que hay hasta los supermercados. AIMA contiene librerías que implementan diferentes algoritmos, tanto de búsqueda heurística como búsqueda local. En otro apartado de la memoria se detalla concretamente el algoritmo usado para la funcionalidad definida. Aunque la librería te proporciona herramientas para implementar los algoritmos necesarios, eres tú quién tiene que darle los diferentes elementos para que pueda actuar. Estos diferentes elementos y propiedades se definen según el problema y el algoritmo a utilizar, definidos más adelante. De esta manera, AIMA te permite definir problemas de búsqueda y solucionarlos. Implementa algoritmos no informados de búsqueda como BFS, DFS, IDS. Además también implementa algoritmos de búsqueda heurística como A* o IDA*. Por otra parte, y más importante porque es la que usamos, implementa algoritmos de búsqueda local como Hill Climbing o Simulated Annealing. Una de las ventajas de la librería es que usa la generalidad para separar la representación del problema de los algoritmos de búsqueda, lo que hace más sencilla la experimentación de diferentes algoritmos y la implementación. El hecho de haber usado ésta librería antes es la que nos llevó a usarla también en este proyecto. 20 21 3. Estudio de algoritmos de inteligencia artificial En este apartado se detalla una de las bazas más importantes del proyecto realizado: la incorporación de inteligencia artificial al sistema. En este capítulo se explican distintos algoritmos de inteligencia artificial que podríamos haber escogido para la aplicación, entrando en más profundidad en los algoritmos escogidos y en cómo funcionan. Dividimos este capítulo según las funcionalidades para las que son usadas los algoritmos: sistema recomendador, algoritmo de optimización de ruta. En cuanto a otras partes de inteligencia artificial incorporada en el sistema, como por ejemplo el cálculo aproximado del precio de un producto, se detalla en “Diseño e implementación de la aplicación”, ya que no es tan relevante ni disponen de un algoritmo concreto. 28 Por lo tanto, por definición del problema, nosotros nos basamos en cuánto se parecen los usuarios. En caso de que se parezcan, las recomendaciones saldrán de entre los productos que el usuario actual no ha comprado y el usuario al que se parece sí. Por lo tanto, nuestro algoritmo se resume en:        En términos generales, nuestro algoritmo dispone de información de los productos comprados por los usuarios y el número de veces que ha sido comprado. A continuación, se calcula la distancia del usuario actual con el resto de usuarios. Una vez tenemos todas las distancias del usuario actual con el resto de usuarios calculadas, procedemos a coger los K usuarios que más se parecen. De entre la lista de usuarios parecidos, se cogen todos los productos que han comprado los usuarios junto a sus frecuencias y se ordenan de manera descendente por frecuencia de compra del producto. De entre todos estos productos, se escogen las N recomendaciones más frecuentes. Para añadir variedad a las recomendaciones, del resto de productos recomendables se añade un subconjunto de tamaño M al azar. De esta manera, obtenemos N+M recomendaciones. Los detalles de los parámetros escogidos y la forma de calcular la distancia y de obtener los usuarios más parecidos y las recomendaciones se detalla en el capítulo “Diseño e implementación de la aplicación”. 29 3.2. Algoritmo de optimización de ruta Toda la información de este capítulo está sacada de los libros comentados en la bibliografía. En este apartado describimos algunos algoritmos interesantes a la hora de implementar la funcionalidad de optimizar una ruta que incluye nuestra aplicación. Finalmente, se justifican las razones que han llevado a escoger Hill Climbing como algoritmo principal para cubrir esta necesidad de la aplicación. Como se ha comentado en la memoria, hemos usado la librería AIMA para la implementación del algoritmo que cumple con esta funcionalidad. Esta librería java dispone de algoritmos de búsqueda no informada, así como algoritmos de búsqueda heurística y búsqueda local. Algoritmos de búsqueda no informada: Estos algoritmos, también conocidos como algoritmos de búsqueda ciega, no tienen en cuenta el coste de la solución durante la búsqueda. Su funcionamiento es sistemático, siguiendo un orden de nodos fijo establecido por la estructura del espacio de búsqueda. Por lo tanto, son algoritmos de ámbito general y que se pueden aplicar en cualquier circunstancia, sin tener información previa del problema a resolver. Otra de las desventajas es que son algoritmos exhaustivos, de manera que se puede dar el caso de que acaben recorriendo todos los nodos del problema para hallar la solución. Debido a ello, el coste puede ser prohibitivo para la mayoría de los problemas reales como el que nos ocupa. Los principales ejemplos de este tipo de algoritmo son el de anchura prioritaria, el de profundidad prioritaria, y el de profundidad iterativa. Decidimos descartar este tipo de algoritmos porque, como se ha dicho, no tienen en cuenta el coste de la solución. Nuestro objetivo es encontrar una solución óptima al problema, no cualquier solución. En caso de emplear este tipo de algoritmos nos valdría cualquier supermercado para comprar los productos pendientes, sea cual sea la distancia y el precio de los productos. Por lo tanto, al no ser éste el objetivo de la aplicación, descartamos este tipo de algoritmos. Algoritmos de búsqueda heurística: Ya hemos comentado las carencias de los algoritmos de búsqueda no informada. En casos en que el espacio de búsqueda sea grande, el coste temporal es una función exponencial del tamaño de la entrada. Para intentar reducir este tiempo búsqueda lo que hacen los algoritmos de búsqueda heurística es intentar hacer intervenir conocimiento sobre el problema que queremos resolver dentro del funcionamiento del algoritmo de búsqueda. 30 Una de las particularidades es que este conocimiento es propio de cada problema. Por lo tanto se pierde generalidad, pero se gana eficiencia. Aun así, el problema que tiene este algoritmo es también el tamaño de los problemas. Estos algoritmos funcionan correctamente hasta cierto tamaño, pero hay un conjunto de problemas en las que la búsqueda del óptimo es imposible por el tamaño de su espacio de búsqueda o por la imposibilidad de encontrar información que ayude en ella. Algunos de estos algoritmos son A* o IDA*. La idea de estos algoritmos es que usan el cálculo del coste de los caminos explorados para saber qué nodos vale la pena explorar antes. De esta manera, el orden de visita de los estados de búsqueda está basado en el coste, y no en su posición en el grafo de búsqueda. Una de las desventajas es que en el peor de los casos también se acaba recorriendo todo el grafo, con lo cual, si no tenemos una función heurística que calcule el coste suficientemente buena, puede que sea igual de ineficiente que los anteriores. Debido a la gran cantidad de supermercados y productos que puede haber, pese a poner filtros para no tener que ir a un supermercado muy lejano, este espacio de búsqueda puede llegar a ser muy grande. Esta es la razón por la que se han descartado también este tipo de algoritmos. Aun así, es importante explicar en qué consiste el algoritmo A* porque es uno de los más utilizados. El objetivo de este algoritmo no es solo llegar lo más rápidamente a la solución, sino encontrar la de menor coste. Por lo tanto, tenemos que tener en cuenta todo el camino y no solo el camino por recorrer. Este algoritmo consiste en visitar el camino de menor coste primero. Para ello, hay que guardar tanto el coste del camino realizado como el la función heurística que calcula el posible coste del nodo actual al siguiente. El algoritmo sólo acaba cuando se extrae una solución de la cola. Es posible que en cierto momento ya haya en la estructura de nodos abiertos nodos solución, pero hasta que no se hayan explorado los nodos por delante de ellos, no podemos asegurar que realmente sean soluciones buenas. Siempre hay que tener en mente que los nodos están ordenados por el coste estimado del camino total, si la estimación es menor es que podrían pertenecer a un camino con una solución mejor. Cuanto más cercana al coste real sea la función heurística, mayor será el comportamiento en profundidad del algoritmo, pues los nodos que aparentemente están más cerca de la solución se explorarán antes. Si esta información deja de ser fiable, el coste del camino ya explorado hará que otros nodos menos profundos tengan un coste total mejor, y por lo tanto se abrirá la búsqueda en anchura. A continuación definimos el algoritmo: 31     El tratamiento de repetidos en este algoritmo se realiza de la siguiente forma. Si es un nodo repetido que está en la estructura de nodos abiertos y su coste es menor, sustituimos el coste por el nuevo, y esto puede variar su posición en la estructura de nodos abiertos. Por el contrario si el coste es igual o mayor nos olvidamos del nodo. Si es un nodo repetido que está en la estructura de nodos cerrados y su coste es menor, reabrimos el nodo insertándolo en la estructura de abiertos con el nuevo coste. No hacemos nada con sus sucesores, ya se abrirán si hace falta. En caso de que el coste sea mayor o igual, nos olvidamos del nodo. En rutas cortas, este algoritmo es bastante rápido. Aun así, y como se ha comentado, debido a la cantidad de información que se puede llegar a tratar, se tomó la decisión de hacer un algoritmo de búsqueda local. Algoritmos de búsqueda local: Los algoritmos antes mencionados tienen el problema de que el planteamiento de la búsqueda de un camino en un espacio de estados puede ser demasiado artificial, o el tamaño de búsqueda es demasiado grande y nos conformamos con una solución que podamos considerar buena. En este tipo de problemas puede ser relativamente fácil hallar una solución inicial, aunque no sea demasiado buena. De esta manera, en este tipo de algoritmos nos planteamos el problema como una búsqueda dentro del espacio de soluciones, en lugar de encontrar caminos. Este es exactamente el caso que nos ocupa en la funcionalidad de encontrar la ruta óptima en cuanto a distancia entre supermercados y precio de productos pendientes de la lista de la compra. Este tipo de algoritmos también permiten iniciar la búsqueda desde un espacio de soluciones no válidas, suponiendo que la búsqueda nos llevará al final al espacio de soluciones. 32 En nuestro caso partimos del espacio de soluciones y buscamos una solución mejor. Eso es porque en nuestro caso cualquier situación puede ser una solución válida. Desde no asignar ningún producto a ningún supermercado a asignar todos los productos o un subconjunto de ellos a diferentes supermercados. El cómo se ha implementado se detallará en la sección de diseño e implementación. La idea de este algoritmo es partir de una solución, y mediante operaciones sobre el espacio de posibles soluciones, ayudar a mejorar esta solución. El coste de estas operaciones no es relevante ya que lo que nos importa es la calidad de la solución. De esta manera, en este tipo de algoritmos se parte de un estado inicial, que en este caso será una solución completa. Un problema adicional es cómo hallar esta solución inicial con un coste relativamente bajo. Este tipo de algoritmos incorpora operadores de cambio de las solución, y una función de calidad. Esta función de calidad, función heurística, nos mide lo buena que es una solución. De esta manera nos permite guiar la búsqueda, teniendo en cuenta que este valor no nos indica cuanto falta para encontrar la solución que buscamos ya que no representa un coste, sino que es una manera de comparar las soluciones vecinas e indicarnos la dirección que lleva a soluciones mejores. El saber cuándo hemos acabado con la búsqueda depende del algoritmo, que tendrá que decidir cuando ya no es posible encontrar una solución mejor. Esto implica que no tenemos un estado final definido. Dos de los algoritmos básicos de búsqueda local son Simulated Annealing y Hill Climbing, que describimos a continuación.  Simulated Annealing Este algoritmo está inspirado en un fenómeno físico que se observa en el templado de metales y en la cristalización de disoluciones. Todo conjunto de átomos o moléculas tiene un estado de energía que depende de cierta función de temperatura. A medida que se enfría, el sistema pierde energía hasta que se estabiliza. Durante este enfriamiento controlado, la energía del conjunto de átomos no disminuye de manera constante, sino que a veces la energía total puede ser mayor que en un momento inmediatamente anterior. En esto se basa el algoritmo de Simulated Annealing. El siguiente nodo a explorar no es siempre el mejor descendiente, sino que se escoge aleatoriamente en función de los valores de unos parámetros entre todos los descendientes, tanto los buenos como los malos. Una de las grandes ventajas de este algoritmo es que no hay que generar todos los sucesores de un nodo, sino que basta con elegir un sucesor al azar y decidir si continuamos por él o no. El algoritmo es el que se detalla a continuación. 33 Algoritmo Simulated Annealing Partimos de temperatura inicial Mientras la temperatura no sea cero hacer Para “un numero prefijado de iteraciones” hacer Estado_nuevo := genera_sucesor_al_azar(estado_actual) Incremento_energia := f(estado_actual) – f(estado_nuevo) Si incremento_energia > 0 entonces Estado_actual := estado_nuevo. Sino Con probabilidad e_E/T : := estado_actual := estado_nuevo Fin Fin Disminuimos la temperatura Fin Como vemos, la estrategia de enfriamiento para saber qué nodos escoger como posibles caminos a seguir, así como el número de iteraciones, son los que deciden el comportamiento del algoritmo. El mayor problema de este algoritmo es la complejidad a la hora de determinar los valores de los parámetros, y que requiere una importante labor de experimentación que depende de cada problema, ya que estos parámetros varían con el dominio del problema e incluso con el tamaño de la instancia del problema. Este algoritmo funciona mejor en los casos en los que encontrar una heurística discriminante es difícil. Este no es nuestro caso ya que tenemos muy claro las propiedades del problema en las que basarnos para calcular esta función heurística: precio de los productos y distancia entre supermercados. Estos motivos, y las ventajas del Hill Climbing que explicamos a continuación, son los que nos han llevado a decantarnos por éste último en vez de Simulated Annealing. 34 3.2.1. Algoritmo utilizado: Hill Climbing Igual que Simulated Annealing, es un algoritmo de búsqueda local, y pertenece a la familia de algoritmos “branch and bound” (ramificación y poda). Esta familia de algoritmos limita el número de elementos que guardamos como pendientes de xplorar olvidando los que no parecen prometedores. Estos algoritmos permiten mantener una memoria limitada, ya que pueden despreciar gran parte del espacio de búsqueda. Por la misma razón, se arriesgan a no hallar la mejor solución, ya que quizás se encuentra en el espacio de búsqueda descartado. En nuestro caso, no nos es necesario encontrar la mejor solución. Necesitamos una buena solución que a la vez sea eficiente. Si el usuario tiene que esperar mucho tiempo para obtener la ruta óptima entre supermercados para saber qué producto tiene que comprar en cada uno, la aplicación pierde usabilidad. Eso es algo que no nos podemos permitir. Debido a que es más rápido que Simulated Annealing porque no explora estados un poco peores pero que pueden llevar a mejores soluciones, y más fácil de implementar ya que no contiene parámetros que varían en función del problema, hemos decidido implementar Hill Climbing. Existen varias variantes que tienen sus ventajas y sus inconvenientes. Una de las variantes, la simple, consiste en elegir siempre el primer operador que suponga una mejora respecto al nodo actual, ignorando las demás. La ventaja es que es más rápido que explorar todas las posibilidades, pero la probabilidad de no alcanzar las mejores soluciones también es más alta. Por ello, la variante usada no es ésta, sino “steepest ascent hill climbing”. Esta variante expande todos los posibles descendientes de un nodo y elige el que suponga la máxima mejora respecto al nodo actual. De esta manera, este algoritmo supone que la mejor solución la encontraremos a través del sucesor que mayor diferencia tenga respecto a la solución actual. Una de las ventajas es que la utilización de memoria es mínima, ya que solo tenemos en cuenta el mejor nodo. Se pueden hacer versiones que guarden caminos alternativos y así permitir una vuelta atrás, pero en nuestro caso no es necesario, si además de una buena solución lo que buscamos es eficiencia. Este algoritmo acaba en el caso que no se encuentre ningún nodo accesible mejor que el actual. Dado que no utilizamos memoria, será imposible reconsiderar nuestras decisiones. Esta circunstancia es probable ya que la función heurística utilizada tiene óptimos locales y depende de por dónde empezamos a buscar encontrar un mínimo local u otro. Existen variaciones que exploran los N mejores nodos, pero en nuestro caso, por razones de eficiencia, hemos decidido quedarnos con el algoritmo general de Hill Climbing que se detalla a continuación. 35 Algoritmo Hill Climbing Estado_actual := estado_inicial Fin := falso Mientras no fin hacer Hijos := generar_sucesores (estado_actual) Hijos := ordenar_y_eliminar_peores(hijos, estado_actual) Si no vacio?(hijos) entonces Estado_actual := escoger_mejor(hijos) Sino Fin := cierto Fin Fin De esta manera, para implementar este algoritmo necesitamos crear un estado inicial. De cómo se cree este estado inicial dependerá de la solución final del algoritmo, tal y como hemos visto. La idea en nuestro caso es crear una solución inicial suficientemente buena pero con un coste no demasiado elevado. Por otra parte, para este algoritmo también necesitamos generar los sucesores del estado actual. Esto se hace a través de operadores que modifiquen el estado actual. Otra de las características de este algoritmo es el hecho de escoger el mejor de los hijos. Esto se hace a través de la creación de una función heurística que le dé cierto valor a cada uno de los estados para saber cuál es el mejor. Todos los detalles de la implementación de este algoritmo en nuestro proyecto se detallan en el capítulo de diseño e implementación de la aplicación. Ahí se explica y se justifica por qué hemos escogido crear el estado inicial como lo hemos hecho, cuales son los operadores seleccionados para generar los sucesores de cada estado, y cuál es la función heurística que calcula el coste, además de otros detalles de la implementación. 36 37 4. Funcionalidades y requisitos de la aplicación En esta sección se determinan las funcionalidades de la aplicación y los detalles sobre en qué entorno puede ejecutarse para su correcto funcionamiento. Es decir, los requisitos. Antes de ello, se expone el estudio que se ha hecho sobre los antecedentes: aplicaciones similares que están disponibles para el uso de todo el mundo en Google Play. Con el estudio de estos antecedentes, se justifican las funcionalidades desarrolladas finalmente. 4.1. Estudio de antecedentes En este apartado se detalla el estudio que se ha hecho de diferentes aplicaciones que están disponibles en Google Play, y las carencias o particularidades de cada una de ellas que nos han llevado a, finalmente, escoger las funcionalidades que hemos decidido implementar en este proyecto. 44 comprarlos. Además, si se calculara una ruta óptima entre supermercados, sería aún más potente la aplicación. Las carencias propuestas son funcionalidades que mejorarían la aplicación. Aun así, es una aplicación intuitiva y fácil de usar y que cumple con la intención que tiene el creador, que no es más que la de poder hacer la lista de la compra. Una de las partes más positivas es que incorpora una alta variedad de productos para los distintos supermercados y tiendas locales como por ejemplo farmacias. Gracias a esto y al poder añadir productos favoritos, hace que la aplicación sea interesante. El hecho que no haya que registrarse siempre es un punto positivo a la hora de atraer a más usuarios, aunque como se ha comentado impide otras funcionalidades interesantes. Merka Free: Pese a haber una versión de la aplicación pagando, la que se ha testeado es la versión gratuita. Funcionalidades:  Crear lista de la compra. Igual que el resto de aplicaciones, ofrece la posibilidad de crear la lista de la compra con el objetivo de que el usuario sepa, antes de salir de casa, que es lo que va a comprar.  Añadir productos por categoría y supermercado. La aplicación contiene una amplia gama de productos separados por categorías y supermercado en el que se puede encontrar. Puedes hacer que se muestren todas las categorías y todos los supermercados.  Escaneo del código de barras. En caso de no encontrar el producto fácilmente, siempre puedes escanear el código de barras para que la aplicación te de la información del producto.  Añadir producto a mano. Si no encuentras el producto a mano y tampoco mediante el código de barras, siempre puedes añadir el producto a mano proporcionando su nombre, su precio y el supermercado en el que se encuentra.  Precio total. La aplicación muestra el precio total previsto a gastar en la lista de la compra según los productos añadidos.  Marcar producto como comprado. El usuario puede tachar un producto de la lista, igual que en el resto de aplicaciones, para indicar que ya lo ha comprado. Carencias:  Gestión de usuarios. Igual que en otras aplicaciones, tener una gestión de usuarios te proporciona diversas funcionalidades interesantes para el sistema.  Sistema de recomendaciones. Esta es una de las funcionalidades interesantes que faltan en la aplicación. Aunque sin tener gestión de usuarios es complicado hacer un 6. Aplicación Merka Free 45 sistema recomendador, sí que se podría hacer uno basado en los productos más populares entre los usuarios de la aplicación.  Localizador de supermercados. De la misma manera que con el sistema recomendador, podría haber un localizador de supermercados y no sólo una lista de supermercados con sus productos correspondientes. De esta manera, el usuario podría encontrar los supermercados y productos con más facilidad a la hora de ir a comprarlos. Además, si se calculara una ruta óptima entre supermercados, sería aún más potente la aplicación. Las carencias son las típicas en las aplicaciones generalistas. Las propuestas son carencias que a nuestro parecer podrían mejorar la aplicación si aparecieran. Por lo demás, igual que “myShopi”, es una aplicación intuitiva y fácil de usar, y que cumple muy bien con la función que ofrece. Me sorprende positivamente el amplio catálogo de productos, igual que “myShopi”, y que ofrezca el precio total, cosa que no ofrecen otras aplicaciones parecidas. Supertruper: Es la aplicación más completa de todas las encontradas. Las carencias son para mejorar la aplicación, teniendo en cuenta que es la mejor de todas las aplicaciones estudiadas. La que dispone de más funcionalidades interesantes. Funcionalidades:  Escaneo del código de barras. La aplicación permite a todos los usuarios escanear un código de barras para determinar qué producto se quiere comprar o añadir a la lista de la compra.  Gestión de listas de la compra. El usuario puede crear una lista nueva de la compra, ponerle nombre, y modificarla según crea conveniente. Además, se puede eliminar un producto de la lista de la compra.  Reconocimiento de voz. De la misma manera que se puede escanear un código de barras, la aplicación permite reconocimiento de voz. Así, únicamente diciendo el nombre del producto, la aplicación te sugiere diferentes productos relacionados con lo que has dicho vocalmente, en caso de encontrarlo.  Información de productos. Ésta es la funcionalidad más interesante encontrada en la aplicación. Dado un producto, te proporciona información del precio medio basándose en diferentes supermercados, y una lista de en qué supermercados lo puedes encontrar y a qué precio en cada uno de ellos. De esta manera, puedes saber dónde está más barato.  Alternativas. La aplicación, para cada producto, te proporciona alternativas. De esta manera, le proporciona al usuario productos que le pueden interesar según el producto seleccionado. 7. Aplicación SuperTruper 46  Compartir listas. Esta es la única de las aplicaciones estudiadas que dispone de la funcionalidad de compartir listas de la compra con otros usuarios, usando el mail de los usuarios con los que la quiere compartir.  Añadir producto. Al hacer una lista de la compra, el usuario puede añadir los productos que le interesen.  Quitar producto. De la misma manera que se pueden añadir productos a la lista de compra, el usuario puede quitar un producto de la lista siempre que lo crea conveniente.  Marcar como comprado. Un producto se puede marcar como comprado cuando el usuario lo considere oportuno. Carencias:  Precio total de la compra. Esta información no se muestra pese a poder marcar los productos como comprados. Aun así, es de las carencias menos importantes y más imperceptibles.  Ruta óptima. Además de proporcionarte el precio de un producto en diferentes supermercados, sería interesante que dada una lista de la compra, te proporcionara también la ruta óptima entre diferentes supermercados para comprar los productos al menor precio posible.  Sistema de recomendaciones más personalizado. Aunque sea de las pocas aplicaciones que proporciona sistema de recomendaciones en cuanto a proposición de alternativas, estas recomendaciones podrían ser más personalizadas aprovechando la información de las compras anteriores de los usuarios, por ejemplo. Es probablemente la aplicación más completa de todas las encontradas. Me ha sorprendido muy positivamente que te ofrezca una lista de los diferentes supermercados y el precio en el que está el producto en cada uno de ellos. Igual que nuestra aplicación, los precios de los productos se calculan a través de la información que proporciona el usuario, que es una buena manera para detectar las ofertas. Por otra parte, no te ofrece sistema de recomendaciones personalizado. El sistema de recomendaciones se basa en la oferta de los supermercados y no en los gustos o preferencias del usuario. Además, no te calcula la ruta óptima entre supermercados para poder ahorrar tiempo y dinero y no se muestra el precio total de la compra. Todo esto son detalles que se podrían mejorar, pero es una aplicación muy completa. 47 Compra Lista: Es probablemente la aplicación con más carencias de las generalistas estudiadas, ya que es la más simple de éstas. Funcionalidades:  Añadir producto. La aplicación ofrece la posibilidad de añadir productos a mano, introduciendo el nombre del producto en la aplicación.  Quitar producto. De la misma manera que se pueden añadir productos, la aplicación ofrece la posibilidad de poder quitarlos de la lista. De esta manera, simula el hecho de quitar un producto de una lista de la compra porque se ha añadido a la cesta.  Marcar y modificar precio en cartera. La aplicación te permite marcar el precio inicial que tienes en cartera. Una vez marcado, se puede reiniciar el precio o se puede incrementar o disminuir. De esta manera, una vez metes un producto en la cesta, puedes marcar en la aplicación que hay quitar cierto dinero de la cartera asumiendo que te lo vas a gastar en el producto. De esta manera, puedes ver cuánto dinero te queda para seguir haciendo la compra. Carencias:  Gestión de usuarios. El hecho de que no haya gestión de usuarios, igual que en otras de las aplicaciones, resta un mundo de posibilidades a funcionalidades muy interesantes personalizada para cada uno de los usuarios.  Gestión de productos. No tienes ninguna información del producto. El hecho de poner el nombre del producto a mano sólo te sirve para hacer la lista de la compra como la simularías sin la aplicación. No puedes saber si en otros supermercados lo puedes encontrar más barato.  Todo tipo de inteligencia artificial. Siguiendo con la línea anterior, no tienes sistema de recomendaciones, ni despensa virtual, ni optimización de rutas, ni información de dónde comprar los productos, pese a ser una aplicación generalista. Aunque esta aplicación simula muy bien el hecho de hacer la lista de la compra, se podría esperar más de una aplicación generalista. Las funcionalidades de las que carece son algunas de las más importantes que se pueden encontrar en nuestro proyecto. Además, como se ve en la imagen, no se tiene en cuenta el tamaño del nombre del producto que escribes, y se sobrepone encima de la cantidad, lo que lo hace ilegible. 8. Aplicación Compra Lista 48 4.1.2.3. Conclusiones Después de estudiar detenidamente las aplicaciones mencionadas anteriormente, hay funcionalidades que se escapan del ámbito del proyecto y otras que han ayudado a decidirse por su implementación en el proyecto debido a su buen funcionamiento. De todas las mencionadas anteriormente, todas tienen su parte positiva y su parte negativa. Para la elaboración del proyecto se han escogido las funcionalidades que se detallan en el siguiente apartado intentando escoger entre las ideas propias que ya se tenían y las ideas mostradas por las aplicaciones que se han comentado en este apartado. De todas ellas, la carencia más extendida es la falta de inteligencia artificial en las aplicaciones. Eso, junto al hecho de que la única que dispone de sistema de recomendación pertenece a un supermercado concreto, es lo que hace que nuestro sistema de recomendaciones y de cálculo de ruta óptima entre supermercados sea una de las bazas más importantes del proyecto que hemos realizado. 4.2. Funcionalidades En este sub-apartado se definen las funcionalidades finalmente implementadas en el proyecto, basándonos en el estudio hecho anteriormente sobre las funcionalidades de otras aplicaciones a priori similares. Las funcionalidades implementadas se pueden dividir en seis grandes grupos: gestión de usuarios, listas de compra, recomendaciones, calcular ruta óptima, realizar la compra, y despensa virtual. Gestión de usuarios: Este grupo de funcionalidades se puede dividir en otras más pequeñas como registro de usuarios, entrar a la aplicación con usuario logueado, solicitudes de amistad, buscador de usuarios, lista de amigos,… ¿Por qué es indispensable en la aplicación? Se decidió hacer una gestión de usuarios para que el usuario obtuviera de manera más personal las recomendaciones. En caso de no disponer de información detallada de cada usuario, es imposible hacerle una recomendación personalizada de productos. Por otra parte, desde un principio surgió la idea de crear la funcionalidad de compartir las listas de la compra. Para ello, también es adecuado que se disponga de una gestión de usuarios y amistades con los que poder compartir una lista de la compra. 49 Funcionalidades:  Registro de usuarios Cualquier usuario tiene la opción de registrarse para poder utilizar las funcionalidades de la aplicación que únicamente están disponibles para aquellos usuarios que se registran. Esta opción únicamente está disponible si el usuario no está logado en la aplicación. En caso contrario, si desea crear un usuario nuevo, deberá salir del usuario en el que se encuentra para poder encontrar esta opción. Una vez encontrada la opción, sólo es necesario insertar algunos datos personales para poder registrarse.  Loguearse Cualquier usuario registrado previamente en la aplicación y que figure en la base de datos, puede después entrar en la aplicación insertando sus datos. Sólo un usuario logado puede ver todas las opciones y funcionalidades de las que dispone la aplicación. En caso contrario, la única opción disponible es la de hacer la compra, cómo se explica en este apartado.  Log out De la misma forma que un usuario registrado previamente puede entrar en la aplicación, también puede salir de ella y del usuario en el que se encuentra. De esta manera, podrá logarse en otra cuenta que tenga registrada o podrá registrarse nuevamente. Esta opción, a diferencia de las dos anteriores, únicamente se muestra si el usuario está logado.  Perfil de usuario El usuario tiene la opción de ver su perfil de usuario. En este perfil, puede ver los datos que insertó cuando hizo el registro. Esta opción no aparece disponible si el usuario de la aplicación no se ha registrado y logado previamente. Dentro del perfil de usuario, el usuario dispone de las siguientes funcionalidades. o Buscador de usuarios: El usuario, conociendo previamente el nombre de los demás usuarios, puede buscar a otros usuarios de la red. A esos usuarios les puede mandar una solicitud de amistad para añadirles a su círculo de amistades. o Solicitudes de amistad: Otra de las opciones que sale en el perfil de usuario es la de ver las solicitudes de amistad. Una vez está viendo las solicitudes de amistad que le han enviado, tiene la opción tanto de eliminarlas como de añadirlas a su círculo de amistades según su interés. o Ver amistades: Esta funcionalidad es únicamente informativa. El usuario registrado puede ver qué usuarios son los que tiene en su círculo de amistades, ya sea porque el usuario ha mandado la solicitud y el otro usuario la ha aceptado, o porque le han mandado una solicitud que ha aceptado previamente. o 50 Gestionar las listas de compra: Este grupo es el que contiene más funcionalidades sobre la aplicación. Aunque también está relacionado con el tema de calcular la ruta óptima e incluso despensa virtual y recomendaciones, en este apartado vamos a definir las funcionalidades generales de la gestión de las listas de la compra. Todas las opciones que se plantean en este apartado están únicamente disponibles para usuarios logados previamente. ¿Por qué es indispensable en la aplicación? Es la idea básica de la aplicación, el motivo por el cual se ha realizado. Sin la gestión de listas de la compra, no podríamos solucionar el problema básico que se plantea como añadir o quitar productos, o marcarlos como comprados, o incluso calcular la ruta óptima o las recomendaciones. Con lo cual, es la base de la aplicación. Funcionalidades  Crear una lista de la compra Cualquier usuario logado puede crear una nueva lista de la compra. En el momento de creación inicial, el usuario únicamente puede añadir productos y guardar la lista de la compra. Sin estar previamente guardada no están disponibles las demás opciones de la gestión de listas de la compra.  Eliminar lista de la compra Una vez creada una lista de la compra, el usuario puede eliminarla si no la considera necesaria. Esta opción está disponible para todo tipo de listas, únicamente si el propietario de la lista es el usuario que está logado en ese momento.  Compartir lista Ésta es una de las funcionalidades más destacables y que hacen más interesante la aplicación. Al ser una aplicación de ámbito social, que permite tener tus amigos en común, puedes compartir la lista de la compra con diferentes amigos agregados previamente. Las ventajas de esta funcionalidad son obvias y es una de las bazas de la aplicación por ello. Por ejemplo, en el ámbito de compartir piso y repartir gastos, es mucho más cómodo si tienes registrado quién ha comprado cada cosa y a qué precio. Por otra parte, gracias a la posibilidad de compartir listas, puedes ver si un producto ha sido comprado o no antes de que lo vayas a comprar tú mismo. De esta manera, volviendo al ejemplo de compartir piso, puedes evitar malentendidos comprando productos que ya se han comprado antes.  Ver y modificar lista de usuarios compartidos A consecuencia de la funcionalidad anterior, también puedes ver, en una lista de la compra, con qué usuarios está compartida una lista. Además de ver los usuarios compartidos, puedes quitar los usuarios compartidos o añadirlos si eres el propietario de la lista de la compra. De manera que si has añadido a alguien por error, le puedes quitar para que no pueda ver más la lista. 51  Finalizar lista Otra de las funcionalidades disponibles referentes a la listas de compra es la de marcar una lista como finalizada. Marcar una lista como finalizada implica no poder hacer más cambios en la lista. No se pueden añadir ni quitar productos, no se puede compartir con más usuarios, ni marcar ningún producto como comprado, y ni siquiera calcular la ruta óptima para comprar los productos restantes. Se entiende que si se ha marcado una lista como finalizada, pueden haber productos pendientes y no se tiene intención de comprar los productos que quedan pendientes por comprar.  Ver precio total gastado en la compra Una vez finalizada la lista, los usuarios pueden ver cuánto dinero se ha gastado cada uno de los usuarios con quién está compartida la lista en hacer la compra de esos productos.  Comprar producto Una vez creada la lista de la compra, cualquier usuario con quien esté compartida la lista puede marcar como comprado cualquier producto de los que quedan pendientes de comprar. Para ello, uno de los pre-requisitos indispensables es calcular la ruta óptima. Sin tener la ruta óptima calculada no te sale la lista de productos pendientes que puedes comprar porque la aplicación, sin calcular la ruta y saber a qué supermercados vas a ir a comprar los productos, no te puede dar una aproximación del precio qué te vas a gastar en él.  Añadir productos Como se ha comentado, ninguna lista de la compra se registra en la base de datos sin tener productos añadidos, ya que conceptualmente no tiene sentido. Por ello está esta funcionalidad en la aplicación. De esta manera, los usuarios pueden buscar entre las recomendaciones, los productos que ya han comprado anteriormente y todos los productos registrados en el sistema para insertar en la lista de la compra y en la base de datos qué productos son los que necesita comprar.  Eliminar productos De la misma manera que con los usuarios compartidos, puede pasar que añadas algún producto a la lista y finalmente te des cuenta que no lo necesitas. Por ello, tienes la opción de eliminar los productos de la lista que ya no necesites o hayas añadido por equivocación, siempre que no hayan sido comprados previamente, en cuyo caso no podrás eliminarlo.  Ver productos Esta funcionalidad es interesante, ya que aunque no puedas ver en todo momento un total de cuánto dinero lleva gastado cada una de las personas en la lista de la compra, sí puedes ver todos los productos que hay, tanto los pendientes como los que ya se han comprado. Además de eso, se proporciona la información detallada de cada producto, como el nombre, el código de barras o la descripción. En el caso que haya sido comprado, se 52 proporciona información también de la fecha, el usuario que lo ha comprado y en qué supermercado.  Guardar lista de la compra Esta funcionalidad es imprescindible. Con esto, se guarda toda la lista de la compra con el estado de ésta y de todos los productos en la Base de datos. Que se guarde es prerequisito para muchas de las otras operaciones y funcionalidades mencionadas anteriormente. Por ejemplo, si una lista no está guardada no se puede marcar como finalizada. Así mismo, tampoco se puede calcular la ruta óptima ni se puede compartir con otros usuarios. Recomendaciones: Esta funcionalidad está ligada a las listas de la compra pero aparece en diferentes partes de la aplicación y por eso se explica en un sub-apartado distinto. Además, es una baza importante de la aplicación. Está ligada con la gestión de las listas de la compra ya que al buscar productos para añadirlos a la lista, el usuario puede seleccionar que se muestren las recomendaciones para saber qué productos son los que debería añadir. Por otra parte, no hace falta que el usuario cree una lista de la compra nueva y busque en añadir producto para poder ver las recomendaciones que le ofrece el sistema. ¿Por qué es imprescindible en la aplicación? Se pretendía que la aplicación, además de ser social, incorporara cierta inteligencia artificial en varios aspectos y funcionalidades y ésta es una de ellas. Esta funcionalidad es lo que hace distinta esta aplicación de muchas de las comentadas anteriormente en el estudio de antecedentes hecho. Calcular ruta óptima: Esta funcionalidad está ligada a la gestión de la lista de la compra, ya que sin ellas no es posible calcular la ruta óptima de una lista de productos pendientes dada. ¿Por qué es indispensable en la aplicación? Esta es otra de las funcionalidades importantes que diferencian ésta aplicación de las comentadas anteriormente. Ninguna de las aplicaciones comentadas anteriormente dispone de un sistema que le indique en qué supermercado comprar un producto específico. 53 Funcionalidad: Gracias a la distinta información sobre supermercados, compras de diferentes usuarios y productos, la aplicación puede, mediante un sistema de búsqueda heurística que se detalla en el apartado correspondiente, calcular la ruta óptima entre los supermercados más cercanos para así, mediante un mapa, indicar el camino óptimo entre diferentes supermercados para comprar los productos pendientes de la lista de la compra. Además, la aplicación te indica qué productos comprar en cada uno de los supermercados. Esta funcionalidad tiene como pre-requisito que la lista de la compra esté creada y guardada. En caso contrario, la aplicación no busca la ruta óptima. Por otra parte, tiene que ser capaz de calcular tu posición, ya que sin la ubicación actual del usuario no puede calcular tampoco la ruta óptima. Comprar sin hacer la lista de la compra o sin registrarse: Otra funcionalidad que parecía interesante desde un inicio es la de hacer la compra sin necesidad de haber hecho la lista de la compra anteriormente. Es la única de las funcionalidades que está disponible tanto si el usuario está registrado y logado en la aplicación como si no. ¿Por qué es indispensable en la aplicación? Esta funcionalidad es útil si estás en el supermercado para saber cuánto dinero llevas gastado en ese momento en la cesta de la compra. Además, debido a esto, es posible que los usuarios no se registren y lo único que busquen es saber cuánto dinero llevan gastado en la cesta de la compra. Por ello, parece una buena idea que los usuarios no necesiten registrarse para llevarla a cabo. Funcionalidades: Esta funcionalidad engloba dos funcionalidades o características importantes a comentar.  Escáner del código de barras. Esta funcionalidad precisa del uso de la cámara. De esta manera no tienes que apuntar el nombre del producto en la aplicación. Simplemente, con hacer una foto al código de barras del producto, y mediante geolocalización, la aplicación te proporciona toda la información del producto y a qué precio se cree que se encuentra en el supermercado en el que estás haciendo la compra.  Modificar el precio del producto. Igual que en ocasiones anteriores, el precio sugerido se puede cambiar. De esta manera, el precio total que llevas en la cesta se verá reflejado correctamente en el caso de haber una nueva oferta en ese producto y ese supermercado que la aplicación aún no ha detectado, o si el precio del producto ha aumentado. 60 5.1.1. Capa de presentación Esta es la capa que contiene las clases que se encargan de construir la interfaz de la aplicación y gestionar las funciones de todas las funciones que hay en ella. Así, esta capa contiene todas las clases “Activity” de Android. Es decir, todas las clases que serán llamadas cada vez que la aplicación abre una nueva pantalla diferente, llamada “Intent” en Android. Además, contiene todos los adaptadores creados para poder adaptar listas de productos, usuarios, supermercados y así poderlas incorporar en los elementos “ListView” de la aplicación. Estos adaptadores, como veremos más tarde en algún ejemplo, puede contener desde textos hasta diferentes botones. De esta manera, las clases de la capa de presentación implementan todas las funciones a las que se llaman cuando se aprieta un botón. Para poder realizar éstas funciones, en muchas ocasiones se comunica tanto con la capa de dominio como con la capa que conecta con la base de datos. El diagrama UML resultante de la capa de presentación es el siguiente. Los detalles de la implementación de estas clases se definen posteriormente en este capítulo. Debido al gran tamaño se ha separado el diagrama UML según sus funcionalidades generales: gestión de usuarios, gestión de listas de compra, y otros. 61 9. Diagrama de clases. Capa de presentación. Gestión de usuarios. 62 10. Diagrama de clases. Capa de presentación. Gestión de listas de compra. 63 11. Diagrama de clases. Capa de presentación. Otras funcionalidades. 5.1.2. Capa de dominio el problema Esta capa contiene las clases que se encargan del dominio conceptual del problema. Es decir, es la capa encargad de almacenar información en memoria y gestionar los datos entre la interfaz y la capa de la base de datos de la aplicación. Además, contiene todas las clases encargadas de implementar el sistema de recomendaciones y el sistema del cálculo de ruta óptima entre supermercados teniendo en cuenta el precio de los productos pendientes y la distancia entre los supermercados donde están disponibles estos productos. De esta manera, además de las clases genéricas conceptuales del problema, como son producto, lista de la compra, usuario, supermercado… también hace los cálculos relacionados con la IA de la aplicación e implementa diferentes clases que se usan para guardar en memoria los resultados y datos de entrada de estas funciones. A continuación se muestra el diagrama de clase UML. Los detalles de implementación de estas clases se muestran más adelante en este capítulo. 64 Una de las particularidades de este diagrama de clases UML es la clase “InstanceUsuario.java”, que detallaremos más tarde. Es una clase “singleton” que se usa desde diferentes puntos de la aplicación para obtener el usuario activo de la aplicación, el usuario que está logado en ese momento. 12. Diagrama de clases. Capa de Dominio. Planificación de rutas. 13. Diagrama de clases. Capa de dominio. Clases globales. 65 14. Diagrama de clases. Capa de dominio. Dominio del problema. 15. Diagrama de clases. Capa de dominio. Recomendaciones. 66 5.1.3. Capa de datos Por último, tenemos la capa encargada de la conexión de la base de datos. El hecho de conectarse a la base de datos y el protocolo utilizado es totalmente independiente tanto de la capa de dominio como de la capa de presentación. Esta capa implementa la clase con la que contactan todas las demás clases cada vez que necesitan conectarse a la base de datos para obtener datos de ella y tratarlos para mostrarlos en alguna de las pantallas de la aplicación. También contactan con ella todas las clases que necesitan borrar o modificar algún o algunos registros de la base de datos. No se detalla en el diagrama pero todas las funciones que conectan con la BD tienen las mismas funciones: doInBackground, onPostExecute y onCancelled. Finalmente, todas aquellas clases que insertan nuevos registros en la base de datos, también necesitan contactar con esta capa para conectarse a ella y hacer las transacciones necesarias. 16. Diagrama de clases. Capa de datos. 67 5.2. Estructura de la base de datos En este sub-apartado definimos el diseño y la implementación de la base de datos creada para guardar los datos de la aplicación. Como se ha comentado en esta memoria, la base de datos utilizada es una base de datos relacional MySQL. Aunque las clases son muy parecidas a las de la clase de dominio, las redefinimos porque las características de este tipo de base de datos no permiten guardar listas. Así, mientras que sólo necesitamos dos clases java para definir productos, supermercados, y productos en un supermercado debido a que supermercado incorpora una lista de productos, no podemos hacer lo mismo en la base de datos. Así, para representar esto en la base de datos, necesitamos tres tablas distintas relacionadas entre ellas: Producto, Supermercado y ProductoSupermercado. Lo mismo sucede en otros casos, como para registrar las solicitudes de amistad, las amistades, los productos de una lista de la compra… A continuación se detallan las tablas creadas, así como su relación con las distintas tablas. Como sabemos, las tablas poseen una primary key, que es una clave única en cada uno de los registros y que no se puede repetir. Además, también definimos las unique key, que son los campos de las tablas que son únicos y tampoco se pueden repetir aunque no sean “primary key”. Para finalizar, también se definen en el diagrama las “foreign key”, que son los campos que están relacionados con otros de otras tablas. El diagrama correspondiente a las tablas de la BBDD es el siguiente. 17. Diagrama de la BBDD 68 Además, hemos implementado un disparador en la base de datos. Un disparador es una función que se ejecuta cada vez que pasa cierta operación en la base de datos. En nuestro caso, hemos definido el disparador para calcular el precio de un producto en un supermercado. Así, se determina que el valor de un producto en un supermercado es el valor más frecuente de compra de ese producto en ese supermercado entre las últimas 100 compras de ese producto en ese supermercado. La razón de escoger un número limitado de compras y no todas es debido a que coger todas las compras para hacer el cálculo a la larga puede ser ineficiente. Además, cogiendo las últimas podemos saber si un producto ha cambiado de precio y cuál es el precio actual del producto. Así, detectamos las posibles ofertas o cambios de precio. 5.3. Implementación de la aplicación En este sub-apartado de la memoria explicamos los detalles más relevantes de la implementación de la aplicación, dividiendo estas explicaciones y justificaciones según por las capas del diseño e implementación comentadas anteriormente, entrando profundamente en detalle en la implementación de los algoritmos de inteligencia artificial. 5.3.1. Capa de presentación En este apartado explicaremos las clases creadas para la interacción del usuario con la aplicación. Es decir, esta capa implementa las funciones que se ejecutan cuando, por ejemplo, el usuario pulsa un botón de la pantalla. Además, esta capa es la encargada de tratar los datos obtenidos de la base de datos mediante la capa de datos usando también la capa de dominio de la aplicación. Una de las particularidades de las aplicaciones Android es que las clases de la capa de presentación heredan de la clase “Activity”. De esta manera, hay algunas funciones que podemos implementar para que su función no sea la de por defecto. En la mayoría de casos, la única de estas funciones usadas es la función onCreate, que es la que más detallaremos. Por lo demás, también existen las funciones onStart, onResume, onPause, onStop y onDestroy, aunque apenas las hayamos utilizado. 69  onCreate. Esta función se llama cuando la “Activity” es ejecutada por primera vez. En esta función hay que definir. Como parámetro recibe un objeto “Bundle”. Si la pantalla actual es llamada desde una pantalla anterior, mediante el objeto “Bundle” es capaz de pasar elementos serializables de una pantalla a otra. Serializar consiste en un proceso de codificación del objeto en un medio de almacenamiento para transmitirlo como una serie de bytes o en un formato más legible. Hay varias funciones importantes que hay que ejecutar dentro de la función “onCreate” para inicializar el contenido y la interfaz de la pantalla. o setContentView(int). Se usa para determinar layout que dará diseño a la pantalla de la aplicación. Para definir este layout se hace mediante un fichero xml incorporando diferentes elementos pertenecientes a clases “View” definidas por las librerías Android utilizadas. Por ejemplo podemos usar ListView para definir listas, TextView para definir textos, entre otros. o findViewById(int id). Esta función te proporciona el elemento “View” identificado por el atributo id que has puesto en el xml procesado en la función onCreate. Así, una vez consigues los elementos visuales mediante esta función, puedes obtener su contenido e incluso modificarlo, tanto a nivel de diseño como e datos.  onStart. Esta función es llamada cuando la actividad empieza a ser visible para el usuario. La función onResume() va a continuación si la actividad se pone en primer plano.  onResume. Esta función se llama cuando la actividad va a empezar a interactuar con el usuario. En este punto, la actividad está encima del todo de la pila de actividades y por tanto el usuario la ve en pantalla. Siempre va seguida de la función onPause().  onPause. Esta función es llamada por el sistema cuando la aplicación está apunto de volver a llamar a una actividad anterior. Las implementaciones de este método deberían ser cortas en cuanto a tiempo de ejecución porque la siguiente pantalla no será cargada de nuevo hasta que acabe. Se utiliza generalmente para guardar cambios que no se han cargado anteriormente.  onStop. Esta función se llama cuando la actividad o pantalla ya no es visible por el usuario porque otra actividad ha ocupado su lugar. Esto puede pasar porque una nueva actividad ha sido iniciada, o una actividad existente ha sido puesta por delante, o la pantalla está a punto de ser destruida.  onDestroy. Es la última función llamada antes de que la pantalla sea destruida. Esto puede pasar porque la actividad está acabando, por ejemplo debido a la llamada a la función finish() o porque el sistema está destruyendo la instancia para guardar espacio. Una vez comentadas las funciones básicas que pueden incorporar todas las clases de esta capa, vamos a comentar una por una las funcionalidades básicas para las que han sido creadas cada una de las clases perteneciente a esta capa. 76 InstanceUsuario Como se ha comentado, es una clase singleton. Singleton es un patrón de diseño diseñado para restringir la creación de objetos pertenecientes a una clase o el valor de un tipo a un único objeto. La intención básicamente consiste en garantizar que una clase sólo tenga una instancia y proporcionar un punto de acceso global a ella. Las características principales en cuanto a implementación son que la propia clase es responsable de crear la única instancia. Además, permite el acceso global a dicha instancia mediante un método de clase, y declara el constructor de clase como privado para que no sea instanciable directamente. De esta manera, en la aplicación existe una única instancia de la clase InstanceUsuario. Esta instancia, en caso de estar creada, contiene el usuario logado actualmente. En caso que no exista la instancia, significa que no hay ningún usuario logado en la aplicación. Por lo tanto, además de los métodos mencionados, contiene funciones para poder acceder a varia información del usuario así como el nombre del usuario logado o el mail. User Esta clase es en la que se basa la clase InstanceUsuario comentada anteriormente. Esta clase existe porque además del usuario logado hay que poder referenciar el resto de usuarios, por ejemplo para la realización del algoritmo Collaborative Filtering o para poder mandar solicitudes de amistad a otros usuarios. Por lo tanto, esta clase representa todos los atributos que posee un usuario, desde su nombre de usuario hasta la fecha de creación del mismo, pasando por su e-mail, contraseña para logarse en la aplicación, o el número de listas de compra que posee. Producto Esta clase es la que representa cualquier tipo de producto. Puede representar desde productos comprados en un supermercado concreto, a producto en general (indicando únicamente su código de barras, nombre, descripción, marca y tipo de producto), pasando por producto disponible en un supermercado. Para saber en qué caso nos encontramos, nos basta con comprobar el atributo de su estado, o comprobar que algunos de los datos están vacíos. Así, si el campo del precio final, o fecha de compra, o usuario que lo ha comprado, está vacío, significa que el producto no ha sido comprado. ListaCompra Esta clase representa una lista de la compra en la aplicación. Como todas las listas de la compra, contiene un identificador, además del usuario creador de la compra y la fecha de creación. 77 Además, contiene una lista de productos, y una lista de usuarios con los que el usuario creador ha compartido la lista. También contiene un atributo que muestra el estado de la lista, si ha sido finalizada o no, y el precio final gastado. Con todos estos campos podemos representar en cualquier momento de la aplicación una lista de la compra. Supermercado Finalmente, otra de las clases generales que disponemos en la aplicación es la que representa a cualquiera de los supermercados de la zona. Para representarlos, no sólo guardamos su identificador, nombre y su dirección en cuanto a nombres de calles, sino su posición en cuanto a longitud y latitud. Además, en ciertos puntos de la aplicación necesitamos saber qué productos hay en cada supermercado. En estos puntos se incluye una lista de productos para representar el supermercado. 5.3.2.1. Funcionalidad ruta óptima: Hill Climbing A continuación se comentan las clases utilizadas para implementar el algoritmo de planificación de rutas utilizado: Hill Climbing. Como hemos comentado en la sección de los algoritmos utilizados, Hill Climbing es un algoritmo de búsqueda local. Parte del estado de soluciones y a partir de ahí intenta mejorar la solución. Tal y como se ha implementado, la idea es que se compren todos los productos que estén disponibles en un ratio más o menos cercano. Es decir, si de 10 productos, hay 7 productos que se pueden comprar en un ratio relativamente cercano, el algoritmo buscará la mejor combinación de precios y supermercados para comprar esos 7 productos, asumiendo que los otros 3, según la ubicación actual, no los puedes obtener. Nos hemos ayudado de la clase AIMA para implementar el algoritmo. A esta clase tienes que proporcionarle una función heurística, un estado, una manera de determinar si el estado es válido o no, y una manera de generar los sucesores de un estado concreto. Con estos datos, la clase AIMA implementa el bucle que, dado un estado inicial que también hay que proporcionarle, genera los sucesores y se queda con el que proporcione mejor solución en cuanto a coste calculado con la función heurística que se le proporciona. La clase AIMA sigue generando sucesores hasta que no encuentra ninguno con un coste menor al estado actual. GoalHillClimbing Esta clase define la función que determina si un estado es válido para ser estado final o no. En caso de no ser válido, ese estado no se tendría en cuenta a la hora de seleccionarlo entre los mejores sucesores. 78 Tal y como se ha comentado, en nuestro caso partimos de una solución inicial y tratamos de mejorarla. Por lo tanto, esta función devuelve verdadero siempre, porque todos los estados son estados finales. EstadoHillClimbing Esta clase es la que contiene la representación de cada nodo, la que contiene la representación del estado. Para representar este estado, la clase contiene el número de productos, una lista de los productos pendientes a comprar y una lista de los supermercados relativamente cercanos. Cada uno de los supermercados, a su vez, tiene información de los productos que están a la venta y sus precios. Esos precios, como ya comentamos, son calculados a partir de la información que transmite el usuario. Además, este estado contiene la longitud y la latitud en la que se encuentra el usuario logado al hacer la petición de calcular la ruta. Finalmente contiene una lista que contiene los supermercados a comprar y los productos a comprar en cada uno, incluido su precio. Esta lista es la lista que representa la ruta final entre supermercados y los productos a comprar en cada uno, y es lo que varía de un estado a otro durante la ejecución del problema. Además de las funciones constructoras que inicializan los datos comentados anteriormente, las funciones más importantes a tener en cuenta son las siguientes:  setEstadoInicial() Esta función, utilizando los productos pendientes y la información de los supermercados y sus productos, inicializa el estado inicial. El algoritmo es sencillo con tal de no perder demasiado tiempo estableciendo una solución inicial. La idea es recorrerse todos los productos pendientes y para cada uno de ellos todos los supermercados. Si el producto pendiente se encuentra en el supermercado, se asigna ese producto a ese supermercado y al precio en el que se encuentra, y se pasa a asignar el producto pendiente siguiente. El algoritmo en pseudocódigo es el siguiente: 79  cambiarOrdenSupermercados(int i, int j) Esta función cambia de orden los supermercados que se encuentran en la posición i y j de la ruta final determinada. Esta función será llamada a la hora de generar los sucesores del estado actual.  asignarProductoASupermercado(int p_i, int s_i, int s_j) Esta función es otro de los operadores que se usan sobre el estado a la hora de generar los sucesores del estado actual. La idea es asignar el producto p_i que ahora está asignado al supermercado s_i al supermercado s_j. Los dos primeros índices pertenecen a los índices de la ruta final mientras que el s_j pertenece a la lista de todos los supermercados cercanos de los que disponemos. Así, el algoritmo consiste en que si el supermercado destino está en la lista de la ruta final, añadirle el nuevo producto. En caso contrario, añadimos tanto el supermercado nuevo como el producto a la lista. Finalmente, borramos la asignación producto-supermercado anterior. Si el supermercado se queda sin productos que comprar, lo eliminamos de la lista. El algoritmo en pseudocódigo es el siguiente: HeuristicFunctionHillClimbing Esta clase es la encargada de implementar el cálculo del coste de la función heurística. Recibe como parámetro un estado concreto, y a partir de él se calcula el coste. Como se ha comentado varias veces a lo largo de la memoria, para calcular el coste tenemos en cuenta tanto la distancia como el precio. Mediante dos bucles, recorremos tanto los supermercados añadidos como los productos en cada uno de ellos. De esta manera, calculamos el precio de todos los productos, y también la distancia entre un supermercado y el supermercado anterior. Hay que tener en cuenta que si estás en la primera posición de la lista de supermercados que forma la ruta final, la distancia que hay que añadir es la distancia entre la posición actual del usuario y la ubicación de este supermercado. Finalmente, se normalizan tanto la suma de distancia como de precio de productos para darle una relevancia parecida y se devuelve la suma de ambos. 80 Algoritmo en pseudocódigo: SuccessorHillClimbing Esta clase se encarga de definir los sucesores de un estado mediante los operadores necesarios para cambiar el estado actual. Las funciones que generan los sucesores están diseñadas para que el estado sucesor siga dentro del espacio de soluciones. En caso contrario, el planteamiento del problema y la definición de algunas de las clases comentadas anteriormente no serían correctos. Las funciones que generan los sucesores son las siguientes:  cambiarOrdenSupermercados(estado). Esta función recorre todos los supermercados y, mediante el operador de cambio de orden de supermercados que hemos visto en la clase que define el estado, hace todas las posibles combinaciones de orden cambiando dos de los supermercados de posición.  CambiarProductoSupermercado(estado). Esta función recorre todos los supermercados y productos de la ruta final, y para cada uno de los productos, busca algún supermercado diferente al que está asignado actualmente y en el que esté disponible, y aplica el operador visto anteriormente de asignar un producto concreto a un supermercado. Una vez se añade este sucesor, se añaden todos los sucesores relacionados con cambiar el orden de visita de los supermercados. No se definen en pseudocódigo los algoritmos debido a su sencillez. Consisten en unos bucles dentro de otros para acabar recorriendo todos los supermercados y productos de los que se dispone tanto en la ruta final calculada hasta el momento, como en los supermercados cercanos. SearchHillClimbing Esta es la clase encargada de realizar toda la búsqueda mediante el algoritmo Hill Climbing. Es la clase con la que interaccionan las demás clases, ya que las otras descritas para esta funcionalidad no están accesibles desde fuera. 81 Además de las funciones creadoras y las funciones básicas para inicializar supermercados y productos pendientes, contiene el atributo que representa el estado final. Este algoritmo está vacío a menos que se ejecute la búsqueda. Para ejecutar la búsqueda, se utiliza la siguiente función:  ejecutarBusqueda(). Con todas las clases definidas anteriormente, ya podemos ejecutar el algoritmo gracias a la clase AIMA. Necesitamos pasarle una definición del estado, una manera de generar los sucesores, una función que determine si un estado es final o no, y una función heurística que calcule el coste. Por otra parte, la librería AIMA incorpora la clase Problem y la clase HillClimbingSearch. Con los datos anteriores podemos definir el problema, mientras que usando la clase HillClimbingSearch, podemos hacer la búsqueda pasando como parámetro el problema definido. Finalmente, nos basta con coger el estado final de la búsqueda para obtener la ruta final obtenida por el algoritmo. En pseudocódigo, el algoritmo es el siguiente: 5.3.2.2. Clases globales DirectionsJSONParser Esta clase es una clase global, aunque únicamente se usa en la clase MapsActivity y está relacionado con el tema de planificación de rutas. Al formar parte de la capa de dominio, se ha incorporado en este sub-apartado de clases globales porque no influye en el proceso de Hill Climbing de calcular la ruta óptima en cuanto a dinero y distancia entre los supermercados. Esta clase se encarga de parsear el objeto JSON devuelto por la API de Google Maps a la hora de hacer la petición de ruta óptima entre dos puntos. Hasta ahora queríamos saber la ruta óptima entre supermercados. Ahora lo que buscamos es obtener la ruta óptima en un mapa entre dos puntos, teniendo en cuenta que el trayecto se hace andando. Así, esta clase trata la respuesta de la API de Google Maps, y devuelve una lista de listas que contiene la longitud y latitud de cada uno de los puntos por los que tiene que pasar el usuario. Estas direcciones se usan en la clase MapsActivity para pintar la ruta. 82 HttpConnection De la misma manera que necesitamos un decodificador JSON para tratar la respuesta de direcciones por las que tiene que pasar el usuario para ir de un punto a otro, también necesitamos establecer una conexión con la API de Google Maps para poder lanzar la petición. Así, esta clase tampoco pertenece al proceso de cálculo de búsqueda local mediante Hill Climbing, pero pertenece a la capa de dominio y está relacionado con la obtención de pintar la ruta final. Aun así, aunque está relacionado indirectamente, se considera una clase de ámbito global. Esta clase se encarga de esto mediante la función readUrl. Esta función recibe como parámetro la url de la petición de direcciones y, usando clases como HttpURLConnection, URL, BufferedReader, InputStream,… establece la conexión y devuelve los datos de la lectura realizada en la URL recibida como parámetro. 5.3.2.3. Funcionalidad Recomendaciones En este apartado determinamos las clases de la capa de dominio que se usan para hacer los cálculos y determinar las recomendaciones personalizadas del sistema al usuario que está logado en ese momento. Como se ha comentado, el algoritmo seguido para la implementación del sistema de recomendaciones es una variante del algoritmo de Collaborative Filtering. Tal y como comentamos es una variante porque el usuario no da una puntuación directa sobre los productos, pero utilizamos la información binaria de la compra o no del producto, y el número de veces que ha sido comprado, para simular esta información. ProductoFrecuencia Tal y como hemos dicho, necesitamos almacenar tanto los productos que ha comprado un usuario tanto como su frecuencia de compra. Esto lo hacemos mediante esta clase, llamada ProductoFrecuencia. Aquí se almacena tanto el producto como un entero indicando el número de veces que se ha comprado este producto. Esta clase, tal y como veremos a continuación, está relacionada a su vez con un usuario concreto. UserProducts Por lo tanto, para realizar el algoritmo del sistema de recomendaciones, necesitamos almacenar, tanto para el usuario logado como para el resto de usuarios, una lista de productos y el número de veces que ha comprado esos productos. Eso es lo que hace exactamente esta clase. Contiene un usuario concreto, y una lista del objeto ProductoFrecuencia explicado antes para almacenar los productos con sus respectivas frecuencias. Así, una clase ProductoFrecuencia siempre está asociada a un único usuario mediante la clase UserProucts. 83 DistanciaUsuarios Esta clase es la encargada de una de las funciones más importantes del sistema recomendador de la aplicación. Esta clase es la responsable de calcular la distancia entre usuarios. También dispone de una función que permite obtener una lista con los K usuarios más cercanos. En nuestro caso, hemos decidido que esta K sea 10, aunque podría ser cualquier otro número al azar. Para realizar todo esto, esta clase almacena inicializa y recibe como parámetros los siguientes atributos: el número de usuarios, el número de productos a comparar, una lista de usuarios con los que compararse, una lista del objeto ProductoFrecuencia propia del usuario logado actualmente, y dos matrices referentes a los productos. Estas matrices representan en filas al usuario, y en columnas a los productos. Así, en la fila i y columna j encontramos en una matriz un booleano que indica si el usuario ha comprado el producto o no, y en la otra matriz el número de veces que el usuario ha comprado ese producto. Además de estos atributos, guarda en memoria un vector de distancias del tamaño del número de usuarios. En cada posición se representa, una vez calculada, la distancia del usuario actual con cada uno de los demás usuarios. Veamos la implementación de las dos funciones más importantes de esta clase:  getKUsers(int num) Esta función devuelve una lista con los usuarios que más se parecen al usuario logado actualmente. Obviamente, para ello es pre-requisito que antes se haya calculado la distancia mediante la función que comentaremos a continuación. El algoritmo de esta función consiste en ir recorrer la lista de todos los usuarios. Si la lista resultante de usuarios está vacía, añadimos el primer usuario, y su distancia en una lista temporal para poderlos comparar. En caso de que el número de usuarios de la lista ya sea el número de usuarios máximos determinados por el parámetro que recibe la función, comprobamos si el parecido del usuario que estamos comprobando con el usuario actual es mayor que algunos de los de la lista, y en ese caso lo insertamos en la posición correspondiente y borramos el último de la lista. En caso contrario el usuario no se añadirá a la lista. Por el caso contrario, si aún la lista no ha llegado a su máximo hacemos lo mismo que antes: comprobamos si el usuario que estamos comprobando se parece más que alguno de los que ya hay. Si se da el caso, se añade en la posición correspondiente, y en caso contrario se añade al final de la lista. 84 Algoritmo en pseudocódigo: Se puede observar en el algoritmo que comprobamos que el vector de distancia sea mayor que el del vector temporal de distancia. Esto es por el valor que nos da el vector de distancias. Cuanto más alto es el número, más se parecen los usuarios.  calculaDistancia() Esta función calcula la distancia que hay entre el usuario actual y cada uno de los demás usuarios y guarda el valor en el vector distanciaUsuarios, donde cada posición se corresponde con el parecido entre el usuario logado actualmente y el usuario que se encuentra en dicha posición. 85 Como se ha comentado en la sección de algoritmos de inteligencia artificial de la memoria, para calcular la distancia usamos la distancia coseno de los vectores. Para ello, en el numerador encontramos la multiplicación de los dos vectores de ProductosFrecuencia: el vector del usuario actual y el vector del usuario con el que medir la distancia. En el denominador de la función encontramos el módulo de ambos vectores. Finalmente, al hacer el coseno de la división, obtenemos la distancia entre ambos vectores. Cuanto más alto es este número, más se parecen los vectores. Cabe destacar que es diferente el parecido encontrado del usuario i con el usuario j, que el parecido del usuario j con el usuario i. Lo que comprobamos es cuanto se parece el vector de productos de un usuario con otro. Esto quiere decir que el vector de productos a comparar siempre tendrá el tamaño del vector de productos del usuario actual. Así, si un usuario sólo ha comprado un producto una vez, y el segundo usuario ha comprado ese producto una vez, además de otros muchos productos, la distancia del primer usuario con el segundo dará como resultado un parecido grande entre los dos usuarios, mientras que un parecido bajo del segundo usuario con el primero. Esto es así por razones de espacio, para no tener que hacer operaciones con vectores del tamaño de todos los productos incorporados en la aplicación del sistema. El algoritmo en pseudocódigo es el siguiente. Consideramos que user1 es el usuario actual mientras que user2 es el usuario a comparar: 92 calcularRutaTask Esta clase es la encargada de calcular la ruta óptima. Para ello, recibe como input los productos pendientes a comprar. En la función doInBackground se conecta a la base de datos y obtiene todos los supermercados cercanos con sus correspondientes productos. Si todas las consultas se han ejecutado correctamente, la función onPostExecute es la encargada de llamar a la clase HillClimbingSearch de la capa de dominio, pasarle todos los datos necesarios, y finalmente llamar a la función que ejecuta la búsqueda local y te devuelve el resultado. Si todas las operaciones aquí llevadas a cabo se han procesado correctamente, esta clase se encarga de llamar a la actividad de los mapas para inicializarla pasándole como parámetro la ruta a seguir entre supermercados y qué productos comprar en cada uno. 5.4. Diseño de la interfaz de la aplicación y estudio de la usabilidad En este apartado se define el diseño de la interfaz de la aplicación. Es decir, se define cómo han sido creados los layouts que hemos mencionado anteriormente que cargaban las clases de la capa de presentación. De esta manera, en este apartado veremos el resultado final de la aplicación y justificaremos la elección del diseño implementado. Así, se hará un estudio de la usabilidad y se propondrán posibles mejoras futuras teniendo en cuenta la forma más intuitiva de usar la aplicación. Pantalla principal Tal y como muestran la imagen, la pantalla principal consiste en varios botones. Según el botón pulsado la aplicación te dirige a una actividad o a otra. En cuanto a usabilidad, es intuitivo ya que el nombre de los botones indica bastante bien el lugar de la aplicación al que te dirige el botón. Por otro lado, no es bonito, a nivel de diseño, un montón de botones seguidos uno detrás de otro. Una posible futura mejora sería la creación de iconos con un símbolo intuitivo del lugar de la aplicación al que te diriges. De esta manera, es más bonito y el usuario no tiene que leer la descripción de todos los botones para saber dónde ir. Otra opción es incorporar algunos de estos links a la barra de tareas. Esto no se hizo porque en según qué versiones de Android, la barra de tareas es inexistente. Aun así, podría hacerse una variante y que según la versión de Android del dispositivo lo distribuyera de una manera o de otra. Por ejemplo, poder acceder al perfil desde la barra superior sería una mejora en el diseño. 18. Pantalla principal 93 Registro/Login Estas pantallas necesitan de algún método de input para que el usuario pueda meter sus credenciales. La manera más rápida y obvia de hacerlo es mediante EditText. Rellenar un formulario es un acto sencillo y que todos los usuarios reconocen a simple vista mediante los EditText, con lo cual se hace intuitivo y no es necesario explicarle nada más para que sepa qué es lo que tiene que hacer. Perfil Usuario Tal y como hemos dicho anteriormente, quizás una forma más bonita e intuitiva de acceder al perfil de usuario sería poniendo el botón de acceder al perfil en la barra superior de la aplicación. Vemos que una vez ahí, además de los datos, se utiliza el mismo sistema de botones continuados para acceder a las amistades, solicitudes de amistad y al buscador de amigos. Por ahorrar espacio, esto se podría haber hecho con un TabHost, de manera que aparecieran diferentes pestañas en la pantalla y el usuario se moviera por ellas según la lista que quisiera consultar y sus necesidades. Esto habría proporcionado ahorro en cuanto a número de pantallas. Como se ha comentado, el diseño es mejorable ya que no era uno de los objetivos prioritarios de la aplicación, pero se ha intentado seguir el mismo sistema en todas las pantallas para que quede una aplicación homogénea. 19. Pantalla de registro 20. Pantalla de perfil 21. Pantalla de amistades 94 Recomendaciones/Despensa Probablemente la que hay implementada es la única manera, o por lo menos la más sencilla e intuitiva, de representar las recomendaciones y la despensa virtual. No es más que una lista de productos. El hecho de que al darle al producto se abra un diálogo proporcionando información del producto en vez de extender el elemento de la lista para que se muestre toda la información, hace que aprovechemos mucho mejor el espacio. Es bastante intuitivo el hecho de apretar uno de los elementos de la lista si se quiere obtener más información del mismo. Es perfectamente asumible que quede en segundo plano la lista de productos, ya que si estás comprobando los datos detallados de un producto completo, probablemente no te interese compararlo con el otro, debido a las características que se representan. Compra Esta pantalla sigue con el esquema de botones propuesta en la pantalla principal, aunque sólo sea con el botón de escanear el código de barras. Una optimización de espacio podría ser, por ejemplo, la de poner un icono que represente la cámara en la barra superior de la pantalla. Por otra parte, se ha decidido que el total del precio figure arriba de la lista de productos porque probablemente, al ejecutar esta funcionalidad, sea lo que más le interese ver al usuario y por lo tanto lo primero que deba ver ListaCompra Esta pantalla es en la que más se notan las desventajas del sistema de botones propuesto, al ponerlos uno debajo de otro. Vemos como, en los casos en los que se muestran todas las opciones y todos los botones, el espacio se reduce bastante, pese a ser un dispositivo con la pantalla relativamente grande. Estas opciones se podrían haber representado en la barra de menú, o incluso alguna en la barra de tareas con tal de optimizar espacio. No se ha hecho así porque hay versiones antiguas de Android que no aceptan Action Bars, y por lo tanto hacer este sistema de botones permitía unificar más la aplicación. Aun así, consideramos que el sistema de pestañas para distinguir los productos comprados del resto es un acierto para optimizar espacio. 22. Pantalla recomendaciones 23. Pantalla compra 24. Pantalla de lista de compra 95 GestionListasCompra De la misma manera que con la clase ListaCompra, consideramos que el sistema de pestañas para distinguir las listas de compra con un estado específico de otras es un acierto para optimizar espacio, además de ser bastante intuitivo y usable. El botón de crear una nueva lista podría figurar perfectamente en la barra de arriba, aunque en las versiones más antiguas de Android no podría ejecutarse la aplicación AnadirProducto Esta es la pantalla que encontramos menos usable y con más carencias. Una de las mejoras importantes sería añadir de alguna forma una lista con los productos añadidos a la compra, ya que en estos momentos la aplicación te avisa cuando añades un producto, pero no puedes ver en esa misma pantalla una lista de los productos seleccionados. Otra futura mejora a tener en cuenta es el hecho de poder encontrar productos según el tipo, o mediante un buscador. El uso de un buscador haría la aplicación más usable, ya que sería mucho más sencillo para el usuario encontrar un producto concreto. 25. Pantalla gestión de listas 26. Pantalla añadir producto 96 CompartirListasCompra El hecho de que el usuario sepa en todo momento con qué usuarios ha compartido la lista y con cuales no, suponemos que es una ventaja. Como siempre, el botón que figura arriba de la pantalla para guardar los cambios podría figurar como alternativa en la ActionBar de la actividad con tal de mejorar el espacio. Otra propuesta que podría mejorar la usabilidad sería la de incorporar un buscador para encontrar un usuario amigo concreto más rápidamente, en el caso de tener a muchos otros usuarios agregados como amigos en la aplicación. MapsActivity Como siempre, el botón de registrar la compra podría aparecer en la ActionBar para optimizar espacio, pero ya hemos contado anteriormente porque no se ha llevado a cabo esta opción: para seguir un sistema homogéneo durante toda la aplicación y unificar el sistema para que funcione en diferentes versiones de Android, aunque finalmente sólo se haya testeado profundamente en una de ellas. Consideramos que el hecho del uso las pestañas para mostrar en una pantalla el mapa y en la otra el detalle es un acierto para la optimización de espacio y hace la aplicación más usable. 28. Pantalla ruta calculada 1 29. Pantalla ruta calculada 2 14. Pantalla Compartir lista 97 6. Validación y Tests En este apartado de la memoria se exponen diversos experimentos realizados a lo largo del desarrollo del proyecto, así como experimentos realizados una vez completada la implementación de la aplicación Android para gestionar la lista de la compra. De esta manera, este capítulo sirve para validar el correcto funcionamiento de la aplicación. Debido a que es la parte más compleja debido a la inteligencia artificial, se hace especial énfasis a los experimentos de planificación de rutas y al sistema de recomendación, aunque también se hacen pruebas para validar que funcionan correctamente las funcionalidades generales como la gestión de usuarios, la gestión de listas, así como la funcionalidad de compartir listas, etc. Por lo tanto, los experimentos están enfocados a la funcionalidad de la aplicación que se quiere testear y validar. 98 6.1. Gestión de usuarios: Registro Objetivo del experimento: El objetivo de este experimento es demostrar el buen funcionamiento de la funcionalidad de registro del usuario en el sistema. Para comprobar que el registro de un usuario funciona correctamente, este experimento también nos servirá para evaluar el comportamiento de la aplicación a la hora de logarse un usuario. Metodología del experimento: Para la realización de este test se plantean varios escenarios posibles para validar el correcto funcionamiento en todos los casos. Los escenarios que se ejecutan y prueban en este experimento son los siguientes, siguiendo este mismo orden. 1. El usuario no está registrado aún en la aplicación pero intenta logarse, con un usuario inexistente en la base de datos: test1. 2. El usuario se registra con un nombre de usuario ya existente en la base de datos de la aplicación: rafa. 3. El usuario se registra con un nombre de usuario no existente en la aplicación: test1. 4. El usuario accede a la aplicación con sus credenciales pero con la contraseña equivocada. 5. El usuario accede a la aplicación con sus credenciales introducidos correctamente. Finalmente entramos a la sección del perfil para comprobar que se ve el usuario correctamente. Resultados obtenidos: 1. En el primer escenario podemos ver, tal y como se muestra en la imagen, como la aplicación comunica al usuario que hay un error al logarse que puede deberse o al usuario con el que se intenta acceder o a la contraseña introducida. 2. De la misma manera que antes, vemos como la aplicación muestra al usuario que el usuario o el mail introducidos para realizar el registro ya existen en la aplicación y por lo tanto no se puede registrar. 3. Al registrarse con un nombre de usuario y e-mail no existentes, la aplicación consigue registrar al usuario correctamente y devuelve al usuario a la pantalla principal con todas las opciones disponibles, con el usuario, además de registrado, logado en la aplicación. 4. Los resultados son exactamente los mismos que en el primer escenario. La aplicación muestra al usuario que hay un error con el nombre de usuario o con la contraseña introducida y no se puede logar. 5. El resultado es similar al obtenido en el tercer escenario. El usuario se puede logar correctamente y aparece en la pantalla principal con todas las opciones que tienen disponibles los usuarios registrados y logados en la aplicación. 99 Vemos que una vez logado, al acceder a la sección del perfil, nos aparecen nuestros datos, tal y como se muestra en la imagen. En las siguientes capturas de pantalla se muestra los resultados de estos 5 escenarios. En la imagen de la izquierda se muestra el resultado de los escenarios 1 y 4. En la captura del medio se muestra el resultado del escenario 2, y en la última se muestra el resultado de los escenarios 3 y 5. Conclusiones del experimento: Con este experimento podemos concluir que el sistema de Registro/Login de la aplicación funciona correctamente, ya que están controlados los casos de error al introducir los datos o de error de clave primaria en la base de datos al hacer el registro, y al acceder a la aplicación nos encontramos con nuestro perfil correctamente. Además, a lo largo del desarrollo, se han probado casos como introducir menos de 4 caracteres en el usuario o contraseña, y los resultados han sido los mismos que en los casos de error de registro por clave primaria. El resultado también es el mismo si en la sección e-mail no se encuentra una “@”. Así, podemos concluir que esta funcionalidad está correctamente implementada. Otra de las conclusiones que podemos sacar del experimento es que en un futuro sería interesante incluir un sistema que enviara al e-mail introducido un enlace para validar el registro del usuario, al igual que hacen muchas webs. De esta manera, nos aseguraríamos que el usuario y el mail realmente existen. 30. Experimento 1. Escenarios 1 y 4. 31. Experimento 1. Escenario 2. 32. Experimento 1. Escenarios 3 y 5. 100 6.2. Gestión de usuarios: Amistades Objetivo del experimento: El objetivo de este experimento es validar y demostrar el correcto funcionamiento de la parte social de la aplicación. Así, el objetivo del experimento es comprobar que el sistema de amistades, solicitudes, y perfiles funciona correctamente. Metodología del experimento: Para la realización de este experimento, seguimos un conjunto de escenarios consecutivos, de manera que partimos del resultado anterior, para realizar el test siguiente. 1. Miramos desde un usuario las solicitudes de amistad y los amigos. 2. Buscamos desde otro usuario al primer usuario utilizando el buscador introduciendo solo parte de su nombre. 3. A continuación, mandamos una solicitud de amistad al primer usuario comentado. 4. Accedemos de nuevo al buscador y volvemos a buscar el mismo usuario, y comprobamos los resultados. 5. Desde el perfil del primer usuario, accedemos de nuevo a las solicitudes de amistad y la rechazamos. 6. Volvemos al segundo usuario y volvemos a buscar al primer usuario y a mandarle una solicitud de amistad. 7. Desde el perfil del primer usuario, accedemos a las solicitudes de amistad y la aceptamos. 8. Finalmente, comprobamos desde los dos perfiles de usuario que la lista de amistades de cada uno. 9. Borramos al amigo desde la lista de amistad, y comprobamos que ambos usuarios dejan de tenerse como amigos en la aplicación. Resultados obtenidos: Partimos desde el usuario creado en el experimento anterior, test1. Vemos que en el primer paso, al entrar a la sección de amistades, nos indica la aplicación que el usuario no tiene usuarios amigos agregados. Tal y como dice el segundo paso, entramos con el usuario rafa en la aplicación y mandamos una solicitud a test1. Vemos que como resultado al introducir test en el buscador, nos aparece el usuario test1, que es el único usuario que incorpora en su nombre la palabra test. Vemos que una vez mandada la solicitud desaparece el botón de añadir, y si volvemos a buscar al usuario, nos dice que no se encuentran usuarios con ese nombre. Eso es porque si ya está entre tus amigos o ya hay una solicitud entre ambos, el buscador no te muestra el usuario para no poder agregarle de nuevo y mantener la persistencia de los datos en la base de datos. 101 En el siguiente paso, rechazamos la solicitud de amistad desde el usuario test1 y vemos cómo se ha borrado la solicitud de la base de datos y cómo el usuario rafa puede volver a mandar la solicitud ya que puede encontrar al usuario en el buscador. Esta vez, desde test1 aceptamos la petición y vemos como desde ambos usuarios, aparece en la lista de amigos el otro usuario añadido. Finalmente, vemos como al borrar al usuario amigo de la aplicación, desde ambos perfiles no se puede ver al otro usuario en la lista de amistades. Conclusiones del experimento: Una vez contemplados todos los casos, y probado el sistema de borrado de amigos, el buscador de usuarios, el envío de solicitudes y la aceptación y rechazo de éstas, podemos concluir que todas estas funcionalidades funcionan correctamente y por lo tanto la gestión de usuarios de la aplicación funciona de manera correcta. 33. Experimento 2. Amigos. 34. Experimento 2. Solicitudes. 108 Otro resultado interesante obtenido es que se muestra un diálogo en caso de que no exista en la base de datos el producto mencionado, o no se encuentre en el supermercado más cercano, con información relativa a que no se ha podido encontrar el producto. Conclusiones del experimento: Con estas sencillas pruebas realizadas en este experimento, podemos concluir el buen funcionamiento de la funcionalidad comentada. Vemos como el sistema de cambio de precio desde la aplicación funciona correctamente ya que suma lo que corresponde al precio total, y como el hecho de quitar productos también cumple correctamente con su cometido. Además, gracias al experimento hemos podido validar también el correcto funcionamiento de la detección del supermercado más cercano en el que la aplicación intuye que te encuentras a la hora de la sugerencia del precio del producto. 6.7. Planificación de rutas y compra Objetivo del experimento: Este experimento tiene como objetivo la comprobación del correcto funcionamiento de la funcionalidad de planificación de rutas. Así, este experimento intentará validar los resultados obtenidos cuando se solicita calcular una ruta y el comportamiento a la hora de realizar la compra mediante la ruta calculada. Metodología del experimento: Para realizar este experimento comprobamos diferentes escenarios, y comprobamos el resultado de la función heurística del Hill Climbing para comprobar que efectivamente es el mejor de los casos. Los diferentes escenarios son los siguientes: 1. Introducimos diferentes productos en la base de datos que se encuentren en dos supermercados cercanos, con el mismo precio, y comprobamos la ruta que te propone la aplicación. 2. Cambiamos manualmente el precio de los productos de la base de datos, de manera que el supermercado que está más lejos sea el que disponga de los productos más baratos, y comprobamos resultados. 3. Hacemos una lista de la compra general, con productos que aparezcan en los dos supermercados, que sólo aparezcan en uno, con productos que no se encuentren en ningún supermercado cercano, y comprobamos los resultados. 4. Comprobamos la sección DETALLE de la actividad de planificación y añadimos y quitamos productos de la cesta según para comprobar el comportamiento. 109 5. Finalmente, registramos la compra y comprobamos el comportamiento del registro de esta compra. Resultados obtenidos: 1. En este caso, el supermercado que tenemos más cercano es el DIA, aunque los productos también se encuentre en el Mercadona. Aun así, la aplicación nos sugiere que compremos en el Dia, y nos muestra la ruta hacia ese supermercado. 2. Con el mismo caso de los supermercados y productos escogidos anteriormente, pero con un precio bastante inferior en el Mercadona, el resultado que nos muestra la aplicación es el e ir a hacer la compra al Mercadona, que está a una única manzana de diferencia. 3. En la captura proporcionada podemos ver cómo nos indica ir a los dos supermercados ya que en ellos se encuentran todos los productos pendientes. Debido a su cercana distancia, la aplicación nos sugiere ir a comprar cada uno de los productos en el sitio donde se encuentre más barato. 4. Al intentar añadir un producto como comprado, se nos abre un diálogo con el precio propuesto del producto. Vemos que tanto si lo cambiamos como si no, el precio total de la compra que se muestra en pantalla, se muestra correctamente. Además, el botón cambia de color y de texto, y si apretamos el nuevo botón Quitar el precio se resta correctamente del precio final de la compra que se muestra por pantalla. 5. Al registrar la compra, tanto si registramos uno de los productos como si registramos varios, la aplicación te devuelve a la pantalla anterior. Los productos comprados que antes salían como pendientes ahora se muestran en la pestaña de comprados, mostrando la información de la compra como la fecha, el usuario o el supermercado donde se ha comprado. Conclusiones del experimento: Después de las pruebas realizadas en este experimento, podemos concretar que el sistema de planificación de rutas funciona correctamente. Como autocrítica, quizás se podría mejorar la función de coste, o utilizar un algoritmo que fuera más eficiente o fuera mejor calculando la ruta óptima teniendo en cuenta la distancia y el precio. Aun así, tal y como está implementado el algoritmo y la inteligencia artificial, los resultados son coherentes y son bastante buenos, que es lo que buscábamos en un principio al realizar el proyecto. 40. Experimento 7. 110 En cuanto a tiempos, vemos que la aplicación tarda menos de 1 segundo en proporcionarte una ruta y abrir el mapa, con lo cual podemos determinar que, aunque quizás haya algoritmos mejores, este cumple con los requisitos de eficiencia que nos habíamos planteado desde un principio. 6.8. Sistema de recomendaciones Objetivo del experimento: Este último experimento tiene como intención la validación de una de las bazas más interesantes del proyecto a nivel de inteligencia artificial. De esta manera, se comprobará el correcto funcionamiento del sistema recomendador de productos de la aplicación exponiendo varios casos y varias situaciones posibles. Metodología del experimento: Para realizar esta última parte de la validación y los test también estudiamos diferentes escenarios. Cabe realizar que los test realizados son con pocos datos incorporados en la base de datos debido a que de esta manera es más fácil verificar que el funcionamiento es el esperado. 1. Comprobamos las recomendaciones que se le ofrecen a un usuario que no ha realizado ninguna compra. 2. Un usuario con 1 compra de un producto en la base de datos, y otros 3 usuarios que han comprado este producto además de muchos otros, variando las frecuencias de compra de estos productos. Comprobar resultados. 3. Sólo dos usuarios con compras realizadas en la base de datos. Los dos usuarios han comprado exactamente los mismos productos. Comprobar resultados. 4. Muchos usuarios en la base de datos con diferentes compras. Calcular las recomendaciones de cualquiera de los usuarios, obteniendo información no sólo de los productos de la pantalla, sino de la distancia entre los usuarios y el resultado en cuanto a los usuarios más parecidos. Resultados obtenidos: 1. El resultado es que no hay recomendaciones para ese usuario. Al no tener productos comprados, no hay usuario al que se parezca y por lo tanto no se ofrece ningún usuario. 2. Al usuario que sólo ha comprado un producto se le ofrecen 10 recomendaciones. Encajan que las 7 primeras recomendaciones son los productos de estos usuarios que también habían comprado el primer producto, ordenados por su frecuencia. Los tres restantes son un subconjunto al azar, pero también son productos que se encuentran entre estos usuarios parecidos por el producto comprado. 3. El resultado es exactamente el mismo que en el apartado número 1. No hay sugerencias de productos para este usuario. 111 4. De la misma manera que en el segundo punto, obtenemos todo tipo de recomendaciones. Vemos que los usuarios más cercanos efectivamente disponen de los productos que se nos han recomendado. Además, estos productos son efectivamente los productos que más veces aparecen como comprados en la base de datos. Después de comprobar los vectores de productos, efectivamente los usuarios seleccionados son los usuarios que contienen en su mayoría productos que el usuario actual también ha comprado. Por lo tanto, es lógico que sean los usuarios más parecidos. Conclusiones del experimento: En los apartados 1 y 3 podemos ver las carencias de este algoritmo de Collaborative Filtering. Como vemos, al usuario se le recomiendan los productos que él no ha comprado recientemente. Por lo tanto, aunque en el apartado 3 los usuarios que se comparan son iguales, el subconjunto de productos a recomendar está vacío, y por lo tanto no se producen recomendaciones. Por lo tanto, si hay pocos datos, el Collaborative Filtering es un algoritmo con carencias evidentes. Como conclusión, este algoritmo es mejorable. De la misma manera que si hay muchos datos, se puede mejorar la eficiencia teniendo en cuenta la cadena de supermercados en los que compran los otros usuarios al calcular la distancia, o poniendo un filtro para comparar el usuario actual con usuarios que estén cercanos al usuario actual y así evitar hacer la comparación con todos los usuarios del sistema. Es probable que un ciudadano de Galicia se parezca menos un usuario catalán que otro usuario catalán, por razones de cultura y proximidad. Así que esta es otra de las mejoras que se pueden plantear en un futuro. Por lo demás, el experimento ha servido para comprobar que el sistema recomendador se comporta como estaba previsto, y por lo tanto damos el visto bueno al test realizado. 112 113 7. Planificación y presupuesto En este apartado se describe, a través de un diagrama de Gantt, la planificación de tareas que se ha llevado a cabo para la realización del proyecto. A continuación, se detallaran concretamente en qué consisten estas tareas, cómo se han ido desarrollando, y qué problemas o cambios se han ido encontrando. A continuación se determinan los roles que se han utilizado en cuanto a recursos humanos se refiere, relacionándolos con las tareas realizadas, y finalmente se plantea el presupuesto final del proyecto 114 7.1. Diagrama de Gantt En este apartado mostramos el diagrama de Gantt de la planificación del proyecto. Hay que tener en cuenta que el diagrama muestra de qué fecha a qué fecha se ha desarrollado cada tarea. Eso no significa que cuanto más largo es este intervalo, más tiempo se ha dedicado a esa tarea, ya que durante la realización del proyecto el número de horas dedicadas diariamente a éste ha ido variando y no es uniforme. 7.2. Tareas realizadas Con el diagrama de Gantt expuesto anteriormente, en este apartado se explican las tareas realizadas para el diagrama de Gantt. Teniendo en cuenta que el diagrama de Gantt muestra los intervalos de tiempo en los que se ha llevado a cabo las tareas pero no muestra el número de horas empleadas para cada una de ellas, a continuación mostramos una tabla con las tareas realizadas, junto al rol y el número de horas. 41. Diagrama de Gantt 115 Descripción Rol Horas Etapa inicial: Estudio y diseño del problema 39 T1.1 Definición del problema a abordar R1 9 T1.2 Definición de las funcionalidades R1 12 T1.3 Estudio de antecedentes R2 18 Etapa investigación 108 T2 Estudio de tecnologías R2 65 T3 Estudio de algoritmos de IA R2 43 Etapa de desarrollo 577 T4 Planificación de desarrollo R1 13 T5 Diseño y especificación de la aplicación R2 30 T6 Desarrollo de la BBDD R3 50 T7 Preparación y configuración del entorno R3 42 T8 Desarrollo de la comunicación cliente-servidor R3 27 T9 Desarrollo de frontend R3 145 T10 Desarrollo de backend R3 230 T12.1 Estudio de usabilidad y diseño gráfico R2 12 T12.2 Diseño gráfico de la aplicación R3 28 Testeo 120 T11 Testeo de la aplicación R4 120 Documentación 110 T13 Redacción de la memoria R1 110 Total: 954 1. Tareas realizadas. 116 7.2.1. Estudio y diseño del problema a abordar La tarea del estudio y diseño del problema a abordar se puede separar en tres tareas más específicas, que son las siguientes.  Definición del proyecto. Se definió el proyecto que se iba a llevar a cabo, así como el problema que se quería solucionar y diferentes alternativas para poderlo abordar.  Definición de funcionalidades. Se definieron las funcionalidades que se iban a implementar en la aplicación, o posibles funcionalidades que a lo largo del proyecto, según la implementación, se detallaron más profundamente, se descartaron o se cambió el planteamiento de éstas.  Estudio de antecedentes. Se realizó un estudio de antecedentes para ver qué se había hecho y cómo, para así ver posibles carencias o mejoras a las soluciones ya planteadas y coger ideas a la hora de diseñar la aplicación. 7.2.2. Estudio de tecnologías Esta tarea corresponde al estudio de las diferentes tecnologías para el desarrollo de la aplicación que gestionara la lista de la compra. Así, en esta tarea se estudiaron todas las tecnologías definidas en el apartado de “Estudio de tecnologías usadas” para así decidir cuáles emplear. 7.2.3. Estudio de algoritmos de Inteligencia Artificial En esta etapa se llevó a cabo el estudio de diferentes algoritmos de Inteligencia Artificial tanto para el diseño del algoritmo de planificación de rutas como para diseñar el sistema recomendador para así, posteriormente, escoger el más adecuado para el proyecto. Esta tarea se llevó a cabo, como vemos en el diagrama de Gantt, antes de implementar esa parte de la aplicación. 7.2.4. Planificación de desarrollo Esta tarea consistió en la planificación de las tareas que se iban a desarrollar a lo largo del proyecto y organizarlas aproximadamente en el tiempo, delimitando unos tiempos de entrega para así asegurarse cumplir con el plazo 117 7.2.5. Diseño y especificación de la aplicación En esta tarea se definió cómo iba a desarrollarse el diseño de la aplicación. Desde cómo se iban a implementar las funcionalidades, a la estructura de la aplicación, así como la definición de los recursos necesarios para facilitar el desarrollo. 7.2.6. Desarrollo de la BBDD Esta tarea consistió en el desarrollo de la BBDD. Esta base de datos se ha ido modificando según las necesidades. Por ejemplo, hasta que no se necesitó el cálculo del precio de un producto en un supermercado, no se implementó el disparador que lo calculaba. Aun así, pese a las modificaciones, esta fue una de las primeras tareas de implementación que se llevaron a cabo. El desarrollo de la BBDD, al contrario de lo que es habitual, se llevó a cabo en un principio antes de la preparación y configuración del servidor, aunque sí se había configurado ya la base de datos MySQL y los programas específicos para desarrollar el proyecto. 7.2.7. Preparación y configuración del entorno Esta tarea consistió en la preparación de todo el entorno para poder desarrollar e implementar la aplicación. Desde la creación del servidor, a la configuración de las herramientas necesarias cómo por ejemplo el programa Eclipse, pasando por la configuración de la base de datos utilizada. 7.2.8. Implementación de la aplicación Esta tarea se ha basado en la implementación de la aplicación en todos los sentidos. Vemos que en el diagrama de Gantt separamos por funcionalidad, aunque también se puede separar por otras características, como la parte de la aplicación que se está desarrollando: la comunicación entre el cliente y el servidor, la parte de frontend, que corresponde a la capa de presentación con la que interactúa el usuario, y el desarrollo del backend, que corresponde a la capa de dominio y que incorpora desde las clases de dominio generales al sistema de recomendación y el sistema de planificación de rutas. 7.2.9. Testeo de la aplicación A medida que se iban implementando las diferentes funcionalidades, se iban testeando. Así, en vez de dejar el testeo para el final, se ha ido haciendo a medida que se desarrollaban las demás partes de la aplicación. Esto se ha hecho porque si se dejaba el testeo para el final, era probable que hubiera que darle una segunda vuelta a la implementación de la aplicación. Al ir testeando por funcionalidad, el desarrollo de la aplicación se ha hecho más dinámico. 124 Así, como conclusión final, además de proporcionarnos calidad en los datos, el realizar negocios con diferentes supermercados nos supondría una vía de financiación importante del proyecto para poder seguir desarrollándolo y llevándolo a cabo.  Servidores y escalabilidad Otra de las carencias de las que se ha hablado a lo largo del proyecto es el tema de la escalabilidad y los servidores. Por razones obvias, y al ser un prototipo, la aplicación no se ha probado con múltiples usuarios. Es decir, no se sabe la reacción del servidor y de la base de datos si nos encontramos con que múltiples usuarios realizan a la vez peticiones al servidor y a la base de datos. Por lo tanto, este es uno de los factores a tener en cuenta y a estudiar en caso de crear una aplicación comercial a partir del prototipo. Por otra parte, el hecho de disponer de un solo servidor también podría llegar a ser ineficiente. Si construimos una aplicación comercial, no se sabe cuántos usuarios pueden acabar usando la aplicación. Esto implica que podría llegar a ser un número elevado. El hecho de tener un único servidor hace que es más probable que se colapse en caso de tener múltiples peticiones. Además, si en algún momento se cae el servidor, la aplicación deja de funcionar. Habría que trabajar en la línea de tener un conjunto grande de servidores que utilizaran un sistema para que la aplicación no se quede huérfana en caso de caerse uno de ellos. Finalmente, no hay que olvidar que al ser un prototipo, el servidor usado es local. Este hecho tendría que cambiar para poder ofrecer un buen servicio a nivel comercial.  Diseño y usabilidad. En cuanto al diseño gráfico y la usabilidad del sistema, en la sección de Estudio de la usabilidad y el diseño se detallan diversas mejoras a llevar a cabo y con las que trabajar en un futuro. Por ejemplo, una de las carencias más importantes a nivel de diseño y usabilidad del prototipo es la adición de nuevos productos a una lista de la compra. Al ser una lista extensa con todos los productos que existen en la aplicación, es complicado encontrar el producto que buscas si no se te proporciona ya en productos comprados anteriormente o en recomendaciones, que son listas más cortas. Así, una de las mejores de diseño en un futuro es la incorporación de un sistema que diferencie los productos según su tipo y su marca, y añadir un buscador para que de esta manera al usuario le resulte más sencillo añadirlo. Otra de las mejores a nivel de diseño sería incorporar notificaciones push. De esta manera, al usuario le llegaría una notificación al móvil en caso de tener una nueva solicitud de amistad, 125 por ejemplo, y no se enteraría de este hecho únicamente si entra en la sección de solicitudes de amistad de su perfil. Otra de las líneas en las que trabajar es la de adaptar el diseño según la versión de Android utilizada. De esta manera, se podrían añadir botones en la ActionBar de la actividad, o se podría utilizar un diseño más sencillo a la par que intuitivo que no usara el sistema de botones que se ha utilizado, que aunque funciona correctamente, desprovee de espacio físico en la pantalla para incorporar otras características que quizás sean más interesantes. Como conclusión, el diseño y usabilidad de la aplicación, tal y como se ha visto en el estudio realizado, es mejorable.  Inteligencia artificial. Una de las bazas más importantes del proyecto es la inteligencia artificial incorporada. Al ser un prototipo, la inteligencia artificial es relativamente sencilla. Debido también al gran avance que se está llevando a cabo en este sector, que está creciendo a pasos agigantados, podemos concluir que otra de las líneas de trabajo a seguir es la mejora de esta inteligencia artificial. Como hemos comentado, en el sistema recomendador podríamos acabar haciendo un sistema híbrido en vez de únicamente un Collaborative Filtering. Así, aunque el algoritmo se base en el algoritmo que hemos utilizado, podemos utilizar el estudio que se ha llevado a cabo sobre diferentes algoritmos para por ejemplo añadir conocimiento demográfico. Por ejemplo, hay productos muy concretos de los supermercados que sólo usan mujeres, y por lo tanto no sería lógico que se recomendaran a los hombres. Por otra parte, la región en la que se encuentre el usuario y la cultura de esa región también influye mucho en los productos que el usuario puede comprar, y por lo tanto es más probable la recomendación de estos que no los productos más populares en una región lejana. Por lo tanto, en cuanto al sistema recomendador se puede trabajar en la línea de ir añadiendo filtros y herramientas para ampliar el algoritmo y que de esta manera sea un híbrido entre varios de los algoritmos que se han comentado en esta memoria. Por otra parte, en cuanto al sistema de planificación de rutas, también podríamos mejorar al algoritmo, ya que se ha desarrollado un algoritmo bastante básico. Otra de las posibles líneas de trabajo es la de cambiar este algoritmo por un A* para intentar obtener mejores resultados, ya que este algoritmo podría ser capaz de recorrer todos los nodos del problema. Aun así, habría que seguir por la misma línea que el prototipo, y aunque se pueda llegar a cambiar el algoritmo, no hay que olvidar una de las características básicas que hemos querido implementar a lo largo del proyecto, que es la característica de mantener una buena eficiencia temporal de cara al usuario final de la aplicación. Para finalizar, otra de las líneas a tener en cuenta en cuanto al sistema de planificación de rutas sería el cambio o la mejora de la función de coste para que puedan intervenir más parámetros. De esta manera, interesa que no sólo se tenga el cuento la distancia y el precio, 126 sino que también se tengan en cuenta supermercados preferidos, o el hecho de a qué factor le da más prioridad el usuario final, al tiempo o al dinero empleado. Según unas preferencias u otras, la ruta planificada para cada compra puede variar. De esta manera, una de las futuras mejoras es la incorporación de más factores a tener en cuenta en los algoritmos de inteligencia artificial de la aplicación.  Seguridad. Para acabar, hacer especial hincapié en el sistema de seguridad de la aplicación, que ahora mismo es nulo debido a ser un prototipo. Por ejemplo, una de las futuras líneas de trabajo sería la incorporación de un sistema de validación de mail en el registro, para poder evitar la entrada de bots en la aplicación. Por otra parte, en cuanto al registro, incorporar una doble validación de la contraseña, o un sistema de recuperación de contraseña utilizando también el e-mail proporcionado por el usuario. Por otra parte, también en cuanto a las contraseñas usadas en el sistema, habría que usar un sistema cifrado para transmitir estos datos con el servidor, de manera que esto complique la recolección de contraseñas a los diferentes piratas informáticos que pueda haber. De la misma manera, en vez de guardar en la base de datos una contraseña tal cual, una manera óptima de aumentar la seguridad sería la de guardar esta información cifrada, de manera que aunque se acceda a la base de datos de la aplicación, no se disponga información adicional sobre la contraseña. No sólo en el ámbito del uso de contraseñas, sino con toda la información que se transmite entre el cliente y el servidor de la aplicación. Podemos concluir que sería conveniente que desde fuera no se tuviera acceso a esta información y por lo tanto aumentar la seguridad en la línea que se ha comentado es una de las tareas básicas a tener en cuenta si finalmente se transforma el prototipo desarrollado en el proyecto en una aplicación de ámbito comercial real. 127 9. Bibliografía Webs oficiales de las herramientas usadas para la elaboración del proyecto Eclipse: https://eclipse.org/ Java: https://www.java.com/es/ Comunidad para desarrolladores Android: http://developer.android.com/index.html Google play services: http://developer.android.com/google/play-services Google Maps: http://developer.android.com/google/play-services/maps.html SQL: http://www.w3schools.com/sql/ MySQL Workbench: http://www.mysql.com/products/workbench/ Oracle: http://www.oracle.com/es/index.html Wamp: http://www.wampserver.com/en/ Librería externa AIMA: http://www.wampserver.com/en/ Librería externa ZXing: http://code.google.com/p/zxing/ Bibliografía sobre sistemas de recomendación: [1] Francesco Ricci, Lior Rokach, Bracha Shapira, Paul B. Kantor. Springer. Recommender Systems Handbook. [2] Curso online de la universidad de Stanford. http://www.coursera.org [3] FIB. Facultat d’Informàtica de Barcelona. Dept de LSI. Apunts d’intel·ligència artificial Bibliografía sobre planificación de rutas: [4] Wouter Pepping. BMI Paper. VU University Amsterdam. 2009. The Shortest Route: Developing a bicycle route planner for the Netherlands. https://www.few.vu.nl/en/Images/werkstuk-pepping_tcm39-107124.pdf [5] Vi Tran Ngoc Nha, Soufiene Djahel and John Murphy Lero, UCD School of Computer Science and Informatics, Ireland. A comparative study of vehicles routing algorithms for route planning in Smart cities: http://csserver.ucd.ie/~sdjahel/papers/VTM12.pdf [6] Daniel Delling, Peter Sanders, Dominik Schultes, and Dorothea Wagner. Engineering Route Planning Algorithms: http://i11www.iti.uni-karlsruhe.de/extra/publications/dssw-erpa-09.pdf [7] FIB. Facultad de Informática de Barcelona. Departamento de LSI. Apunts d’intel·ligència artificial 128 129 10. Anexo 10.1. Manual de usuario Pantalla principal sin registro previo:  Para registrarse acceda a la pantalla de registro apretando el botón Registro.  Para logarse acceda a la pantalla de Log In apretando el botón Log in.  Para acceder a la funcionalidad de realizar la compra sin haber realizado la lista de la compra previamente, acceda a ella mediante el botón Comprar. Pantalla Registro: Para registrarse en la aplicación, introduzca un nombre de usuario que no exista en la base de datos y que conste como mínimo de cuatro caracteres. A continuación, introduzca también una dirección de correo válida y una contraseña de cuatro caracteres mínimo. Para registrar estos datos, apriete el botón Registrar. Pantalla Log in: Para logarse acceda a la pantalla de Log in, e introduzca sus credenciales, tanto nombre de usuario como contraseña. Una vez introducidas las credenciales, apriete el botón Log in. 130 Pantalla Comprar: Para añadir productos a la lista, apriete el botón Escanear código. A continuación haga una foto al código de barras del producto que quiera añadir a la lista. Modifique el precio del producto si lo cree conveniente y presione el botón Ok. Para quitar productos de la lista, apriete el botón rojo con la cruz correspondiente al producto que desee eliminar de la lista. Si desea ver el precio total de la compra, mire en la parte superior de la pantalla, debajo del botón Escanear código. Pantalla principal logado  Para ver su perfil acceda a la pantalla del perfil presionando el botón Perfil.  Para crear una nueva lista, acceda a la pantalla presionando el botón Crear nueva lista.  Para realizar la compra sin haber hecho la lista previamente, acceda a la pantalla de compra presionando el botón Comprar.  Para gestionar sus listas de compra, acceda a la pantalla de gestión apretando el botón Gestión de listas de compra.  Para acceder a la despensa virtual, acceda a la pantalla presionando Despensa virtual.  Para acceder a las recomendaciones, acceda a la pantalla apretando el botón Recomendaciones.  Para salir de la aplicación, apriete el botón Log out. Pantalla perfil Para ver los datos de su perfil, mire a la parte superior de la pantalla, encima de los botones. Para acceder a las solicitudes de amistad, presione el botón Solicitudes de amistad. Para aceptar una solicitud de amistad apriete el botón verde del usuario correspondiente, y para rechazarla el botón rojo. Para acceder al buscador de usuarios, apriete el botón Buscar amigos. En esa pantalla, introduzca el nombre de usuario que quiere buscar y presione el botón Buscar. Para mandarle una solicitud a un usuario, presione el botón verde al lado del usuario correspondiente. Para acceder a la lista de amistades, apriete el botón Amigos. Si quiere borrar algún usuario de la lista, presione el botón rojo correspondiente al usuario a borrar. 131 Gestión de lista de la compra  Para consultar las listas de compra finalizadas, acceda a la pestaña Finalizadas.  Para consultar las listas de compra pendientes, acceda a la pestaña Pendientes.  Para consultar las listas de compra que han compartido con usted, acceda a la pestaña Compartidas.  Para consultar todas las listas, acceda a la pestaña Todas.  Para crear una nueva lista, acceda a la pantalla apretando el botón Crear una nueva lista.  Para borrar una lista de la compra, apriete el botón rojo correspondiente a la lista de la compra a borrar y confirme que está seguro de hacerlo. Lista de la compra Para añadir productos, acceda a la pantalla apretando el botón Añadir productos. Para consultar los productos comprados anteriormente, las recomendaciones, o todos los productos, acceda a la pestaña correspondiente. Para añadir un producto a la cesta, apriete el botón correspondiente al producto a añadir. Para añadir finalmente los cambios, apriete el botón Guardar productos. Para guardar cambios de productos en la lista de la compra, apriete el botón Guardar lista. Para marcar la lista como finalizada y no poder hacer más cambios en ella, apriete el botón Finalizar lista. Para comprobar el precio total gastado de una lista finalizada, observe la parte superior de la pantalla, encima de las pestañas. Para compartir una lista con otro usuario, o modificar los usuarios que pueden ver la lista, acceda a la pantalla apretando el botón Compartir lista y seleccione o deseleccione los usuarios correspondientes. Una vez realizados los cambios, apriete el botón Aceptar. Si no quiere guardar los cambios, apriete el botón Cancelar Para obtener información detallada de cualquier producto, tanto comprado como no, apriete el producto correspondiente en cualquiera de las listas. Para eliminar un producto pendiente, presione el botón rojo correspondiente al producto a eliminar. Para calcular la ruta óptima de productos pendientes y poder marcar los productos como comprados, acceda a la pantalla presionando el botón Calcular ruta. 132 Ruta calculada Para ver el mapa con la ruta a seguir, presione la pestaña MAPA. Si quiere saber el nombre del supermercado del mapa, presione encima de éste. Si quiere ver los productos a comprar en cada supermercado, presione la pestaña DETALLE. Para marcar un producto como comprado, apriete el botón Comprar. Le saldrá información del producto y podrá modificar su precio en caso necesario. Para quitar un producto de la cesta de la compra, apriete el botón Quitar de los productos relativo al producto correspondiente. Para registrar la compra, presione el botón Registrar compra. Si quiere ver el precio total de la compra, observe en la parte superior de la pantalla, debajo del botón Registrar compra. Recomendaciones y despensa virtual Para acceder a las recomendaciones del sistema, apriete el botón Recomendaciones en la pantalla principal, o la pestaña Recomendaciones en Añadir productos. Si quiere más información del producto, presione el producto de la lista correspondiente. Para acceder a la despensa virtual, apriete el botón Despensa virtual en la pantalla principal. Para obtener más información de alguno de los productos, presione el producto correspondiente en la lista. 133