Integración Continua en Aplicaciones Web con Oracle ADF – Parte 2

Por Alexis Lopez Oracle ACE Associate
Publicado en Agosto 2016

En la primera parte de esta serie de 5 artículos describimos brevemente el marco de trabajo Oracle ADF y su versión gratuita, tanto para desarrollar como para desplegar, ADF Essentials. También hablamos de la práctica de Integración Continua y su importancia en el desarrollo de aplicaciones usando dicho marco de trabajo.

En esta segunda entrega, comenzaremos a describir las diferentes herramientas que componen nuestro ambiente de Integración Continua, específicamente hablaremos de la herramienta oficial de desarrollo (IDE) para Oracle ADF: Oracle JDeveloper. También hablaremos de Git como sistema de control de versiones (VCS), su integración con JDeveloper y presentaremos algunas herramientas para la administración de repositorios Git.

Acerca de Oracle JDeveloper
La herramienta oficial de desarrollo (IDE) para Oracle ADF es Oracle JDeveloper, es gratuita y cuenta con instaladores para Windows, Linux y Otros. También existe un plugin para eclipse llamado Oracle Enterprise Pack for Eclipse con el que se pueden crear aplicaciones usando Oracle ADF en dicho IDE, pero no cuenta con toda la cantidad de asistentes que se encuentran en la herramienta oficial y por lo tanto, estos artículos asumen que se usará Oracle JDeveloper.

Es importante anotar que cada versión de Oracle ADF corresponde a una versión de Oracle JDeveloper y que éste cuenta con un servidor Weblogic integrado en el que los desarrolladores pueden probar sus desarrollos. La matriz de certificación específica todas las versiones de las tecnologías que son compatibles con la versión del IDE y la cual sugerimos seguir al pie de la letra para evitar errores inesperados por incompatibilidades.

Debido a que estos artículos son acerca del uso de la práctica de la Integración Continua en aplicaciones desarrolladas usando Oracle ADF, no entraremos en detalle de todas las opciones y los asistentes que ofrece el IDE, solo hablaremos de los que sean relevantes.

Git
Git es un sistema que nos permite hacer seguimiento y controlar cambios en el software. Lo que hace especial a Git frente a otros sistemas que buscan el mismo objetivo, es que Git es distribuido y tiene un muy buen soporte para trabajar con diferentes ramas de desarrollo al mismo tiempo.

Que sea distribuido significa que el código fuente no se encuentra únicamente en un servidor remoto, sino que de hecho se encuentra en cada una de las estaciones de trabajo de los desarrolladores. De esta manera, cuando un desarrollador se encuentra trabajando en una nueva funcionalidad o en algún parche para corregir inconsistencias, todos los cambios realizados en el código fuente se encuentran en su estación de trabajo y solo cuando el desarrollador certifique su trabajo, éste será integrado con el servidor remoto. Aquí es importante hacer una buena división de las tareas porque nos interesa que el código que se escriba se integre lo más pronto posible.

El trabajo con ramas de desarrollo en Git también es muy potente, fácilmente podemos crear ramas a partir de otras, integrar los cambios de una rama en otra, publicar ramas en el servidor remoto para que nuestros pares puedan revisar nuestro código o como copia provisional de nuestro trabajo. Una vez terminamos el desarrollo de todas las funcionalidades podemos crear una etiqueta (tag), la cual es como una rama que no puede ser modificada nuevamente, es más bien como una fotografía del código fuente en un instante de tiempo, ideal para cuando liberamos versiones de la aplicación que estamos construyendo.
Más adelante en esta misma entrega mostraremos un esquema de cómo trabajar con ramas para tener la menor cantidad de conflictos a la hora de integrar el código.

Si aún no usas/conoces Git, te recomendamos un buen curso gratuito para aprenderlo: Cómo usar Git y GitHub (Udacity en inglés).

Oracle JDeveloper y Git
El IDE cuenta con un plugin especial para usar Git sin necesidad de instalar software adicional. Para quienes venían usando el plugin de subversion, notarán que se usan las mismas ventanas y comandos muy parecidos a la hora de trabajar con el plugin Git.

Existe un archivo especial para los repositorios git denominado: .gitignore. Dicho archivo le indica a Git cuales otros archivos/directorios deben ser excluidos por medio de patrones de nombres. Es importante registrar en él todos esos archivos/directorios que no tienen que ver con el código fuente de nuestra aplicación para que no vayan a parar al repositorio. Otro punto importante es que debemos crear este archivo dentro del directorio de la aplicación antes de versionarla, de esta manera aseguramos que ninguno de esos archivos/directorios van a quedar en la versión inicial.

A continuación proponemos el contenido de este archivo:

# JDev
cwallet.sso.lck
*.cdi_javac
*.class
*.jar
*.war
*.ear
.data/
temp/
classes/
deploy/
javadoc/

 # Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties

 # Others
.svn/
.git/
*.bak
*.git
*~

 

Para inicializar nuestro repositorio local y crear la primera versión de la aplicación, accedemos a la opción Team->Version Application:

Lo anterior desplegará un asistente que nos ayudará a crear nuestra primera versión. Lo primero que nos solicitará el asistente es definir el directorio de la aplicación y un comentario inicial:

Luego se nos presentarán una serie de patrones de nombres que usará JDeveloper para excluir archivos a la hora de detectar modificaciones pendientes:

La diferencia frente al archivo .gitignore radica en que .gitignore es usado por Git independientemente de si estamos trabajando con el plugin para JDeveloper o con cualquier otro cliente, mientras que la configuración de filtros que hacemos en este paso aplica solo para JDeveloper. Recomendamos contar siempre con el archivo .gitignore dentro del directorio de la aplicación y al versionar la aplicación desde JDeveloper, aceptar los filtros propuestos.

Una vez que finalizamos el asistente, podemos notar, en la ventana de aplicaciones, que nuestros proyectos reflejan la rama sobre la cual estamos trabajando:

También podemos ver el contenido del archivo .gitignore desde JDeveloper por medio de la opción Team->Git->Show .gitignore. Si el archivo no existe, JDeveloper preguntará si deseamos crearlo, pero como mencionamos previamente, la mejor práctica es que debemos crear el archivo dentro del directorio de la aplicación antes de versionarla:

Una ventana que es muy útil a la hora de trabajar con Git desde JDeveloper es la ventana de versiones, a la que podemos acceder por medio de la opción Team->Versions:

En esta ventana podemos ver, para las aplicaciones que tenemos abiertas, las ramas, etiquetas, repositorios remotos y realizar algunas operaciones sobre el repositorio:

Creación de ramas
Existen varias formas de crear una rama de desarrollo desde JDeveloper, pero a continuación mostraremos los pasos que a nuestro parecer son los más rápidos. Desde la ventana de versiones mostrada más arriba, clic derecho sobre la rama a partir de la cual queremos crear una nueva y seleccionamos la opción Create Branch. En el asistente que se despliega a continuación, podemos escribir el nombre de la nueva rama y seleccionar desde cual commit (botón Select Commit) de la rama origen queremos crear la nueva rama, si no seleccionamos un commit entonces se usará el más reciente. También es importante seleccionar la casilla Checkout Created Branch para que de una vez JDeveloper comience a usar la nueva rama:

Al finalizar el asistente, podemos notar que nuestra ventana de aplicaciones refleja la nueva rama en cada uno de nuestros proyectos y que la ventana de versiones muestra la nueva rama marcada de color verde, indicando que es la rama de desarrollo actual:

Cambios entre ramas
Ahora que contamos con varias ramas podemos movernos entre ellas por medio de la opción Checkout que nos presenta JDeveloper cuando hacemos clic derecho sobre la rama a la cual nos queremos cambiar:

Una vez seleccionada dicha opción, se nos presenta un asistente que nos permite hacer algunas configuraciones adicionales, pero si solo deseamos movernos entre ramas podemos aceptar las opciones que nos presenta por defecto.

Desarrollo sobre la rama
Cuando adicionamos/cambiamos clases/paquetes en nuestra aplicación, necesitamos adicionarlos a la rama de desarrollo actual. JDeveloper cuenta con una ventana especial en la que podemos ver los cambios pendientes para que los podamos adicionar y finalmente realizar el commit de éstos.

Se puede acceder a dicha ventana por medio de la opción Team->Git->Pending Changes. La ventana muestra las dos listas de cambios que maneja Git, una que lista todos los cambios y otra que lista los cambios que van a hacer parte del commit. A continuación se muestra la ventana con un archivo candidato, es decir que tuvo cambios:

Aquí podemos seleccionar, de todos los archivos que tuvieron cambios, cuales queremos pasar a la lista de cambios que harán parte del commit. Para ello, seleccionamos los archivos y luego presionamos el icono de cruz verde que se muestra en la imagen. Una vez hecho esto, los archivos seleccionados pasan a la otra lista:

Esta lista cuenta con más opciones que la anterior, podemos ver las opciones para hacer commit a los cambios (Commit y Commit All) e incluso una opción para revertir los cambios (Revert), entre otras. Al seleccionar la opción para hacer commit se nos presenta un asistente en el que podemos escribir el mensaje que describe los cambios.

Integrar ramas
Cuando hemos realizado cambios en alguna rama de desarrollo y deseamos integrar dichos cambios a otra rama, por ejemplo a la master, entonces podemos seguir el siguiente procedimiento:

  1. Nos movemos a la rama en la cual queremos que queden los cambios, es decir, nos movemos a la rama destino.
  2. De ser necesario, actualizamos la rama destino por medio de la opción Team->Git->Pull. Esto aplica para cuando estamos trabajando con una rama que también se encuentra publicada en el repositorio remoto.
  3. Clic derecho sobre la rama origen, es decir, la que tiene los cambios y seleccionamos la opción Merge.

En la imagen anterior, queremos que los cambios hechos en la rama v1.0 sean integrados a la rama master y para ello, seguimos los pasos descritos previamente.

Solución de conflictos
En ocasiones, es posible que algunos cambios que queramos integrar en otra rama presenten conflictos por el trabajo de alguno de nuestros compañeros de equipo. En esas situaciones, JDeveloper nos alerta del conflicto con un mensaje de la siguiente manera:

Si revisamos la ventana de cambios pendientes, también podemos notar que el archivo en cuestión se encuentra en un estado con conflictos y tenemos la posibilidad de solucionarlos por medio de la opción Resolve Conflict que aparece al hacer clic derecho sobre el archivo:

La solución de conflictos se realiza en una ventana especialmente diseñada para ello, nos presenta el mismo archivo tres veces: Al lado izquierdo se muestra el archivo con los cambios que queremos integrar; al centro se presenta el archivo como quedará una vez terminemos de integrar los cambios; al lado derecho se presenta el archivo tal como se encuentra en la rama de desarrollo actual:

La ventana nos permite ver las diferencias en el código y nos facilita controles para pasar el código de uno de los lados al centro, que es como va a quedar el archivo una vez solucionemos los conflictos. Una vez terminamos de pasar el código y nuestro archivo se ve como queremos, podemos hacer uso de la opción que graba los cambios y termina de resolver el conflicto, ubicada en la parte superior derecha de la barra de herramientas de esta misma ventana.

Borrar ramas
Una vez integramos nuestro código, podemos eliminar las ramas que no necesitemos más. Para ello, nos debemos situar en la ventana de versiones, hacemos clic derecho sobre la rama que deseamos borrar y seleccionamos la opción Delete. Nota: No podemos borrar la rama sobre la que nos encontramos desarrollando actualmente, si así lo requerimos, primero debemos movernos a una diferente.

En ocasiones la ventana de versiones no se refresca automáticamente y todavía muestra ramas que acabamos de borrar, por lo que debemos hacer uso del botón de refresco manual, que está ubicado en la parte superior izquierda de la misma ventana, al lado derecho de la X roja.

Otras opciones
El plugin cuenta con muchas otras opciones que no alcanzamos a describir en este artículo, pero que vale la pena mencionar: Ver el historial de commits, Comparar los cambios de un archivo con un commit anterior, actualizar nuestro repositorio local desde el repositorio remoto (Pull), publicar los cambios de nuestro repositorio local en el repositorio remoto (Push) y otras más.

Es posible que para realizar algunas opciones más avanzadas con Git sea necesario contar con software adicional, pero consideramos que las opciones que ofrece el plugin son suficientes para el desarrollo normal de una aplicación.
Esquema de trabajo con repositorios Git
Aún cuando Git tiene muy buen soporte para las ramas de desarrollo, es importante seguir un estándar para tener la menor cantidad de conflictos a la hora de integrar el código. A continuación proponemos un esquema básico de trabajo que puede ser adaptado a cada caso particular y que explicaremos a continuación:

  1. La estructura de cada repositorio será la estándar, es decir, se contará con una rama protegida master (rama principal en Git) la cual contiene el código estable de la aplicación, es decir, la versión desplegada más actual.
  2. Para el desarrollo de nuevas versiones creamos ramas separadas a partir de la rama master. El nombre de dichas ramas debe quedar definido en el estándar de desarrollo del proyecto, un ejemplo del nombre puede ser la letra 'v' y luego el número de la versión: v1.0, v1.1, v2.8.4, etc.
  3. Cada desarrollador que participe de la versión en desarrollo deberá crear su propia rama auxiliar a partir de la rama de la versión, por ejemplo v1.1-desa1 o v1.1-desa2. Con esto logramos que su trabajo esté aislado del trabajo de los demás miembros del equipo.
  4. A medida que vamos terminando de desarrollar y comprobamos las funcionalidades en las ramas auxiliares, integramos el código de éstas a la rama de la versión.
  5. Una vez terminamos de desarrollar y comprobamos todas las funcionalidades, debemos integrar la rama de la versión a la rama master y generamos una nueva etiqueta (tag). El nombre a usar puede ser el mismo que tiene la rama de la versión.


En este momento podemos descartar la rama de la versión y cualquier corrección en caliente (hotfix) que se requiera, debemos hacerla a partir de la etiqueta (tag) creada para la versión.

A continuación se muestra, gráficamente, una forma general en la que podemos trabajar con el repositorio tanto para nuevas versiones como para correcciones en caliente (hotfixes):

Si la corrección es para una versión diferente a la que se encuentra en la rama master, entonces en el primer paso no usamos la rama master para crear la rama de la versión, sino que usamos la etiqueta (tag) de la versión a corregir.

Ahora veamos específicamente lo que sucede en el proceso de desarrollo una vez el desarrollador recibe la notificación de que la rama sobre la cual debe trabajar se encuentra disponible. Lo siguiente ocurre en la máquina local del desarrollador:

  1. Cada desarrollador que participe de la versión en desarrollo deberá crear su propia rama auxiliar a partir de la rama de la versión, por ejemplo v1.1-desa1 o v1.1-desa2. Con esto logramos que su trabajo esté aislado del trabajo de los demás miembros del equipo.
  2. Realizamos los cambios requeridos por el desarrollo, haciendo commit a la rama auxiliar por cada cambio representativo. Es importante que nuestros commits sean estables, es decir, que cada commit incluya todos los cambios requeridos para que el código compile correctamente.
  3. Probamos y comprobamos la rama auxiliar. Si hay errores, volvemos a desarrollo.
  4. Al terminar el desarrollo, debemos pasarnos nuevamente a la rama de la versión y actualizarla para traer los últimos cambios que otros miembros del equipo puedan haber hecho.
  5. Integramos el código de nuestra rama auxiliar a la rama de la versión. Si hay conflictos debemos resolverlos en la rama de la versión.
  6. Publicamos la rama de la versión, haciéndola disponible para todo el equipo y para el ambiente de integración continua.


Esta propuesta intenta establecer un esquema de trabajo con el repositorio Git, sin embargo no debe tomarse como camisa de fuerza, siempre podemos adaptarla a nuestro caso particular. Lo importante es que los desarrolladores puedan hacer su trabajo de forma aislada, pero integrándolo continuamente.

Otras situaciones que pueden presentarse respecto al manejo del repositorio son:

  • ¿Qué pasa con las ramas auxiliares que son creadas por los desarrolladores? Una vez el código ha sido integrado a la rama de la versión y no requerimos desarrollar más funcionalidades, entonces podemos descartar las ramas auxiliares.
  • ¿Qué pasa si requerimos una funcionalidad que desarrolló otro miembro del equipo sobre su rama auxiliar? Lo ideal es que dicha funcionalidad sea integrada a la rama de la versión y crear nuestra rama auxiliar a partir de ésta. De no ser posible, entonces podemos integrar el código de la rama auxiliar de nuestro compañero de equipo a la nuestra.
  • ¿Qué pasa si requerimos hacer una corrección en caliente (hotfix) de una versión anterior, pero necesitamos esa corrección en la rama actual? En este caso debemos integrar la rama donde desarrollamos la corrección a las demás ramas que la requieren, por lo general, la rama master, la de la versión actual y las demás auxiliares.

Repositorios Git
Dividiremos esta sección en dos: Repositorios instalados y Repositorios en la nube.

  • Repositorios instalados: Son repositorios que se instalan manualmente en las máquinas propias (también llamados “on-premise”). Como todo el software que requiere ser instalado, se debe pensar en los requerimientos de la máquina, contar con una persona que realice la instalación y mantenimiento posterior (actualizaciones y copias de seguridad).

    El libro oficial de Git tiene una sección de cómo instalar Git en un servidor. En un principio esto parece suficiente, sin embargo, cuando se piensa en la gestión del repositorio, seguridad, usuarios y colaboración entre ellos, la cantidad de comandos y pasos manuales pueden llegar a ser dificultosos. Por fortuna, existen aplicaciones que permiten administrar nuestros repositorios Git de una manera visual y declarativa, gestionar usuarios, configurar la seguridad, crear/proteger/integrar ramas de desarrollo, incrementar la colaboración entre desarrolladores, wikis para los repositorios y muchas otras opciones. Entre dichas aplicaciones se encuentran:
    • GitLab → Cuenta con una versión de comunidad gratuita para descargar e instalar y otras versiones más completas por un costo adicional.
    • BitBucket → Al momento de escribir este artículo, cuenta con una versión para instalar de hasta 10 usuarios (equipos pequeños) por un pago mínimo y único.
    • GitHub → El reconocido servicio de repositorios Git en la nube, cuenta con una versión empresarial que puede ser instalada en máquinas propias por un pago anual por usuario.

  • Repositorios en la nube: En este caso el servicio ya se encuentra instalado y solo debemos hacer uso de él. Algunos de los proveedores que ofrecen repositorios Git en la nube:
    • GitLab → También cuenta con un servicio gratuito en la nube que permite la creación de proyectos tanto públicos como privados ilimitados.
    • BitBucket → Al momento de escribir este artículo, cuenta con un plan gratuito de hasta 5 usuarios para crear repositorios tanto públicos como privados ilimitados.
    • GitHub → La versión gratuita solo permite la creación de repositorios públicos, es decir, todos pueden acceder al código fuente. La creación de repositorios privados requiere pago.
    • Oracle Cloud Developer Service → Servicio en la nube de Oracle que va más allá de repositorios Git, es todo un ambiente de Integración Continua en la nube. Al momento de escribir este artículo, su uso está restringido, pero es gratuito para quienes cuentan con alguno de los demás servicios en la nube de Oracle: Java Cloud Service, Mobile Cloud Service y otros (visita la página oficial para mayor información). 

Conclusión

En esta segunda parte hablamos acerca de la herramienta oficial de desarrollo para Oracle ADF, de Git como repositorio de código fuente distribuido y de las características y funcionalidades que ofrece el plugin de JDeveloper para trabajar con Git. También propusimos un esquema de trabajo con el repositorio que ayuda a minimizar los conflictos entre miembros del equipo y permite trabajar con varias ramas de desarrollo al tiempo. Por último, revisamos diferentes proveedores para trabajar con repositorios Git tanto en máquinas propias como para su uso en la nube.

A continuación algunos puntos para recordar:

  • Oracle JDeveloper es la herramienta oficial de desarrollo para Oracle ADF. Contiene una serie de asistentes que permiten trabajar de forma declarativa con este marco de trabajo.
  • Git es un repositorio de código fuente distribuido que ofrece gran soporte para el trabajo con ramas de desarrollo. Su naturaleza distribuida permite que cada desarrollador cuente con su propio repositorio local, cada cambio se hace localmente sin afectar el repositorio remoto. La integración de código y solución de conflictos también se hace localmente dejando el repositorio remoto en un estado consistente en todo momento.
  • El plugin para trabajar con Git desde JDeveloper ofrece la facilidad de usar Git sin necesidad de instalar software adicional. Cuenta con opciones para ver las modificaciones pendientes, adicionarlas y hacer commit, gestionar ramas/etiquetas, etc. Sin embargo, para operaciones avanzadas, tal vez sea necesario contar alguna herramienta adicional.
  • Realizar la instalación de Git en nuestras propias máquinas requiere, además, la instalación de una herramienta para su administración y realizar su mantenimiento posterior (actualizaciones, copias de seguridad, etc.). Este es un aspecto importante a tener en cuenta a la hora de elegir si se instala o se usa el servicio en la nube, en donde el mantenimiento lo hace el proveedor.

Continuamos armando nuestro ambiente de integración continua para Oracle ADF, en este momento se ve de la siguiente forma:

Información Adicional
Los siguientes enlaces ofrecen mayor información respecto a este tema:

Cómo usar Git y GitHub (Udacity en inglés):
https://www.udacity.com/course/how-to-use-git-and-github--ud775

Libro oficial de Git
https://git-scm.com/book/es/v1

GitLab
https://about.gitlab.com/

BitBucket
https://bitbucket.org

GitHub
https://github.com

Oracle Cloud Developer Service
https://cloud.oracle.com/developer_service 

 


Alexis Lopez (@aa_lopez) es consultor independiente Java/ADF/BPM. Ha sido profesor universitario de cursos relacionados con tecnologías Java y conferencista en congresos reconocidos como: Oracle Open World, JavaOne, Campus Party y OTN Tour. Cuenta con un título de ingeniero de sistemas y las siguientes certificaciones y reconocimientos: Oracle Ace Associate, OCP Java 8, OCPJMAD, OCPWCD, especialista de implementación de Oracle ADF y Oracle BPM. Es líder del grupo de usuarios Java de Cali-Colombia (www.clojug.org), miembro del comité de dirección del grupo de usuarios virtual de Java (virtualjug.com) y blogger activo en www.acelopez.com

Este artículo ha sido revisado por el equipo de productos Oracle y se encuentra en cumplimiento de las normas y prácticas para el uso de los productos Oracle.