viernes, 30 de noviembre de 2012

Android y Jenkins: Integración continua

En el articulo Android conoce a Jenkins explicamos como configurar Jenkins para que este consultara periódicamente nuestro repositorio en busca de cambios y compilara la aplicación, eso es una pequeña parte de lo que se puede y debe llegar a hacer si queremos desarrollar una aplicación de calidad. Si queremos tomarnos en serio la integración continua tendremos que crear dos tareas nuevas en Jenkins una para la ejecución de pruebas y otra para el análisis de la calidad del código.

Pruebas automatizadas

Las pruebas son una parte vital para asegurarnos que nuestra aplicación cumple con los requisitos, pero a medida que el proyecto va creciendo va dejando de ser eficaz ejecutar las pruebas manualmente desperdiciando así mucho tiempo que puede ser dedicado para otras cosas.

Para las pruebas usaremos Ant, JUnit y Robotium.

En eclipse creamos un nuevo proyecto de pruebas, la creación y conceptos basicos estan explicados en estos dos articulos Testing from Eclipse with ADT y Testing Fundamentals

Ant

En este caso la única diferencia es que tenemos que indicarle a ant que esta vez el proyecto es un proyecto de pruebas.

 android update test-project -m <main_path> -p <test_path>  

Robotium

Robotium es un framework para la realización de pruebas en Android su uso facilita bastante las pruebas (sobre todo las relacionadas con UI). Para poder ejecutarlas en Jenkins sin problemas debemos colocar el jar de robotium en la carpeta libs/ del proyecto de pruebas y subirlo a nuestro repositorio.

Jenkins

La creación de la tarea es igual que la del articulo anterior, para obtener el código tenemos dos opciones obtenerlo directamente desde el repositorio o clonar el workspace de la tare de compilación. En mi caso voy a usar la segunda opción, ya que reduce el tiempo de ejecución y el consumo de ancho de banda. Para poder realizar la clonación tenemos que instalar Clone Workspace SCM Plugin, una vez instalado abrimos la tarea de compilación y en Post-build Actions agregamos la acción Archive for Clone Workspace SCM.
Luego en el proyecto de pruebas dentro de Source Code Management eligiremos Clone Workspace Parent Project y en lista desplegable elegimos el proyecto principal.

En Build Triggers hay que indicar que la tarea se iniciara al completarse la tarea anterior, en mi caso el nombre de esa tarea es Finder.



Emulador de Android

Cuando creamos un emulador mediante el SDK de Android, este por defecto se guarda en ~/.android/avd/. Por lo que si creamos un emulador con nuestro usuario este no podrá ser accedido por Jenkins ya que mirara en su home y no en el nuestro.

Lo mas simple es iniciar sesión con Jenkins y crear el emulador con el terminal con la instrucción android create avd. En la documentación podemos consultar con detalle todas las opciones de este comando.

Por ejemplo para crear un emulador con Froyo, ejecutaríamos
 android avd create -n nombre -t android-8  

Dependiendo de nuestra combinación HW+SW podemos encontrarnos con un error bastante molesto, al ejecutar el emulador con el usuario jenkins se generara un segmentation fault. Lo raro es que al ejecutarlo con nuestro usuario no hay ningún problema. Leyendo el informe del bug, podemos ver que se encontró un "workaround" para evitar el error, basta con renombrar la librería ANDROID_SDK/tools/lib/libOpenglRender.so. Al renombrar la librería el emulador no la encontrara por lo que hará el renderizado via software.

Build

Ya tenemos configurado el repositorio y el emulador ahora hay que definir que hacer en la compilación. Para eso agregaremos solo una instruccion en la seccion Build de Jenkins la cualr sera Invoke Ant tendremos que especificar el target como:
 clean emma debug install test fetch-test-report  
  • clean: limpia el proyecto
  • emma: indica que se analizara el code coverage
  • debug: aplicacion en modo debug
  • install: instala la aplicación en el emulador
  • test: ejecuta las pruebas
  • fetch-test-report: obtiene el resultado de las pruebas desde el emulador, lo definiremos mas adelante
Si tenemos las pruebas en el mismo repositorio que la aplicación tendremos que especificar que fichero build.xml usara ant ya que al buscar en la raíz encontrara el correspondiente a la aplicación y no al proyecto de pruebas. Para ello en el campo Build File ingresamos test/build.xml o la ruta donde se encuentren nuestro proyecto de pruebas.
Finalmente tendremos que definir dos propiedades en el campo Properties, la ruta del SDK y el target a usar
 sdk.dir=/opt/android-sdk-linux  
 target=android-8  


Emma

Emma calculara el code coverage (cobertura de código) , lo cual es realmente útil para saber que partes de nuestro proyecto están cubiertas por las pruebas. Tendremos que instalar Emma Plugin en Jenkins y agregar en Post-build Action la acción Record Emma coverage report.

Hay que indicar la ruta donde se encuentra el informe de cobertura, en nuestro caso sera en la carpeta bin del proyecto por lo que seria **/bin/coverage*.xml




En caso de que la ruta fuera distinta al ejecutar las pruebas con Emma en la consola de salida se muestra la ruta donde se guardan los informes bastaría con ver donde se guardan y modificar la ruta acorde a nuestro proyecto.

JUnit

Para poder mantener un registro de las pruebas realizadas y saber en detalle cuales fallaron y cuales no, Jenkins necesita el resultado de las pruebas en formato XML y ahi es cuando entra en juego Android JUnit reportbajamos el jar y lo agregamos a la carpeta libs/ del proyecto y lo subimos al repositorio.

Para configurarlo hay que hacer un par de cambios en nuestro proyecto primero nos vamos a AndroidManifest.xml, buscamos el tag instrumentation y cambiamos el atributo android:name
 android:name="com.zutubi.android.junitreport.JUnitReportTestRunner"  
El segundo paso es crear el fichero custom_rules.xml en la carpeta raiz del proyecto



Con esto estamos definiendo el target fetch-test-report el cual ejecutara el comando pull en adb para obtener el informe y lo guardara en reports/junit-report.xml.

A esta altura tenemos ant configurado para que obtenga el resultado de las pruebas desde el emulador, lo siguiente es añadir Publish JUnit test result report en Post-build Actions y definir donde encontrar el  informe si no modificaron el custom_rules.xml anterior esta ruta seria **/tests/reports/junit-report.xml

Ya estamos listos para ejecutar la tarea, si todo sale bien en el dashboard del proyecto tendremos dos gráficos uno que nos indica el estado de las pruebas y otro el estado del code coverage. Tiene que ejecutarse al menos dos veces para poder ver la gráfica con datos. Al hacer click sobre las graficas se mostraran los detalles de cada informe.




Calidad del código

En esta parte nos centraremos en analizar la calidad de nuestro código, buscando código repetido, comprobando reglas de estilo y encontrando posibles bugs mediante análisis estadístico. Para esto crearemos nuevamente una tarea free-style. La configuración del repositorio y la compilación es igual que el proyecto de pruebas salvo que esta vez la compilación en vez la de ejecutarse al finalizar el proyecto principal se ejecutara al finalizar el proyecto de pruebas.

Nos quedaría definido el siguiente escenario: tenemos tareas, Finder, Finder-test y Finder-code-quality. Al hacer un commit se ejecuta la tarea Finder si no hay fallos se ejecuta Finder-test y nuevamente

Build

Nuevamente a la hora de compilar lo único que haremos sera invocar a Ant. El target sera
 findbugs pmd lint  

Ejecutando findbugs y cpd, a continuación veremos que es cada uno y en el caso que no nos interese ejecutar uno de ellos simplemente borramos el target.

FindBugs

FindBugs tal como su nombre indicara buscara bugs en nuestro código mediante análisis estadístico. Precisaremos el jar findbugs-ant el cual en mi caso no venia incluido en la versión de findbugs de Fedora así que lo baje e instale manualmente. Una vez bajado el archivo y descomprimido en /opt/findbugs-x.y.z donde x.y.z es la versión tendremos que copiar el archivo $FINDBUGS_HOME/lib/findbugs-ant.jar a $ANT_HOME/lib

Antes de ponernos a configurar FindBugs tendremos que instalar el plugin para Jenkins que nos mostrara el informe de manera detallada.

Tendremos que definir en ant el target findbugs, agregando el siguiente código al fichero custom_rules.xml  sino existe lo creamos en la raíz de nuestro proyecto NO en el de pruebas.

El tag class indica donde se encontrar los archivos .class tenemos dos opciones forzar la compilación diciendo que el target findbugs depende de algún otro target que genere las clases (debug por ejemplo) mediante el atributo depends o usar las clases generadas por la tarea Finder, esta ultima opción es la que yo estoy usando. Por lo que ustedes tendrán que decidir que es lo que prefieren y adaptar la configuración de findbugs.

Al definir este target necesitaremos especificar el valor de algunas variables en el campo Properties de llamada a Ant.

 findbugs.home=/opt/findbugs-2.0.1
 android.jar=/opt/android-sdk-linux/platforms/android-8/android.jar

Tenemos que indicar la ruta del jar de Android como classpath auxiliar, es decir, es necesario para el analisis ya que se realizan llamadas a sus métodos en caso de no indicarlo cada vez que se haga una instancia de una clase de Android tendremos un error de missing class.

Y como ultimo paso para ejecutar y obtener los resultados de findbugs en Post-build Actions añadiremos Publish FindBugs analysis results y como ruta de los informes **/reports/findbugs.xml

Open Tasks

Con Open Tasks analizaremos nuestro código en búsqueda de tareas tipo TODO o FIXME, que muchas veces se añaden al código para indicar que falta algo por hacer o hay algo que arreglar y así permanecen durante la eternidad. Luego de instalar el plugin añadiendo Scan workspace for open tasks en Post-build Actions podremos configurar los parámetros de la búsqueda.

Como vemos en la imagen, tendremos que indicar que archivos queremos analizar, cuales excluir y los tags a buscar con su respectiva prioridad.

Checkstyle

El estilo del código también debe tenerse en cuenta a la hora de medir la calidad del mismo. Dependiendo del lenguaje con el que estemos trabajando tendremos un estilo definido para cada uno de ellos. Checkstyle se encargara de analizar este aspecto de nuestro código. Me encontré con el siguiente problema, lo mas raro es que si lo ejecutaba con mi usuario funcionaba sin problemas pero al ejecutarse mediante Jenkins daba ese error. Modificando ANT_HOME el problema se solucionaba parcialmente, ahora si lo ejecutaba con el usuario jenkins funcionaba, pero cuando era el propio Jenkins quien lo ejecutaba el error seguía ahí. La solución que encontré fue instalarlo desde el repositorio de Fedora.

Al igual que con findbugs, tendremos que definir el target para ant



No hay un fichero oficial para comprobar el estilo para Android, pero si que hay varios fichero por la vuelta, uno de ellos lo pueden encontrar en android-checkstyle.xml

PMD

PMD analizara el código en busca de posibles errores, variables sin usar, código muerto, demasiado complejo, duplicado, etc. Como siempre descargamos los binarios, y pasamos a agregar el target a Ant. Ya que CPD forma parte de PMD, no usaremos el informe de codigo duplicado ya que se encontrara dentro del informe de PMD.


Y mas de lo mismo, indicar en Post-build Actions que queremos publicar el informe generado por PMD.

Y finalmente tenemos todo listo, no es una tarea difícil pero si que puede ser bastante ardua. Sobre todo al principio si nunca habíamos usado Ant haciendo muchos cambios a base de prueba y error.

lunes, 22 de octubre de 2012

Android conoce a Jenkins




La integración continua es una técnica software en la cual se integran los cambios muy frecuentemente (generalmente horas), tratando de detectar errores lo mas pronto posible, automatizando la compilación y la ejecución de las pruebas.

Para poder desarrollar nuestra aplicación en un entorno de integración continua haremos uso de
  • Ant que se encargara de la automatización 
  • Jenkins sera el encargado de la integración continua.
  • En este caso Git y Bitbucket como control de versiones
Como punto de partida tendremos un proyecto Android con su respectivo proyecto de pruebas, para mas detalles consultar la documentación.

Configuración de Ant

Primero que nada necesitamos indicar que nuestro proyecto va a ser compilado con Ant y donde queremos despegarlo, para ello abrimos el terminal, vamos a la carpeta donde se encuentra nuestro proyecto y ejecutamos:



Como resultado se creara el archivo build.xml 


Jenkins

Hay dos posibles maneras de instalar Jenkins: desde un repositorio o desplegando un war en apache, las instrucciones las podemos encontrar en la documentación.

Una vez instalado Jenkins  abrimos el navegador y entramos a localhost:8080 si vemos la pagina inicial de Jenkins es que todo esta bien, sino tendremos que iniciar el servicio.

Ahora si, ya tenemos a Jenkins ejecutándose y el siguiente paso a dar es añadir el soporte de Git (o el repositorio escogido), lo cual puede hacer fácilmente instalando el plugin Jenkins Git plugin.

Creación de la tarea

Jenkins se encarga de ejecutar tareas, por lo tanto todo lo que queramos hacer tendrá que ser definido como tal. En el panel izquierdo tendremos la opción de crear una tarea, y a continuación nos mostrara una serie de opciones. Para nuestro proyecto Android tendremos que elegir Free-style Project. Ya en la pantalla de creación de la tarea tendremos que configurar lo que queremos hacer, en este caso compilar e instalar la aplicación.

Repositorio

Esta parte no tiene mucho misterio, simplemente es especificar los datos de nuestro repositorio.
  • URL: de tipo git@bitbucket.org:usuario/proyecto.git
  • Browser:  bitbucketweb
  • Browser URL: de la forma https://bitbucket.org/usuario/proyecto 
Ignoren los posibles errores que surjan al indicar la web de repositorio, mas adelante se explicara como solucionarlo.

Planificación

Jenkins tendrá que saber cuando se compilara la aplicación, para integración continua lo más adecuado es que se haga ni bien se detecta un cambio en el código, es decir cada vez que se haga un commit. Por lo que en Build Triggers tendremos que marcar Poll SCM, para que Jenkins consulte el repositorio cada cierto tiempo en busca de cambios, la frecuencia de la consulta se define siguiendo el formato de cron. Por ejemplo "15 * * * *" comprobara el repositorio pasados los 15 minutos de cada hora, es decir 12:15, 13:15, 14:15, etc.

Bitbucket brinda un servicio en el cual es el propio Bitbucket el que notifica a Jenkins de que hubo algún cambio en el código, pero para esto se necesita una url publica para Jenkins.

Compilación e Instalación

A esta altura Jenkins ya sabe de donde obtener el código y cada cuanto comprobar si hay algún cambio, nos faltaría definir como compilar y que hacer después de compilar. La compilación se hará mediante Ant para ello añadiremos dos pasos clean debug para limpiar el proyecto y compilar en modo debug; y debug install para instalar el .apk generado.



Para poder instalar la aplicación tendremos dos opciones usar un dispositivo real o el emulador, en este caso usaremos el emulador. Para ello dependeremos de Android Emulator Plugin podemos hacer el propio plugin cree el emulador en tiempo de ejecución o definirlo nosotros mismo. Si decidimos crearlo a mano en el documento Managing AVDs from the Command line esta muy bien explicado.

Dentro de las opciones avanzadas de compilación encontraremos un campo llamado Properties, en el cual tendremos que indicar donde se encuentra el SDK de Android y la plataforma sobre la que trabajaremos.



Si queremos conservar los .apk generados en cada compilación, tendremos que ir a la sección Post-build Actions, la opción que nos interesa es Archive the artifacts. Especificando la ruta donde queremos guardarlo, por ejemplo para guardarlo en la ruta asignada por defecto y agregando "-debug" al final del nombre del fichero seria: **/*-debug.apk

Ya tenemos la tarea configurada, pero si compilamos ahora mismo fallara. Viendo el log generado veremos que se debe a que no tenemos los permisos necesarios para acceder al repositorio, obviamente si es un repositorio publico esto no pasara.


Dando permisos a Jenkins

Una vez creada la tarea realizar la configuración necesaria para que el usuario Jenkins (desde le cual se ejecuta la aplicación) tenga los permisos necesarios para acceder al repositorio. No sera necesario crear un nuevo usuario en Bitbucket exclusivo para Jenkins ya que se puede configurar una clave ssh otorgando acceso de solo lectura mediante una Deployment Key. El primero paso sera iniciar sesión con el usuario Jenkins, pero por defecto viene desactivado así que tendremos que habilitar el inicio de sesión modificando el fichero /etc/passwd

Una vez tengamos ubicada la linea del usuario Jenkins, cambiaremos /bin/false por /bin/bash para poder iniciar sesión con dicho usuario.



Por ultimo queda asegurarnos que Jenkins tiene permisos para acceder a las herramientas proporcionadas por el SDK de Android, es decir que tiene permisos de lectura en Android-SDK/tools/

Ya terminamos con la configuración en el lado del cliente, solo queda agregar la clave creada en Bitbucket para eso accedemos al panel de administración de nuestro proyecto en Bitbucket creamos una Deploymente key nueva y pegamos el contenido del fichero /var/lib/jenkins/.ssh/id_rsa.pub

Si el repositorio no esta en la lista de host conocidos (.ssh/known_hosts) debemos clonar el repositorio manualmente en una carpeta temporal y cuando se nos pregunte si queremos añadirlo a la lista de host conocidos tendremos que decir que si, ya que Jenkins no es capaz de gestionar dicho escenario.

Y por hoy eso es todo, en el próximo articulo veremos como crear pruebas automatizadas con Jenkins.

lunes, 21 de mayo de 2012

Sincronizando Android con la Nube

Viendo la presentación Developing Android REST client applications se habla dos errores muy grandes que todo principiante comete al implementar servicios web con Android:
  • ejecutar el servicio web en el hilo principal
  • alojar los recursos obtenidos en la memoria en lugar de en almacenamiento permanente
La parte negativa del primer punto es que las transferencias de datos pueden llevar bastante tiempo derivando en una UI lenta y en ocasiones que esta deje de responder. Por otro lado el no persistir los datos se pude pensar que hará nuestra aplicación mas rápida. Pero ¿que pasa si el S.O. decide expulsar de memoria a nuestra aplicación para darle lugar a otra? Que tendremos que volver a pedir los datos al servidor conllevando mas gasto de CPU por lo tanto de batería y el esperar tiempo necesario para volver a transferir el recurso.

En la charla se proponen tres patrones de diseño diferentes:
  • Service
  • Content Provider
  • Content Provider y SyncAdapter
Cada uno de las diseños se pueden ver las transparencias de la charla.

En este caso veamos como se implementa el ultimo de ellos. En los dos primeros patrones tenemos que encargarnos manualmente del estado de los recursos y de las transacciones, pero en el ultimo caso todo esto se hace automáticamente a través de SyncAdapter. SyncAdapter sera el encargado de gestionar el estado de los recursos y actualizarlos cuando sea conveniente, este es el patrón usado por Gmal, Facebook, LastFM, por citar algunos.

Imagen tomada de las transparencias de la presentación.
Como vemos la estructura se divide en cinco partes. La capa mas alta se encarga de mostrar los datos al usuario. La actividad es una actividad común y corriente, que interactúa con el usuario guardando pidiéndole o mostrando los datos que nos interesen. El CursorAdaptar es quien refresca los datos que están en el ContentProvider con la interfaz, mostrando siempre los datos mas recientes. Los datos son almacenados en un ContentProvider, si no quieren usar un content provider para guardar los datos deberán engañar al sistema, creando uno que no haga nada, en StackOverflow se explica mas o menos como hacerlo.

ContentProvider
Como crear un ContentProvider ya se explico en un post anterior así que como es de suponer no se volverá a explicar. Es más, dicho post fue pensado para usarlo como base para este.

Account Authenticator
Para poder sincronizar nuestra aplicación con un servidor primero debemos agregar una cuenta al sistema.  Para ello que mejor que echarle un vistazo a los ejemplos de Google, en concreto a este. El ejemplo también se puede encontrar dentro del SDK que tenemos instalado, pero no es exactamente igual a la versión online, traten de usar la versión online que es la mas actual.

Dentro del paquete authenticator se implementa la gestión de cuentas haciendo uso de tres clases:
  • Authenticator: implementa la gestión de la cuenta.
  • AuthenticationService: define un servicio que instancia a Authenticator para realizar las tareas en el background.
  • AuthenticatorActivity: la actividad mostrada para pedir las claves al usuario.
Para tener todo la gestión de cuentas haremos uso del viejo y querido copy & paste, en un mundo ideal funcionaria sin ninguna modificación pero es demasiado bueno para ser verdad asi que hay que hacer algunas modificaciones. En el ejemplo usa otra dos clases, Constants y NetworkUtilities. Si quieren también las pueden copiar, sino:
  • definir las dos constantes definidas en Constants en la clase Authenticator
  • reemplazar Networkutilities por la clase donde este implementado el acceso al servidor, el método authenticate es el que nos interesa, ya que es con el que se validan las credenciales del usuario.
Si usaron AuthenticatorActivity en lugar de una actividad propia, hay que copiar el fichero xml/authenticator.xml, el contenido de values/strings.xml, y añadir al Manifest la definición del servicio y de la actividad.
La variable android:name indica la ruta de la clase AuthenticatorService.


Con eso si instalamos nuestra aplicación al ir a Settings > Accounts and sync > Add account saldrá nuestro el tipo de cuenta que acabamos de definir.

Tengan muchísimo cuidado al declarar el servicio ya que al estar trabajando con XML es muy fácil meter la pata, en mi caso cuando se creaba la cuenta se iniciaba la sesión sin problema pero mas tarde al volver a intentarlo no se iniciaba la sesión porque no estaba guardando el password de usuario. Todo eso por tener mal los ficheros XML.


SyncAdapter
Con lo anterior ya esta la gestión de la cuenta ahora viene lo que realmente nos interesa como sincronizar nuestro teléfono con un servidor. Nuevamente tendremos que crear un servicio para que se ejecute ocultamente sin molestar a nadie. Para eso se precisan dos clases SyncAdapter y SyncService.

SyncAdapter define las acciones a realizar cuando se lleva a cabo la sincronizacion, en este caso llama al metodo syncLog de la clase VideoLogger.

syncLog implementa lo que realmente se hace al sincronizar, esto puede ir dentro de syncAdapter, pero pero claridad y facilidad de mantenimiento decididí gestionarlo aparte. Como veran primero obtiene todos los objetos PendingMovie que hay almacenados y luego va iterando sobre ellos y subiendolos al servidor, en este caso en concreto el metodo upload, borrara el objeto del ContentProvider una vez recibido el ACK del servidor.


Y SyncService instancia a SyncAdapter comom un singleton y lo vincula al servicio.

Finalmente hay que crear un XML con la definición del syncadapter y definir el servicio en el Manifest.


res/xml/syncadapter.xml

Y eso es todo.

martes, 15 de mayo de 2012

Scrum II: Scrum Team

Imagen obtenida de openclipart

Luego de haber comentado un poco la teoría en la que se basa Scrum, es posible hablar de quienes son los responsables de llevarlo a cabo. La puesta en practica se lleva a cabo en equipos denominados Scrum Team, cada equipo esta formado por Product Owner, Development Team (o equipo de desarrollo) y Scrum Master. Estos equipos son completamente autónomos, multidisciplinarios y auto-organizados. Con este modelo se pretende tener flexibilidad, creatividad y productividad. Entremos un poco en los detalles de cada perfil.

Product Owner
El Product Owner es quien gestiona el valor del producto, es decir quien decide que es lo que hay que hacer, se podría comparar con la figura tradicional del Jefe de proyecto. Product Owner hay uno y solo uno, ni dos, ni tres; únicamente una persona determinada es quien puede cumplir este rol. 

Para realizar la tarea con éxito, toda la organización debe respetar las decisiones tomadas por el Product Owner. Nada de el jefe del jefe del jefe dice A o B, el que quiera cambiar algo que hable con el Product owner, tan sencillo como eso. Si lo convencen bien, sino mala suerte, si esta en ese puesto sabrá lo que esta haciendo.

Las tareas que tiene a cargo son:
  • Definir los elementos del Product Backlog
  • Ordenar el Product Backlog para lograr los objetivos establecidos
  • Asegurarse que el equipo de desarrollo cumple con su trabajo
  • Asegurarse que el Product Backlog es visible, transparente y comprensible para todos
  • Asegurarse que el Product Backlog muestra realmente el trabajo planificado
  • Asegurarse que el equipo entiende un elemento del Product Backlog al nivel necesario
Development Team
Los integrantes del equipo de desarrollo serán los que llevaran a cabo las tareas para poder implementar el incremento del producto. Para poder realizar el desarrollo completo de un incremente logicamente tendrán que ser grupos multi-disciplinarios. La organización del grupo depende de si mismos y las relaciones internas son de igual a igual, no hay diferencias de roles, todos son considerados como desarrollador. A pesar de que cada persona tenga un conjunto de habilidades especifico, la regla anterior tiene que cumplirse por lo que cada uno tiene que ser capaz de saber cuales son sus puntos fuertes y sus puntos débiles. 

El tamaño de los equipos es algo que siempre se discute en cualquier metodología, Scrum particularmente no define una cifra concreta sino que determina dos rangos, uno inferior y otro superior. No es aconsejable que el equipo tenga menos de tres personas, aunque a primera vista parezca algo bueno ya que se reduce el tiempo de comunicación aumentando un poquito la productividad, es muy probable que la productividad ganada se desperdicie cuando el equipo se encuentre con un problema que no es el mas adecuado para sus habilidades. Y en el caso contrario equipos de de más de nueve personas requiere mucha comunicación llevando a una reducción de la productividad.

Una posible combinación para un equipo podría tener los siguientes roles: ingeniero de software, arquitecto, analista, programador, tester y diseñador de UI.

Scrum Master
El Scrum Master es el director de la orquesta, tiene que ser capaz de sincronizarse a la perfeccion con el equipo tratando de eliminar todos los posibles obstaculos que aparezcan por el camino. Gran parte de su tarea es estar pendiente de que el equipo de desarrollo siga las pautas de Scrum (teoria, practicas y reglas). Otra de sus funcionalidades es de actuar como un enlace entre el equipo y el mundo exterior, decidiendo cuando el equipo puede o no interactuar con alguien del exterior.
Brinda tres tipos de servicio:

  • Servicios para el Product Owner
    • Proveer de técnicas eficaces para la gestión del Product Backlog
    • Comunicar el objetivo del Product Backlog al equipo de desarrollo
    • Enseñar a todo el equipo como diseñar elementos del Product Backlog
  • Servicios para el Equipo de desarrollo
    • Ayudar con la organización del equipo
    • Ayudar con la creación de un producto de gran valor
    • Eliminación de obstáculos
  • Servicios a la organización
    • Guiar a la organización a adoptar Scrum como metodología
    • Generar cambios que produzcan un aumento en la productividad de equipo
    • Trabajar coordinadamente con otros Scum Masters para aumenta la eficacia de Scrum en la organización.
    • Planificar la implementación de Scrum con la organización

Los servicios que brinda un Scrum Master como puede verse son muchos y muy variados, sin duda que es un perfil muy flexible. Es una pieza clave para el desarrollo de Scrum, al principio sera un guía, un instructor enseñando al equipo con mucha frecuencia, luego que el equipo adquiera experiencia tendrá que enfocarse en la motivación, para que esta no decaiga.

Para la próxima eventos y artifactos.

viernes, 4 de mayo de 2012

Android: Creación de un ContentProvider

Un ContentProvider es una interfaz que nos brinda Android para acceder a una base de datos que se encuentre en nuestro teléfono. Y hacer que las aplicaciones puedan compartir información fácilmente.

Los pasos a seguir para la implementación son los siguientes:
  1. Extender la clase ContentProvider
  2. Crear la base de datos
  3. Implementar getType
  4. Implementar onCreate
  5. Implementar los metodos CRUD
  6. Registar el ContentProvider en AndroidManifest.xml

Se va a explicar como crear un Content Provider que llevara un registro de los ficheros que abre un usuario.

Extender la clase ContentProvider
Al definir que nuestra clase extiende ContentProvider se nos crear el esqueleto básico de nuestra clase.
Que debería ser algo así:


Crear la base de datos
Ya con la estructura creada, tenemos que definir una URI para nuestra base de datos, para que el sistema pueda identificarla. En el futuro cuando llegue el momento que queramos realizar alguna consulta a la base de datos se hará a través del URI que vamos a definir. Se definen en la linea 2 y 3.

Ademas del URI, hay que definir una serie de propiedades, entre paréntesis se indica el numero de linea:
  • Tipos de URI, un ítem especifico o un conjunto de ellos (6 - 11)
  • La base de datos, nombre, versión y nombre de la tabla (14 - 20)
  • Columnas de la tabla y su respectivo indice (23 - 28)
  • Controlador de peticiones (30-36)

Ahora hay que pasar a la creación de la BD, para ello hay que implementar SQLiteOpenHelper como una clase privada. Y como pueden ver en la constante CREATE_TABLE se define la creación de la tabla con SQL usando las columnas definidas anteriormente. Mediante SQLiteOpenHelper el inicio de la base de datos se hace de manera perezosa, es decir hasta que no se necesita no se inicia. Evitando que nuestra aplicación se inicie mas lentamente, y que surjan errores relacionados con la base de datos al iniciar la aplicación.



Implementar getType

Este metodo se encarga de analizar la consulta y decidir que tipo de datos se esta consultando. Los dos tipos de datos fueron definidos en CONTENT_TYPE_LISTCONTENT_TYPE_ITEM, el tipo de datos debe empezar por vnd.android.cursor.dir/ y vnd.android.cursor.item/ para una lista y un item especifico, respectivamente.



Implementar onCreate

Como estamos usando SQLiteOpenHelper, tan solo le indicamos que queremos crear la base de datos y  este mismo ya se encarga de hacerlo cuando sea necesario.


Implementar los metodos CRUD
Al definir como realizar las consultas a la base de datos tenemos que ver si se trata de un item especifico  o de todos.

Registar el ContentProvider
Suponiendo que nuestro ContentProvider se encuentra en un paquete llamado provider, tenemos que registrarlo en el Manifest

viernes, 20 de abril de 2012

Scrum I: La base

Scrum es un framework para la gestión y desarrollo de proyectos software mediante un enfoque iterativo e incremental. El objetivo de Scrum es poder resolver problemas complejos de manera productiva y creativa, creando un producto con la mayor calidad posible. Al ser un proceso con iteraciones de corta duración (como máximo un mes) el feedback obtenido del cliente es constante y la evolución es mas cercana a lo que desea el cliente.

Scrum esta compuesto de cinco elementos: equipo, roles, eventos, artefactos y reglas; siendo cada uno de ellos esencial para su funcionamiento. Estos elementos se cubrirán en detalle en otros articulos.

Hay tres pilares que hay que tener siempre en cuenta a la hora de trabajar con Scrum: transparencia, inspección y adaptación.

Transparencia
Los aspectos importantes del proyecto deben ser visibles para todo el entorno, usando un lenguaje común y bien definido asegurándonos que todos entienden lo mismo por el mismo termino.

Un clásico ¿Cuando algo esta terminado? Cada persona puede dar una respuesta diferente a esa pregunta.

Lo que se pretende con la transparencia es saber en todo momento en que punto nos encontramos con nuestro proyecto y hacia donde vamos.

Inspección
Sino tenemos transparencia llevar a cabo una inspección seria una tarea extremadamente tediosa, improductiva y seria realmente difícil evaluar la situación actual. Por eso al tener un proceso transparente facilita enormemente la inspección de nuestra situación actual y de como vamos avanzando hacia nuestro objetivo.

La inspecciones deben realizarse con frecuenta pero sin llegar al punto de que obstruya el trabajo. Las inspecciones van de la mano con las adaptaciones, en el siguiente punto se explicara como ponerlas en practica.

Adaptación
Luego de una inspección, los errores o desviaciones detectados que sobrepasen los limites de aceptación deben solucionarse.  Los ajustes deben hacerse cuanto antes mejor, minimizando así el grado de desviación, la cantidad de errores actuales, y se evita el arrastre de errores; todo esto ayuda a mantener la planificación y el coste inicial.

Formalmente Scrum define cuatro puntos de inspección y adaptación:
  • Sprint Planning
  • Daily Scrum
  • Sprint Review
  • Sprint Retrospective

miércoles, 18 de abril de 2012

Protocolos de arranque y configuración

Address Resolution Protocol
Primero que nada aclara que el protocolo de arranque y configuración seria RARP, pero es mucho mas claro explicar ARP para entender RARP, ya que es su caso inverso.

Address Resolution Protocol o ARP, es un protocolo que partiendo de una dirección de un protocolo de nivel superior (TCP, FTP, TELNET, etc) nos permite obtener la dirección Ethernet de un dispositivo.

Generación de paquetes ARP
Supongamos que trabajamos con el protocolo IP a nivel de red. Al enviar un mensaje desde el host A al host B, solo conocemos la direccion IP de la maquina de destino, pero a nivel de enlace el paquete es encapsulado en una trama Ethernet, por lo que sera necesario saber la dirección Ethernet de nuestra maquina destino (en caso de estar en la misma red) o de la maquina a través de la cual se hará el enrutamiento. Este proceso se hace media broadcasting, al ser un procedimiento muy costoso cada cliente mantiene una tabla de correspondencia con con los pares IP-Ethernet.

Recepción de paquetes ARP 
Como se dijo anteriormente cuando un terminal necesita determinar la dirección Ethernet de una maquina,  lo hará mediante un broadcast. Cuando una petición de resolución llega a un cliente, primero se actualiza la tabla de correspondencia (para evitar futuros broadcast) y luego se comprueba si nuestra dirección de protocolo es la buscada. Si el mensaje no va dirigido a nosotros se descarta, en caso contrario se responde al dispositivo que genero el mensaje indicándole nuestra dirección Ethernet.

Para consultar la tabla de correspondencia podemos ejecutar arp -a


Como se dijo al principio el caso inverso, es RARP, es decir conocemos la dirección física del dispositivo y queremos saber la dirección IP.


Suponiendo que tenemos que mandar un mensaje desde A (.10) a B (.20), la secuencia de mensajes de ARP es la siguiente:

  1. arp who-has 192.168.1.10 tell  192.168.1.20
  2. arp reply   192.168.1.20 is-at 00:11:22:33:44:55

Esto se puede ver perfectamente con Wireshark.

Bootstrap Protocol
Para lidiar con los problemas del broadcast limitado de RARP (255.255.255.255) surge BOOTPl objetivo de este protocolo es saber la IP de un host a partir de su dirección física. Se basa en UDP usando los puertos 67 y 68  para el servidor y el cliente respectivamente. 

El mayor problema de BOOTP es que el administrador de la red debe introducir manualmente la tabla de correspondencia IP y Ethernet, para evitar eso BOOTP evoluciono a DHCP.

Dynamic Host Configuration Protocol
DHCP se encarga de automatizar la configuración (IP, gateway, mascaras, etc) de los dispositivos. Para el cliente es como si usara BOOTP, ya que usa los mismos puertos y protocolo. La gran diferencia con los protocolos anteriores es que el servidor DHCP no tiene porque estar en la misma red, siendo necesario un agente re-transmisor. Cuando el cliente desea saber su IP genera un mensaje DHCP discover mediante broadcast, en caso de que el servidor se encuentre en la misma red le responde directamente sino el agente de retransmisión re enviara el mensaje al servidor.

  • discover: enviado desde al servidor para solicitar una IP, puede sugerir la IP deseada.
  • decline: rechaza la IP solicitada por el cliente.
  • offer: el servidor le ofrece una configuración al cliente.
  • request: es un mensaje generado por el cliente para confirmar/rechazar ofertas.
  • ack / nak: confirmación / negación de un mensaje de tipo request

lunes, 9 de abril de 2012

Permisos de acceso y Capifony

En el ultimo post se explico como desplegar un proyecto Symfony 2 con Capifony. Dependiendo del servidor con el que estemos trabajando debemos tener mas o menos cuidado con los permisos de usuario. Git en concreto solo guarda información sobre el bit ejecutable de un archivo. En mi caso al desplegar me encuentro con que el servidor se queja de los siguiente:
  • Carpetas 775 en lugar de 755
  • Archivos 664 en lugar de 644
Al intentar servir una pagina web en la que el archivo o la carpeta no tenga los permisos adecuados , se genera un error 500. Así que hay que hacer algo para realizar los cambios pertinentes. Seria bastante estúpido, montar todo Capifony para desplegar cómodamente con la ejecución de un comando para tener que cambiar los permisos de los ficheros manualmente.

Por defecto Capifony le dará permisos de escritura al grupo, asi que para ello hay que agregar a Deploy.rb la opción:
 set :group_writable, false  

Con eso están solucionados los permisos de las carpetas, sin embargo para los ficheros no hay una opción que podamos modificar. Mirando el código de Symfony2.rb, cuando se despliega el código la ultima tarea ejecutada antes del commit es deploy:symlink asi que teniendo esto en cuenta podemos modificar deploy.rb para que cambie los permisos de los ficheros cuando termine de desplegar. Yo solo necesito eliminar los permisos de escritura para todos los que no sean el propietario.
 after "deploy:symlink" do  
  run "cd #{latest_release} && chmod -R go-w web/"  
 end  


sábado, 7 de abril de 2012

Desplegar Symfony2 con Capifony

Seguro que a más de uno con tan solo escuchar la palabra desplegar se le pondrán los pelos de punta. Si hay algo importante en las metodologías ágiles es el famoso DRY (don't repeat yourself), ¿porque romper con ese enfoque para desplegar? no tiene ningún sentido desplegar a la vieja usanza, lidiando con ver que ficheros subir a producción, cuales no y empezar a subir los ficheros mediante FTP o rsync. Para evitarnos esos dolores de cabeza es donde Capifony entra en juego. Capifony nos permitirá desplegar nuestro proyecto con tan solo un comando, tan sencillo como cap deploy. Aunque a ese estado no se llega por arte de magia, primero habrá que realizar ciertas instalaciones y configuraciones, así que vamos a ello.


Salvo que se indique lo contrario las instrucciones deben ser ejecutadas DESDE donde se desplegara la aplicación.

Instalación de Capifony
Para instalar Capifony debemos tener instalado RubyGems y usaremos capistrano_rsync_with_remote_cache para poder desplegar con mayor rapidez, ya que solo se subir los cambios realizados y no todo el respositorio.
 sudo apt-get install rubygems  
 sudo gem capifony  
 sudo gem capistrano_rsync_with_remote_cache  


Configuración del entorno
Lo más cómodo (y seguro) es usar ssh con nuestra clave publica, en lugar de introducir el password cada vez que vayamos a desplegar. En caso de no tener una clave RSA generada, crearla es tan fácil como seguir los pasos del asistente que se nos muestra al ejecutar:
 ssh-keygen  

Copiar la clave publica al SERVIDOR.
Personalmente tuve algunos problemas al conectarme y tratar de copiar mi calve publica desde el terminal, así que tuve que copiarlo mediante cPanel. Hay que copiar el fichero ~/.ssh/id_rsa.pub (nuestra maquina) a ~/.ssh/authorized_keys (servidor)


Para probar si la clave quedo bien instalada, hay que ejecutar:
 ssh usuario@ip -p puerto  


Si en nuestro servidor conviven PHP 5.2 y 5.3, y en el PATH solo se encuentra la versión 5.2, debemos agregar 5.3 al PATH, sino tendremos problemas (ver la ultima sección del post). Para hacerlo tenemos que modificar el fichero (en el servidor) ~/.bashrc y añadir la siguiente linea:
 PATH=/path/to/php5.3:$PATH   

Cerramos la sesión y listo.

Configuración del proyecto
El proyecto se puede desplegar de dos maneras: obteniendo el código desde desarrollo o desde un repositorio. Se detallara como hacerlo desde un repositorio externo, para ver como hacerlo desde desarrollo consultar la documentación de Capifony.

Para crear los ficheros necesarios de capifony basta con ejecutar.
 cd /path/to/project  
 capifony .  

Esto nos creara dos archivos:

  • Capfile: se encuentra en la raiz del proyecto, es el ejecutable que indica que estamos trabajando con Symfony.
  • Deploy.rb: este fichero se encuentra en app/config/ y se usara para configurar Capifony.
Ahora hay que editar Deploy.rb para configurar Capifony, vayamos por partes.

En esta sección se define lo que es la aplicación en si básicamente el nombre y donde se despliega.
 #Application 

 set :application, "acme" 
 set :domain,   "#{application}.com" 
 set :deploy_to,  "/path/to/project" 
 set :app_path,  "app" 
 set :keep_releases, 3 

 role :web,    domain 
 role :app,    domain 
 role :db,     domain, :primary =&gt; true 

 set :model_manager, "doctrine"  

La mayoría de los parámetros dejan bien claro que es lo que hacen, aunque algunas aclaraciones no estarían de mas:

keep_releases
es la cantidad de versiones (las mas nuevas) que se dejaran en el servidor al ejecutar cap deploy:cleanup, es decir si desplegamos 10 veces, tendremos 10 versiones en la carpeta releases, al realizar el clean up se eliminar las versiones mas viejas dejando únicamente las mas nuevas, en este caso tres. 

role
si estamos desplegando solo a una maquina, hay que dejarlo tal cual esta, pero si necesitamos desplegar en varias al mismo tiempo, deberá ser algo así:
 role :web, "subdom1.domino.com", "subdom2.dominio.com", "subdom3.dominio.com" 
 role :app, "subdom1.dominio.com", "subdom2.dominio.com", "subdom3.dominio.com" 
 role :db, "db.dominio.com"  

La configuración al repositorio es muy simple,  ssh_options[:forward_agent] = true le indica a capifony que estamos usando ssh para acceder al repositorio, y que la clave se encuentra en nuestra maquina, sino habría que indicar el usuario y el password.
 #Repository  
 set :repository, "url"  
 set :scm,     :git  
 set :deploy_via, :rsync_with_remote_cache  
 set :git_enable_submodules, 1  
 ssh_options[:forward_agent] = true  

Los ficheros compartidos (shared), como lo indica su nombre son compartidos, compartidos entre versiones, por lo que se mantienen de versión a versión. En las ultimas dos opciones se indica que cada vez que se despliegue se actualicen los vendors y se instalen los assets (imágenes, css, etc que se encuentran dentro de un Bundle).
 #Symfony2  
 set :shared_files,   ["app/config/parameters.ini"]  
 set :shared_children,   [app_path + "/logs", web_path + "/uploads", "vendor"]  
 set :update_vendors, true  
 set :dump_assetic_assets, true  

Finalmente se configura el acceso al servidor, si trabajamos en un servidor compartido es IMPORTANTISIMO, indicarle a Capifony que no puede usar sudo, ya que generara problemas de acceso, porque no tendremos privilegios de administrador.
 #Server connection  
 set :user, "user"  
 ssh_options[:port] = "port"  
 set :use_sudo, false  

Despliegue
Finalmente tenemos todo listo para hacer el despliegue.

La primera vez hay que crear la estructura para Capifony. Así que desde la carpeta de nuestro proyecto ejecutamos
 cap deploy:setup  

El cual creara una estructura como la siguiente:
 `-- /path/to/project  
  |-- current   
  |-- releases  
  `-- shared  
   |-- log  
   |-- config  
   `-- web  

Cada vez que despleguemos se creara una carpeta en releases con el timestamp actual, y se enlazara current con la ultima versión.

Un fichero fundamental es app/config/parameters.ini, antes de ejecutar el primer despliegue, tendremos que copiarlo a shared/app/config/parameters.ini


 scp -P puerto app/config/parameters.ini user@domain:/path/to/project/acme/shared/app/config/parameters.ini  

¡Ahora si estamos listos para desplegar!
 cap deploy  

Si, todo fue bien (esperemos que si) nuestra aplicación ya esta desplegada en producción. Y por si fuera poco Capifony nos permite acceder a la consola de Symfony directamente desde nuestra maquina, para ver todos los comando disponibles ejecutar cap -T

Posibles problemas
Sin acceso root
Leé nuevamente la sección Configuración  del proyecto ;)

No such file or directory
Este error me surgio en dos ocasiones, una haciendo referencia a una carpeta de un Bundle y otra a web/images/ y web/js/.

En el primer caso esto pasa cuando en el fichero deps en la URL de algún bundle tenemos  git=git://... en lugar de  git=http://... 

En el otro caso, capifony busca las carpetas web/images/ y web/js/ por lo que al no encontrarlas lanza el error, para solucionarlo hay que crear la carpeta en cuestión en nuestro proyecto con un fichero vacio (para que la detecte git) y agregarla al repositorio.

Parse error: syntax error
En concreto este error me dio bastante problemas, después de muchas horas pude dar con la fuente del problema. El error se genera al indicar manualmente (porque el default es 5.2) el path para el ejecutable de PHP 5.3 para reinstalar los vendors, cuando se terminan de actualizar se actualiza el bootstrap, y en ese momento es cuando se genera el error. Ya que la construcción del bootstrap se hace con el ejecutable de PHP que se encuentra en el path.

Para solucionarlo hay que agregar al PATH la ruta donde se encuentra PHP 5.3. En caso de no poder modificar el path por algún motivo en concreto habría que modificar el shebang de los ficheros que están dando problemas, indicando manualmente la ruta de PHP 5.3, esto ultimo no es muy aconsejable, pero bueno nos puede sacar de un apuro.

miércoles, 28 de marzo de 2012

Symfony 2: múltiples formularios en una página

Al momento de usar dos formularios no relacionados en la misma pagina, surgieron mas complicaciones de las que me esperaba. Aunque cada formulario estuviera definido en su propio controlador y funcionaran correctamente cuando estaban aislados, al mostrarlos en la misma pagina obtuve dos errores:
  • This form should not contain extra fields
  • The CSRF token is invalid
La manera de solucionarlo fue asignarle un nombre a cada formulario para comprobar que la solicitud esta asociada a dicho formulario. Para poder darle nombre a un formulario hay que acceder al servicio brindado por FormFactory usando el metodo createNamedBuilder. Un ejemplo con la estructura básica seria el siguiente:


Un par de aclaraciones, Acme es una entidad, AcmeType es un formulario definido en dicha clase.

Como se puede ver, el nombre del formulario es acme_form, por el cual se puede identificar cual fue el formulario que genero la petición POST.  

viernes, 23 de marzo de 2012

Symfony 2: Aislamiento de pruebas

La base de datos es parte de nuestra aplicación por lo que también debe formar parte de las pruebas. Ya que sino las pruebas estarán incompletas y dejaran un agujero en la calidad de nuestro software.

Las pruebas a una base de datos deben hacerse de manera aislada. ¿Que pasaría si una prueba corrompe la base de datos? Nuestro entorno de desarrollo se vería afectado y las siguientes ejecuciones de otras pruebas podrían fallar. Por lo que habría que solucionar el problema restaurando la base de datos. Seguro que nadie quiere molestarse en perder tiempo volviendo a un estado fiable de la base de datos.
Un par de cosas a tener en mente a la hora de realizar las pruebas, que sean cortas y concisas; y que la base de datos no tenga gran cantidad de datos (salvo que sea necesario) para poder ejecutar las pruebas rápidamente. 

Para lograr iniciar las pruebas siempre en el mismo estado y por ende que los cambios no se reflejen en la base de datos, tenemos que usar Doctrine Fixtures. Los fixtures permiten definir los datos que necesitamos  para una ejecución correcta de las pruebas. Estos deben ir definidos en la ruta AcmeBundle/DataFixtures/ORM, y su definición es bastante sencilla.



Y por ultimo hice un pequeño shell script con las ordenas para borrar el esquema actual, crear uno nuevo y cargar los datos.



Con eso ya tenemos listo nuestro entorno de pruebas.

jueves, 15 de marzo de 2012

Autentificación con Symfony2 y PHPUnit

Al momento de hacer pruebas es bastante mas comodo hacer la autentificación mediante HTTP basic que manejando los formularios con el crawler de Symfony2 (que por cierto me da bastantes problemas). Para poder iniciar sesion con los datos de un usuario en las pruebas, tenemos que agregar al fichero config_test.yml lo siguiente:

 security:  
   firewalls:  
     main:  
       pattern:  /.*  
       http_basic:  
         realm: "Secured Area"  
         provider: fos_userbundle  
       logout:   true  
       security:  true  
       stateless: true  
       anonymous: true  

En mi caso uso FOSUB como proveedor de usuarios, si se usa otro proveedor obviamente habria que cambiarlo.

Y finalmente en las las pruebas hay que crear el cliente como se indica en la documentación de Symfony.

 $client = static::createClient(array(), array(  
   'PHP_AUTH_USER' => 'username',  
   'PHP_AUTH_PW'  => 'pa$$word',  
 ));  

Algo bastante sencillo para los dolores de cabeza que me dio.

miércoles, 14 de marzo de 2012

Latex: instalar moderncv

Los paquetes de Latex que vienen empaquetados en Ubuntu son bastante viejos, pero por un tema de pereza y espacio (unos 2GB, para instalar manualmente la ultima versión), sigo usando lo que viene por defecto con el sistema ya que no tengo que hacer nada muy avanzado ni complejo. Lo uso para escribir documentación y para hacer mi CV.

El paquete que uso para mi CV es moderncv, hay que instalarlo manualmente y siempre me olvido como hacerlo, así que ahí va el mini tutorial:

Descargamos el zip desde la pagina oficial y desde la carpeta se descomprimió ejecutamos lo siguiente:
 sudo rm -rf /usr/share/texmf-texlive/tex/latex/moderncv/  
 sudo mv moderncv/ /usr/share/texmf-texlive/tex/latex/  
 sudo texhash  

La primer linea es para eliminar el paquete obsoleto de Ubuntu, la segunda para instalar el paquete nuevo, y la ultima para actualizar las referencias internas de Latex. Y listo, nada mas.

lunes, 12 de marzo de 2012

Android + Symfony2: Autentificación

Hoy en día una tarea bastante común es validar las credenciales de un usuario remotamente. En mi caso necesito que una aplicación ejecutándose en Android se valide en el sistema principal que esta construido con Symfony2 y con FOSUserBundle como proveedor de usuarios.

Ya que FOSUB se encarga de la validación en el sitio web, lo ideal y mas lógico seria que también se encarga de la validación remota, evitando duplicar trabajo y cometer errores. En esencia es el mismo escenario que cuando el usuario quiere iniciar sesión desde un navegador tradicional. Pero con algunas diferencias, así que manos a la obra.

Symfony2
En nuestro proyecto de Symfony tenemos que definir un firewall para hacer accesible la autentificacion via HTTP:

security.yml
 api:  
  pattern: ^/api/.*  
  stateless: true  
  security: true  
  http_basic:  
    realm: "API"  

access_control:
  - { path: /api/, role: ROLE_USER }

Con estas lineas presentes en el firewall, cada vez que se quiera acceder una ruta del siguiente tipo <nuestro-domino>/api/ se generara una petición para iniciar sesión mediante HTTP.


routing.yml
 api_login:  
   pattern: /api/login  
   defaults: { _controller: AcmeUserBundle:Security:apiLogin }  


En el rounting es necesario indicar el controlador y la acción a realizar.


SecurityController
 public function apiLoginAction()  
 {  
   $response = new Response();  
   $response->setContent('<html><body>OK</body></html>');  
   $response->setStatusCode(200);  
   $response->headers->set('Content-Type', 'text/html');  
   
   return $response;  
 }  


Y finalmente en el controlador generamos la respuesta, es muy importante indicar el código html de la respuesta para poder saber en Android si el login fue correcto o no.



Android
En Android hay que implementar la siguiente funcion, creando un cliente HTML y dandole una peticion GET para acceder a la URL.

  1 public int login(String username, String password)
  2 { 
  3     HttpClient httpClient = new DefaultHttpClient();
  4      
  5     //construir peticion get 
  6     HttpGet httpGet = new HttpGet("url");
  7     httpGet.addHeader(BasicScheme.authenticate( 
  8             new UsernamePasswordCredentials(username,password), "UTF-8", false)); 
  9      
 10     //ejecutar get y recibir respuesta 
 11     HttpResponse response = null; 
 12     Boolean error = false; 
 13     try { 
 14         response = httpClient.execute(httpGet); 
 15     } catch (ClientProtocolException e) { 
 16         error = true; 
 17         e.printStackTrace(); 
 18     } catch (IOException e) { 
 19         error = true; 
 20         e.printStackTrace(); 
 21     } finally{ 
 22         //cerrar conexion htl y liberar recursos
 23         httpClient.getConnectionManager().shutdown(); 
 24     } 
 25      
 26     //devolver algun codigo (exito, fallo, error, etc) 
 27 }

Este es el caso mas básico de autentificación, ya que al ser HTTP Basic, el usuario y el password van en texto plano. Pero para la etapa de desarrollo y depuración es bastante útil.


Y con esto estaría todo funcionando. Mas adelante me tocara implementar un inicio de sesión para producción (así que tendrá que ser seguro), así que eso ya vendrá en otro post.

jueves, 8 de marzo de 2012

Instalar PHPUnit en XAMPP

PHPUnit es un framework para la realización de pruebas unitarias en PHP. Mi entorno de desarrollo normalmente es XAMPP, asi que vamos a ver como se instala PHPUnit en XAMPP.

cd /opt/lampp/bin

sudo ./pear config-set auto_discover 1 
sudo ./pear install pear.phpunit.de/PHPUnit

Y por ultimo habria que indicadarle a nuestro IDE donde encontrar el ejecutable de PHPUnit, su ruta es /opt/lampp/bin/phpunit

¿Complicado no?