martes, diciembre 10, 2019

GX 16 U2 "java.lang.NoClassDefFoundError: org/apache/commons/collections4/bidimap/TreeBidiMap"


Me llegó un reporte de error que tenía un cliente a la hora de generar los reportes excel en el servidor.
El equipo de Desarrollo funcionaba bien pero al hacer el deploy en producción le daba error. La verdad que simplemente busque en google y la solución fue actualizar las "Apache Commons Collections"

El sistema fue desarrollado en GeneXus 16 Upgrade2 generando Java, el servidor de aplicaciones es un Tomcat8 java8.


El error que me daba era el siguiente:

Estado HTTP 500 - java.lang.NoClassDefFoundError: org/apache/commons/collections4/bidimap/TreeBidiMap

type Informe de Excepción

mensaje java.lang.NoClassDefFoundError: org/apache/commons/collections4/bidimap/TreeBidiMap

descripción El servidor encontró un error interno que hizo que no pudiera rellenar este requerimiento.

excepción

javax.servlet.ServletException: java.lang.NoClassDefFoundError: org/apache/commons/collections4/bidimap/TreeBidiMap
at org.apache.poi.hpsf.Section.(Section.java:178)
at org.apache.poi.hpsf.MutableSection.(MutableSection.java:41)
at org.apache.poi.hpsf.PropertySet.init(PropertySet.java:494)
at org.apache.poi.hpsf.PropertySet.(PropertySet.java:196)
at org.apache.poi.hpsf.MutablePropertySet.(MutablePropertySet.java:44)
at org.apache.poi.hpsf.SpecialPropertySet.(SpecialPropertySet.java:47)
at org.apache.poi.hpsf.DocumentSummaryInformation.(DocumentSummaryInformation.java:99)
at org.apache.poi.hpsf.PropertySetFactory.create(PropertySetFactory.java:116)
at org.apache.poi.POIDocument.getPropertySet(POIDocument.java:236)
at org.apache.poi.POIDocument.getPropertySet(POIDocument.java:197)
at org.apache.poi.POIDocument.readPropertySet(POIDocument.java:175)
at org.apache.poi.POIDocument.readProperties(POIDocument.java:158)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.updateEncryptionInfo(HSSFWorkbook.java:2295)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.getBytes(HSSFWorkbook.java:1506)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.write(HSSFWorkbook.java:1428)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.write(HSSFWorkbook.java:1414)
at com.genexus.gxoffice.poi.hssf.ExcelDocument.Save(Unknown Source)
at com.genexus.gxoffice.ExcelDoc.Save(Unknown Source)
at listados_reporteaexcel.privateExecute(listados_reporteaexcel.java:254)
at listados_reporteaexcel.execute_int(listados_reporteaexcel.java:76)
at listados_reporteaexcel.execute(listados_reporteaexcel.java:55)
at alistadorevalida_impl.privateExecute(alistadorevalida_impl.java:274)
at alistadorevalida_impl.webExecute(alistadorevalida_impl.java:60)
at com.genexus.webpanels.GXWebObjectBase.doExecute(Unknown Source)
at alistadorevalida.doExecute(alistadorevalida.java:20)
at com.genexus.webpanels.GXWebObjectStub.callDoExecute(Unknown Source)
at com.genexus.webpanels.GXWebObjectStub.callExecute(Unknown Source)
at com.genexus.webpanels.GXWebObjectStub.doGet(Unknown Source)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.genexus.filters.ExpiresFilter.doFilter(Unknown Source)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections4.bidimap.TreeBidiMap
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1293)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1145)
... 55 more

com.genexus.webpanels.GXWebObjectStub.callExecute(Unknown Source)
com.genexus.webpanels.GXWebObjectStub.doGet(Unknown Source)
javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.genexus.filters.ExpiresFilter.doFilter(Unknown Source)

nota La traza completa de la causa de este error se encuentra en los archivos de diario de Apache Tomcat/8.0.14 (Debian).
Apache Tomcat/8.0.14 (Debian)

domingo, octubre 13, 2019

Hola Mundo en Django

Desde hace un tiempo me encuentro aprendiendo Django y Python, como siempre que arranco con algo lo primero que hago es el "Hola Mundo". Es el arranque de todo y como decía un amigo si te sale el "Hola Mundo" ya dominas el lenguaje ("Una broma interna").

Podríamos hacer un html simple y al ponerlo en la raíz del sitio lo podríamos acceder pero la idea es usar vistas por lo que vamos a describir como hacer un "Hola Mundo" rápidamente.

El primer paso para nuestro ejemplo es crear el proyecto "holamundo"

cgomez@cgomez-urulinux ~/djangocode $ django-admin.py startproject holamundo



Luego de crear el proyecto entramos a la carpeta holamundo que contiene los archivos:
cgomez@cgomez-urulinux ~/djangocode $ cd holamundo/holamundo

Vamos a crear nuestra vista dentro del archivo que contendrá las vistas, le podríamos poner cualquier nombre pero para seguir las convenciones vamos a llamarlo views.py


Simplemente creo una vista que recibe un request y devuelve un response que dice "Hola Mundo", es un ejemplo muy simple para crear nuestro "Hola Mundo". Para que esto se pueda realizar me falta enganchar mi vista al proyecto ya que por ahora esto no quiere decir nada. 

Debo configurar mi url y esto se hace desde el archivo urls.py, este archivo se crea por defecto cuando creamos un proyecto vacío en django. Dentro de este archivo se encuentra por defecto el acceso al admin por lo que para nuestro ejemplo lo vamos a comentar y configurar nuestra vista.



En la sección de urlpatterns es donde indico como se encuentra mi vista que mostrara "Hola Mundo", lo único que hice para esto fue usar una expresión regular como se muestra en la imagen.

Luego de guardar estos cambios, arranco el servidor y accedo a mi ejemplo:
Este es un ejemplo simple de mi primer "Hola Mundo"












domingo, septiembre 22, 2019

Django for dummies y algo de Python

Para no perder la costumbre este año me puse como objetivo dominar Python  y Django, hice el curso de Microsoft que se encuentra en línea aparte de otro presencial en BIOS. El problema que tengo es que me esta costando agarrar práctica y en ocasiones me complico con cosas muy simples, por este motivo voy a ir poniendo todo lo que me ha complicado en el arranque con Django. La idea es que si recién arrancas no te tranques en las cosas simples que me he trancado.

¿Como detectar la versión de django?

Es algo muy sencillo pero en mi caso me estuve complicando hasta que encontré la forma mas sencilla, abrí una terminal ejecute python hice el import de django y luego django.VERSION. Al ejecutar esto me da el siguiente resultado:

cgomez@cgomez-urulinux ~ $ python
Python 2.7.12 (default, Aug 22 2019, 16:36:40)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(1, 11, 23, u'final', 0)
>>> 

En mi caso tengo Python 2.7 y 3.5 por lo que probé y funciona de la misma manera. Es algo sencillo pero que me llevo navegar un poco en internet para darme cuenta de esto.

cgomez@cgomez-urulinux ~ $ python3
Python 3.5.2 (default, Jul 10 2019, 11:58:48)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(2, 2, 0, 'final', 0)
>>>
Al hacer la consulta con Python 3 me da que tengo otra versión de Django, esto por que lo tengo así configurado y uso la versión que necesito según lo que quiera hacer.

¿Por qué ejecutar el manage.py migrate?
Ten en cuenta que no soy experto en esto pero en resumen cuando comienzas un nuevo proyecto se debe ejecutar el comando manage.py migrate para que se cree la base por defecto con las estructuras necesarias para django. Esto no es obligatorio pero si usas por ejemplo SQLite como base de datos al ejecutar el comando se crean las tablas necesarias para las aplicaciones definidas en INSTALLED_APPS, esto lo puedes ver en el archivo settings.py. Con SQLite lo hace con la primera ejecución si no me equivoco pero en mi caso lo hago para no olvidarme. Aquí un ejemplo de ejecutar este comando:
cgomez@cgomez-urulinux ~/djangocode/misitio $ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
cgomez@cgomez-urulinux ~/djangocode/misitio $ ls -l
total 48
-rw-r--r-- 1 cgomez cgomez 40960 sep 22 20:23 db.sqlite3
-rwxrwxr-x 1 cgomez cgomez 627 sep 22 20:10 manage.py
drwxrwxr-x 3 cgomez cgomez 4096 sep 22 20:14 misitio
cgomez@cgomez-urulinux ~/djangocode/misitio $
En el ejemplo se crea la bae db.sqlite3 ya que es la base que viene por defecto en la configuración y al ejecutar el migrate se crea con las estructuras necesarias para las aplicaciones que vienen por defecto.

¿Servidor de Desarrollo?
Para que no te tengas que complicar con Apache ni nada por el estilo django cuenta con un servidor de desarrollo que es sencillo y lo puedes ejecutar solo con una línea.

cgomez@cgomez-urulinux ~/djangocode/misitio $ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
September 22, 2019 - 23:39:41
Django version 2.2, using settings 'misitio.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Con runserver se ejecuta un servidor liviano para desarrollo que escucha en el puerto 8000 por defecto por lo que puedes ejecutar esto en tu equipo y luego entrar al browser de la siguiente manera:



Si necesitas cambiar el puerto en el que escucha el servidor de desarrollo se lo puedes pasar como parámetro al ejecutarlo, también puedes hacer que escuche en la ip pública del equipo para compartir esta ejecución con otro desarrollador.

cgomez@cgomez-urulinux ~/djangocode/misitio $ python3 manage.py runserver 8081
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
September 22, 2019 - 23:47:20
Django version 2.2, using settings 'misitio.settings'
Starting development server at http://127.0.0.1:8081/
Quit the server with CONTROL-C.

En el ejemplo mi servidor de desarrollo escucha en el puerto 8081, también puedo hacer lo siguiente:

cgomez@cgomez-urulinux ~/djangocode/misitio $ python3 manage.py runserver 192.168.1.6:8081
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
September 22, 2019 - 23:49:54
Django version 2.2, using settings 'misitio.settings'
Starting development server at http://192.168.1.6:8081/
Quit the server with CONTROL-C.

En este ejemplo queda accesible mi servidor para que desde otro equipo lo puedan acceder, siempre y cuando tengan acceso al ip 192.168.1.6 en el puerto 8081. Estoy descartando temas de firewall y seguridad ya que el ejemplo es solo ilustrativo.





viernes, septiembre 20, 2019

Angular desde cero "Instalando y arrancando mi primer proyecto"

La verdad que desde hace tiempo vengo escuchando del tema de Angular y tengo que admitir que por cuestiones de tiempo o de falta de interés no me había metido en este tema.

Ahora que se acerca un nuevo encuentro GeneXus veo que se le sigue dando para adelante al generador Angular y la verdad que intento estar en todo lo que tenga que ver con el mundo GeneXus.
Esto me motivo a arrancar a meterme en Angular para entender de que viene el generador Angular. En el GX29 existe una charla llamada "Nuevos generadores GeneXus: Angular.... y otros", espero poder asistir a esta charla e ir al evento por lo que arranque por entender e investigar un poco que es Angular.

Para hacer la instalación me base en dos artículos que encontré en la vuelta y que me ayudaron mucho:
https://ubunlog.com/angular-instala-framework-ubuntu/
https://tecadmin.net/install-latest-nodejs-npm-on-linux-mint/

En mi equipo hice la instalación siguiendo los pasos de los artículos mencionados y luego lo que hice fue actualizar la versión del Node Package Manager (NPM)
cgomez-urulinux cgomez # npm -v
6.10.3
cgomez-urulinux cgomez # sudo npm install npm@latest -g
cgomez-urulinux cgomez # npm -v
6.11.3
Luego de actualizar el npm y configurar mi git lo que hice fue hacer una aplicación de ejemplo:
cgomez-urulinux cgomez # ng new ejemploangular
Luego de ejecutar ese comando lo que hice fue entrar al directorio "ejemploangular" y ejecutar mi aplicación mediante el comando: pm start
cgomez-urulinux ejemploangular # npm start 
> ejemploangular@0.0.0 start /home/cgomez/ejemploangular
> ng serve
10% building 3/3 modules 0 activeℹ 「wds」: Project is running at http://localhost:4200/webpack-dev-server/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: 404s will fallback to //index.html
chunk {main} main.js, main.js.map (main) 47.8 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 264 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 9.7 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 3.81 MB [initial] [rendered]
Date: 2019-09-21T02:44:45.706Z - Hash: 0f7af56d6a2dbfe76dde - Time: 6898ms
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
ℹ 「wdm」: Compiled successfully.
Mi nuevo proyecto quedo levantado en el puerto 4200 y al ir al browser se ve de esta manera:


En principio para entender un poco que es Angular buscando en la web encontré un artículo llamado: "Angular: Mucho más que un framework", con eso me alcanzo para entender un poco y ponerme manos a la obra para instalar y hacer mi primer aplicación.

Ahora solo me queda comenzar a meterle mano a Angular para no quedarme por fuera de este framework ni del generador Angular de GeneXus.

jueves, mayo 16, 2019

Glowroot, un aliado para la mejora de performance de mis aplicaciones

El Glowroot es un APM que estoy usando para poder evaluar el rendimiento de mi aplicación y la considero una herramienta fundamental para el desarrollador. Hoy en día el papel del desarrollador no es solo picar código, si no que también debemos estar atentos a que nuestra aplicación pueda convivir dentro del ecosistema de aplicaciones que la rodean.  En mi caso tengo una aplicación que atiende a todo el país y debe convivir con otras aplicaciones que brindan servicios los cuales consumo aparte de exponer servicios a varios clientes. Esto hace a que debo estar atento a que los cambios que se realizan no impacten en el rendimiento del ecosistema en el que se ve inserto el sistema.

Para poder estar atento al rendimiento de mi aplicación necesito contar con alguna herramienta que me permita hacer un estudio del consumo de memoria, consultas a la DB y guardar estadísticas de estos consumos.

En mi caso me encuentro haciendo refactoring a un sistema que lleva en producción unos 11 años y ha sufrido cambios varios que me han permitido migrar versión de GeneXus (9, 15 y 16) e inclusive hacer mejoras en su arquitectura. Estos cambios implican hacer "refactoring" de código casi constantemente, en realidad a medida que planifico liberaciones trato de mejorar aspectos de rendimiento y mejoras varias por lo que necesito contar con insumos que me permitan demostrar las mejoras realizadas.

Cuando el año pasado comencé con algunos problemas en consumos de memoria luego de haber migrado mi aplicación de GX 9 a GX15 me puse a investigar que herramientas existían en la vuelta y me decidí por instalar Glowroot.

El uso diario que le doy y el mas sencillo de usar es el análisis de las consultas que hace mi aplicación sobre la base de datos. Básicamente al tener Glowroot instalado alcanza con ejecutar mi aplicación y luego ver las consultas que genera, aquí dejo un ejemplo de una ejecución de una parte del sistema que tenía que cambiar: 

Sin optimizar


Luego de optimizar y hacer refactoring ejecute nuevamente mi aplicación y consulte las consultas que había realizado a la base y pude verificar que los cambios que hice realmente bajaron la cantidad de consultas mejorando el rendimiento de código que había modificado.

Optimizada



La información con la que cuento en Glowroot con respecto a las consultas que realizo sobre la base me permiten estudiar y verificar la cantidad de veces que se ejecuta una consulta aparte de los tiempos de cada una. Realmente es algo muy sencillo de utilizar y que rápidamente puedo verificar que las consultas que se están ejecutando son las que realmente quiero que se hagan. 

El ejemplo que puse arriba es algo muy sencillo en donde mejore el código pero lo que quiero mostrar es que la herramienta me permite consultar rápidamente que consultas hago, la cantidad, el tiempo y en que consiste cada una. 

El Glowroot es una herramienta potente que me permite analizar el rendimiento de la memoria y muchas cosas mas. Este ejemplo es una de las cosas mas básicas que tiene esta herramienta, en mi caso la uso a diario y la comparto para que puedan aprovecharla como lo hago a diario.

domingo, mayo 05, 2019

Mi primer aplicación migrada a GeneXus 16 U2 ya se encuentra en producción

Desde octubre del 2018 me encuentro trabajando con GeneXus 16 pero por distintos motivos recién hace una semana pude pasar a producción mi aplicación. El sistema del que estoy hablando atiende a todo el País y se encontraba en producción desde hacía un año generado en Java con GeneXus 15.

Mi motivación para migrar a GeneXus 16 se basaba en dos puntos:
a) Actualización tecnológica
b) Poder implementar CI/CD

La decisión de cambiar a GeneXus 16 la base en los puntos que puse arriba y también la oportunidad de implementar grandes cambios solicitados por el cliente, estos cambios iban a necesitar volver a probar todo el sistema por lo que aproveche a sumar a todos los cambios la migración de GeneXus.

La migración de GeneXus 15 a GeneXus 16 fue transparente y no tuve problemas mayores, lo único que me complico un poco fue el cambio que hicieron en GeneXus 16 con los wsdl de los servicios web.

Lo que estaba documentado en las Release Notes no impactaba en mi forma de definir los SDT que exponían mis servicios pero había algo que no estaba en la documentación que me impacto y me cambio los wsdl de varios de mis servicios.

Intente pasar a producción mi aplicación y mi plan de testing no incluía revisar que no existieran cambios en los wsdl de mis servicios web por lo que esto llego a producción, básicamente fue un desastre y todas las aplicaciones clientes que consumen mis servicios web dejaron de funcionar.  Tuve que volver a la versión anterior y trabajar en mejorar mi plan de pruebas.

La forma que tuve de arreglar los wsdl fue modificando el código java generado por GeneXus a mano dado que no era viable pedirle a todos los clientes que consumían mis servicios que volvieran a consumir y regenerar sus programas. (En el U3 en teoría existe una propiedad que arreglaría mi problema)

En síntesis el problema que tuve es que mi plan de pruebas no cubría todo lo que debería cubrir y fue un descuido de mi parte pero me sirvió de experiencia ya que dado ese incidente pude mejorar mucho la calidad de mis pruebas.

También a nivel de desarrollo comenzamos a implementar pruebas unitarias y otras mejoras que surgieron a partir de este incidente.

Comparto mi experiencia con el resto de la comunidad para que pierdan el miedo a ir cambiando de versión ya que el problema en sí no es el cambio de versión de GeneXus si no la calidad que tengamos en nuestro plan de pruebas o que tan maduro estemos en QA. Creo que existe la necesidad de integrar mas calidad a nuestros desarrollos para que nos permitan ir migrando de versión y no quedar estancados en el tiempo.

En lo personal estoy aprendiendo mucho y me estoy metiendo en implementar prácticas que permitan hacer grandes cambios en desarrollo sin tener miedo a que se pueda romper algo. La industria del software necesita que estemos actualizados y tenemos que prepararnos para poder hacer esto sin miedo, de lo contrario vamos a estar trabajando en proyectos con GeneXus 9 por varios años.

En síntesis después de algunos meses de sufrir y aprender mucho pude poner en producción mi aplicación desarrollada con GeneXus 16 y comenzar un proceso de cambio mejorando mis procesos de Desarrollo.


















Pruebas Unitarias en GeneXus

Dentro de la comunidad GeneXus no existe mucho apego a las pruebas unitarias o no es una práctica común, por lo menos esa es mi impresión. En realidad si tengo que ser justo veo que las pruebas unitarias no son utilizadas por muchos programadores independientemente del lenguaje que usen.

Dentro de la industria existen muchas empresas que tienen dentro de sus prácticas la utilización de pruebas unitarias pero no lo veo muy adaptado por parte de los programadores o la mayoría de los que pude hablar lo ven como algo que les quita tiempo.

Estudiando el tema dentro de la comunidad no pude encontrar muchas opiniones sobre el tema y lo que pude encontrar esta relacionado a GX-Unit que lo intente comentar en otros artículos de este blog.

En la comunidad la persona que se ha preocupado mas por el tema es Enrique Almeida y podrán encontrar varios artículos en su blog. En GeneXus 16 encontramos la posibilidad de crear "Unit Test" de forma automática la cual pueden encontrar toda la información en el siguiente link.

En síntesis GeneXus cuenta con una herramienta incluida en el IDE la cual nos permite crear pruebas unitarias de forma automática, esta herramienta es gratuita para el desarrollador pero si quiero usar estos "unit test" con mis procesos de Integración Continua (CI/CD) tengo que adquirir una licencia.

En mi experiencia con los años pude entender la importancia de las pruebas unitarias y se han convertido en una necesidad para poder brindar la calidad que los productos en los que trabajo me exigen. Esto me llevo a evaluar las herramientas existentes para GeneXus y las diferentes opiniones de miembros de la comunidad pero mi conclusión final es que las herramientas existentes tienen mucho camino por recorrer para poder cubrir todas nuestras necesidades.

Un problema de las herramientas existentes para GeneXus es que al ser poco utilizadas por la comunidad no le damos la oportunidad de que mejoren para cubrir nuestras necesidades.

En la actualidad me encuentro en un proyecto que necesita hacer refactoring y cambios grandes de arquitectura pero si no logro tener pruebas unitarias se me hace muy difícil garantizar que los cambios que hago no rompan parte de las funcionalidades existentes en el sistema.

Por este motivo estoy implementando pruebas unitarias a medida que voy modificando el código del sistema y voy a compartir mi experiencia en un próximo artículo, de todas maneras adelanto que estoy usando parte de los "unit test" de GeneXus y por otro lado programar mis pruebas unitarias a mano para poder cubrir mis necesidades.

















martes, abril 16, 2019

Instalando Odoo 12 (Inicio con datos de prueba)

Hace unos días hice la instalación de odoo 12 en mi equipo y lo que me faltaba era iniciar la aplicación siguiendo los pasos que se me muestran en el wizard de instalación. Al instalar odoo el sistema me pide los datos para iniciar con la primer base de datos y  dado que estoy evaluando la herramienta voy a comenzar con iniciar la base usando los datos de prueba que me provee la misma aplicación.

Los pasos que tuve que seguir son los siguientes, ejecutar la aplicación (localhost:8069):


Esta pantalla se muestra dado que todavía no indique cual es la base en que quiero inicializar mi instalación. Luego de que hago este paso al iniciar la aplicación me presenta la pantalla de ingreso de credenciales de Odoo. En mi caso para poder evaluar indique que la base inicial tenga los datos de demo que vienen en odoo.

Luego de inicializar los datos el sistema me muestra la lista de aplicaciones disponibles para instalar en mi ambiente. 

En la primer etapa de evaluación de odoo voy a instalar dos aplicaciones:

CRM

Inventario


El proceso de iniciar la base y evaluar odoo con los datos de prueba es muy sencillo y fácil de realizar, en cuestión de 15 minutos pude iniciar los datos e instalar las dos aplicaciones que me interesa evaluar en este momento. Espero para la próxima poder meterme en otras aplicaciones y comenzar con lo interesante de este ERP.

Ahora al ir a la aplicación me pide el login y no crear la base por defecto como antes:



Espero en próximas entregas hablar con un poco mas de propiedad de esta aplicación que por lo que pude ver tiene mil cosas que son necesarias y me evitaría tener que desarrollar desde cero un ERP.






viernes, abril 05, 2019

Instalar odoo en Linux Mint 18.3

Desde hace un tiempo me encuentro investigando un ERP libre llamado odoo el cual es bastante utilizado y para mi sorpresa es muy usado en Uruguay. Esta alternativa libre antiguamente se llamaba OpenERP y desde hace un tiempo ha migrado al nombre de odoo

Por ahora me encuentro evaluando esta herramienta para un cliente y estoy comenzando por instalarla en un Linux Mint 18.3. Estuve leyendo y la verdad que se me complico un poco con todas las cosas que se deben instalar pero después de googlear unos minutos encontré un script que se encarga de hacer toda la instalación.

El script se puede descargar de github.com/Yenthe666/InstallScript y al ejecutarlo se encarga de descargar e instalar todas las dependencias. 

Luego de ejecutar el script el servicio de odoo queda en ejecución y al ejecutar la aplicación web  (http://localhost:8069) queda pronto para comenzar con la configuración:








miércoles, febrero 06, 2019

GeneXus 16 Upgrade 2

El día de ayer se ha liberado el Upgrade 2 de GeneXus 16, toda la información necesaria para descargarla los pueden obtener en la wiki de genexus.

En mi caso me encuentro liberando una versión de mi sistema y aproveche a instalarme el U2 generando todo nuevamente, de esta manera aprovecho el testing que se iba a realizar con la última versión de GeneXus.

Entiendo que para algunos puedo estar loco pero quiero mantenerme en lo último y esta fue una buena oportunidad de testear la versión generando en la última versión.

Espero no tener problemas ya que me la jugue a ciegas. :-)



miércoles, octubre 03, 2018

Usar GeneXus 16 contra GXserver 15

El título es extraño pero es una realidad que intente simular ya que tengo una oportunidad de migrar mis kbs que están en GX15 a GX16 pero no el GXServer.  En el evento tuve la oportunidad de preguntar al equipo de GXServer que pasaba en este caso y obviamente no recomendaban hacer esto.

Dado que quiero arrancar ya mismo con GX16 comence abriendo la kb y haciendo Rebuild-All, no tuve problemas por lo que probé la aplicación y en principio todo funciona bien. Ahora solo me quedaba probar contra GXserver que se encuentra en GX15 u9. Al probar hacer update no tuve problemas por lo que me había puesto contento, el problema lo tuve cuando quise hacer un commit de mi kb (GX16) contra GXServer (GX15) ahí salieron mensajes de error que de alguna manera los estaba esperando.

Error al hacer commit:

error: GeneXus Server: Error reading from export file.
error: GeneXus Server: An error occurred in File 'strbase64tofile_java' : Error reading from export file.
Invalid property 'JavaExtract'.
Invalid property 'NetExtract'.

error: GeneXus Server: Could not commit changes
Commit Failed

Este error me dio con un archivo pero también me da algo parecido con otros tipos de objetos.

En síntesis no voy a poder seguir mi desarrollo con GX16 hasta que no pueda actualizar la versión de GXServer.


martes, octubre 02, 2018

Mi primer error en GeneXus 16 (error: GeneXus Module installation failed)

En el día de ayer instale GX16 en mi equipo y hoy comence por abrir una KB que estaba en GX15, mi equipo tiene Windows 7 con permisos de administrador.

Al abrir la kb e intentar hacer un "Rebuild All" tuve el siguiente mensaje de error:

========== Build All started ==========
warning: Updating 'GeneXus' module version from 1.9.4.120900 to required 2.0.9.127528.
error: GeneXus Module installation failed.
Build All Failed

Revisando un poco el problema me di cuenta que no se estaba copiando el modulo de Genexus pero si creaba la carpeta correspondiente. En mi equipo la carpeta que creaba es la siguiente:
C:\Users\vmwin7\AppData\Roaming\GeneXus\GeneXus\16\Modules_v1.0\GeneXus_4f454e73-7d8f-4a0f-908a-1a355f3634a5\2.0.9.127528

Pero faltaba el archivo: GeneXus_2.0.9.127528.opc

La solución fue copiar el archivo: F:\GeneXus\GX16\Modules\GeneXus_2.0.9.127528.opc a la carpeta:

C:\Users\vmwin7\AppData\Roaming\GeneXus\GeneXus\16\Modules_v1.0\GeneXus_4f454e73-7d8f-4a0f-908a-1a355f3634a5\2.0.9.127528

Luego al abrir la KB y hacer "Rebuild All" el resultado fue el esperado. Seguramente este error es algo de mi instalación y se podría haber solucionado corriendo el /install pero al hacer lo que puse arriba quedo solucionado.

Estoy muy motivado a comenzar a trabajar en esta versión y subir mis resultados para compartirlos con el resto de la comunidad.











  

lunes, octubre 01, 2018

Instalando GX16

A pesar de que estuve probando la versión beta de GX16 en el día de hoy hice la instalación de GX16 la primera versión liberada. En principio no tuve problemas y lo único que me solicito es que instalara .Net Framework 4.7.1, ya que estaba instale el .Net Framework 4.7.2.

Mi equipo tiene Windows 7 y aproveche el .Net Framework 4.7.2 para poder instalar GeneXus Protection Server (9751) para mantener la compatibilidad con las licencias anteriores. 

En cuanto al licenciamiento al instalar GX16 nos pide que actualicemos la licencia, la verdad que esto es un problema ya que me obligan a desinstalar mis licencias y enviarlas a claves para que me las actualicen. Entiendo que esto es un proceso de seguridad pero tengo que admitir que me gustaría que no se hiciera esto para permitirme comenzar a trabajar en GX16 rápidamente y no tener que esperar a actualizar mis licencias.


Ahora me queda pedir las nuevas licencias y comenzar a migrar mis kbs a GX16.

miércoles, septiembre 19, 2018

¿Qué espero del GX28 Encuentro GeneXus ?

Desde hace unos años por problemas de tiempo y salida en producción de varios proyectos no he podido asistir al evento GeneXus como lo hacía antes. En este GX28 voy a intentar asistir ya que existen varias charlas que coinciden con mis investigaciones actuales.

Dado que hace tiempo que no puedo disfrutar de un Evento GeneXus espero encontrarme con amigos y asistir a charlas que me dejen enganchado como antes. Espero que las charlas no sean muy comerciales y sean técnicas ya que estoy en un punto que necesito saber si GeneXus me acompañara en mi proceso de cambios.

En la actualidad no hay forma de concebir nuestro trabajo sin implementar Integración Continua, Microservicios, Módulos y acercarnos a la cultura DevOps.

En síntesis espero que después de este evento pueda afirmar que GeneXus me acompañara en mi proceso de cambios o el estado en el que se encuentran las herramientas que estoy necesitando.

Revisando un poco la agenda pude ver varias cosas interesantes que como decía coinciden con lo que estoy investigando. Voy a intentar ir a las de DevOps, GXServer  y las de seguridad.

Por ahora mi lista de charlas seleccionadas es la siguiente:




jueves, septiembre 13, 2018

Como implementar módulos en GX y no morir en el intento (Parte 2)

Después de haber sufrido un poco en "mi primer experiencia al intentar modularizar una kb" levante un respaldo y arranque nuevamente a modularizar mi kb.  Los problemas que voy a comentar se presentan por partir de una kb mediana que ya tiene años y el sistema atiende a todo el pais por lo que es algo relativamente importante. (Tengo que lograr que el cambio sea trasparente)

Básicamente me puse a pensar como hacer para modularizar mi kb sin tener que hacer un alto en el desarrollo y sin tener que dedicar mucho tiempo, la realidad es que la kb se encuentra en constante desarollo y en la actualidad tiene tres líneas de desarrollo que implican tocar bastante el código existente.

Necesito lograr comenzar a modularizar "rompiendo" lo menos posible mi kb e ir liberando estos cambios aprovechando el cronograma de trabajo establecido.

Quiero aprovechar las instancias de testing para no tener que volver a probar todo luego de pasar a modulos ya que como todos saben es complejo encontrar el tiempo para hacer grandes cambios y quiero aprovechar los cambios solicitados para poder mejorar el diseño de mi kb.

Aprovechando los tiempos que tengo decidi comenzar a modularizar sin hacer un análisis exaustivo de mi kb si no que arranque por las cosas que rompen los ojos y que son fáciles de pasar a un modulo (Ej. funciones de validación de CI o funciones varias que siempre tenemos en nuestra kb).

Para ilustrar y poder contar lo que hice voy a partir de una kb llamada MiKB. Lo que hice en el día de hoy para comenzar a modularizar y dejar andando mi kb es lo siguiente:

a) Hice una nueva Kb llamada MiKB_CORE: esta kb es la que tendra los modulos que luego voy a usar de MiKB. (Quiero trabajar como si fueran paquetes y tener un diseño de paquetes a futuro)

b) Exporte los objetos que fui seleccionando de MiKB y los importe en MiKB_CORE

c) Hice los módulos según el diseño que quiero implementar en la modularización de la KB. ej. utils, common, mensajes, etc.

d) Pase los objetos a cada Módulo según lo que correspondiera dejando público solo lo que corresponda, por ejemplo las transacciones las puse "Private" ya que desde MiKB quiero que solo vean los procedimientos en cada paquete y no las TRNS (Esto en el arranque).

e) Luego de luchar con algunas cosas que voy a poner en las conclusiones de este post genere un paquete por cada módulo.

f) En mi kb origen (MiKB) cargue estos módulos, al hacer esto los objetos que había exportado ya no están en MiKB y en el código hace referencia a los módulos.

g) En la kb origen (MiKB) borre las trn que pase a módulos en la kb MiKB_CORE

h) Hice "rebuild all" y verifique que todo quedara integrado, por ahora solo hice alguna pruebas unitarias teniendo en cuenta las funcionalidades que pase a los módulos.  Subí todo a GXserver y por ahora todo ha compilado y ha quedado instalado sin problemas.

Conclusiones positivas:

a) Al revisar mi kb pude aprovechar a realizar limpieza de objetos apoyándome en KBDoctor. Con la limpieza y la modularización pude eliminar 20 objetos por estar duplicados o deprecated, aparte de pasar 50 objetos a los módulos.

b) En la kb de los módulos aproveche para mejorar el código de los objetos que importe de la kb origen y pude unificar comportamiento de algunos objetos que tenían mas de 10 años.

c) Pude modularizar y visualizar la potencia de tener todo en módulos, aparte de comenzar con el re-diseño de mi KB después de 10 años de estar metiendo mano de una forma no muy organizada.

El resultado de mi primer etapa de trabajo es la siguiente:

KB CORE con los Módulos                                 


KB que utiliza los Módulos:

En síntesis me encuentro motivado y con ganas de seguir modularizando mi kb  para alcanzar un nuevo nivel de GeneXus Modularity Maturity Model.





















miércoles, septiembre 12, 2018

Como implementar módulos en GX y no morir en el intento (Parte 1)

Este es mi segundo intento de comenzar a trabajar con módulos en GeneXus y la verdad que mi experiencia no ha sido del todo buena dado que me he topado con algunos bugs que me están enloqueciendo. 
Según el GeneXus Modularity Maturity Model  me encuentro en el nivel 1 (Sin módulos) por lo que estoy intentando comenzar con los módulos pero no dentro de la kb que quiero modularizar, lo que estoy haciendo es tener otra kb en donde creo los módulos y luego trabajo con los módulos en la kb origen. 
Quiero aclarar que trabajando con módulos dentro de la misma kb no tengo problemas mayores pero quiero trabajar con los módulos como si fueran paquetes dado que quiero tener paquetes separados con las cosas que son comunes en varias kbs. 

Mi idea es poder distribuir los jar de cada paquete (modulo gx) en cada aplicación, me encantaría poder hacer un diagrama de paquetes con los diferentes módulos e integrarlos según mis necesidades. 

Esto dado que en la actualidad tengo 5 kbs que tienen objetos comunes y quiero poner esos objetos en un modulo y usar desde las 5 kbs ese modulo. Aparte de querer modularizar una kb grande para que me quede mas sencilla y aprovechar los beneficios de modularizar.

Básicamente en cuanto al trabajo estoy utilizando GX15 U9 y lo que hice fue crear una kb nueva en donde hice un par de módulos, desde la kb origen fue exportando objetos mediante xpz y los importe en la kb donde tenía los módulos.

En la kb de los módulos renombre estos objetos y los organice según mis necesidades, también me quedaron algunas carpetas dentro de mi módulo con el mismo nombre de la kb origen sin sospechar el resultado que iba a obtener al cargar este módulo en mi kb origen.

El resultado que obtuve al cargar el modulo en la kb origen fue el siguiente:

a) Un objeto que exporte de la kb origen llamado PMiObjeto a la kb de módulos en donde lo renombre a miobjeto y al crear el módulo quedo como mimodulo/miobjeto. Al cargar el modulo a la kb origen me cambio el código en toda la kb en donde estaba PMiobjeto.call(....) por mimodulo.miobjeto.call(...). Esto no es un gran problema pero me hubiera gustado poder hacer el cambio en el código a demanda y que no lo hiciera de forma automática dado que al objeto del modulo le había cambiado las rules por lo que tuve que tocar en varios objetos dado que al cambiar el código tuve que cambiar la llamada por el nuevo parámetro. Lo otro que me llamó la atención fue que me borro el objeto PMiObjeto de la kb.  Tengo que admitir que seguramente esto este documentado y sea que yo me lo comí al tirarme a hacer estos cambios dado que si no es así es un bug de GeneXus.

b) Una carpeta que exporte la puse adentro de mi modulo y al cargar el modulo en la kb origen me cambio en todos los objetos (255) que estaban en esa carpeta la propiedad Module/Folder por el nombre que esta adentro del modulo pero que no existe en la estructura de mi kb. Básicamente por la estructura de mi kb no puedo ver esos 255 objetos y al generar quedaron con el nombre del paquete adelante cuando en realidad no corresponde. 

Seguramente lo que esta pasando al exportar un objeto de la kb origen a una kb de modulo y luego cargar el modulo en la kb origen GeneXus deje algúna referencia en el objeto que haga que se tenga este comportamiento. 

Espero que esto sea un bug de GeneXus y que esto se arregle a futuro para no volver a pasar por esto, al día de hoy tuve que levantar una kb de respaldo y estoy haciendo todo nuevamente. 

Dejo estos comentarios para ir compartiendo mis experiencias, de todas formas no me voy a dar por vencido y voy a continuar intentando modularizar mi kb y no morir en el intento.












miércoles, septiembre 05, 2018

GXUnit (Pruebas unitarias en GeneXus) (DEPRECATED)

En otro artículo comentaba que estaba contento por el resurgimiento de GXUnit pero después de actualizarme me di cuenta que en la actualidad se encuentra "Deprecated". En realidad no se actualiza desde hace un año y hoy en día no se puede descargar del Marketplace de GeneXus.

Estuve indagando y en la actualidad las pruebas unitarias se van a poder actualizar con GXTest4, en principio y por lo que tengo entendido el modulo de gxtest para realizar pruebas unitarias no tiene costo.

Básicamente creo que con GXTest4 voy a poder cumplir el objetivo de realizar pruebas unitarias y va a tener el mantenimiento necesario, esto ayuda a intentar poner recursos para la generación de pruebas unitarias en nuestros procesos de desarrollo.

Por lo que tengo entendido en la versión Tero estara integrado, para GeneXus 15 hay que bajarlo e instalarlo a mano. En mi caso ya lo tengo instalado y me encuentro por arrancar con mis primeras pruebas unitarias.




martes, septiembre 04, 2018

GXUnit (Pruebas unitarias en GeneXus)

En el último mes me encuentro en una búsqueda de mejorar el código que estoy desarrollando y la calidad de los productos en los que estoy participando. Mi motivación se basa en la necesidad de mejorar y adoptar una nueva cultura de trabajo en la cual pueda acompañar las tendencias de la industria de TI.

En principio creo que adoptar la cultura DevOps me permitiría acompañar los cambios necesarios para estar a la altura de los nuevos desafíos a los que me estoy enfrentando a diario.

La intención de comenzar en DevOps me ha llevado a investigar sobre Integración Continua y Liberación continua dentro de la Comunidad GeneXus.

Todo esto me ha llevado a volver a escuchar de la importancia de GXUnit y ver que por suerte ha tenido un resurgimiento, pueden leer mas en estos dos artículos:  GXUnit renace nuevamente y Renovando interés en GXUnit

También comparto los comentarios en donde se ve con asombro que la comunidad de usuarios no le damos la importancia que tiene el proyecto de GXUnit y realmente creo que tenemos que impulsar la utilización de pruebas unitarias en GeneXus.

Ahora me queda comenzar a implementar pruebas unitarias y ver como sacarle el mejor provecho a GXUnit.



lunes, septiembre 03, 2018

GeneXus Modularity Maturity Model

Estoy intentando aplicar o seguir el GeneXus Modularity Maturity Model  planteado por Enrique Almeida, la verdad que es muy bueno poder llegar a tener todo organizado en módulos dado que cuando se trabaja con KB grandes o para proyectos muy grandes esto se hace mas que necesario.

En los proyectos que me encuentro tengo aplicaciones monolíticas que necesitan comenzar a utilizar módulos ya que se vuelve inmanejable tener KB con mas de 5000 objetos sin modularizar.

El principal problema que tengo es de Calidad y creo que al modularizar voy a poder tener este tema bajo control.

En síntesis siguiendo el GMMM me encuentro en el NIVEL 1, espero en próximas publicaciones poder contar del avance en el que me encuentro.




Mis pedidos para GeneXus Server

Desde hace algún tiempo estoy exigiendo bastante a GeneXus Server y le estoy encontrando algunos detalles que me gustaría que no estuvieran. Si tuviera la posibilidad de pedir algo me gustaría que si me bajo las versiones a mi kb local que las mismas se puedan actualizar si cambian en el server sin tener que volver a bajar todo creando una nueva kb.

Ej: Cuando hago el "Create Knowledge Base From GeneXus Server" me traigo las versiones existentes en el server: Digamos que tengo la versión 1.0, 1.1 y la 1.2. hago cambios y al pasar  tiempo en el server se crea la versión 1.3 en el servidor.

En este caso si quiero tener la versión 1.3 en mi copia local  no me queda otra que volver a crearme una nueva kb desde el server . Esto me implica tener que volver a generar todo y realmente alcanzaría con poder traerme la versión del server. Entiendo que seguramente exista algún problema o impedimento técnico que se me este escapando pero sería muy útil poder contar con esta opción.

Tengo formas de resolverlo pero es algo que me facilitaría la vida en la forma de trabajo que estamos implementando.

También tengo que pedir que en el update se pueda filtrar por los comentarios que se ponen en el commit ya que cuando SCM quiere bajar los objetos que fueron etiquetados en un comentario no lo puede hacer directamente si no que tiene que ir a la opción de history ver los objetos y luego marcarlos para bajar.