sábado, diciembre 17, 2022

Estudiar MongoDB on-line

 Estuve revisando y búscando cursos hasta que me di cuenta que existe MongoDB University



En realidad existe la página https://learn.mongodb.com/ que tiene varios recursos para aprender sobre MongoDB, lo que estuve revisando y ya hice varios cursos es en la sección de "MongoDB University". En este lugar existen varios cursos gratis los cuales brindan un comprobante. También se puede hacer la certificación en línea la cual creo que tiene costo. 

En síntesis les comento que este recurso es super completo y van a poder encontrar mucha información para poder formarse en MongoDB.



jueves, diciembre 15, 2022

MongoDB 6.0

La última versión de MongoDB que había usado fue la 4x o algo por el estilo, ahora estoy en un proyecto que debo usar nuevamente Mongo y veo que la última versión es la 6.0x. En principio estoy investigando los cambios y lo primero que puedo decir es que descontinuarón el mongo shell legacy (mongo) a partir de la versión 5.0X. Tienen qu eestar atentos ya que ahora se debe instalar MongoDB Shell (mongosh) para trabajar en consola. 

Por ahora estoy sin mi equpo Linux por lo que voy a describir la instalación que hice en mi equipo Windows, los pasos para instalar son los siguientes:

a) Descargar versión para windows  de MongoDB Community Server
b) Descargar MongoDB Shell

En el proceso de instalación nos presenta pantallas como las siguientes:


En mi caso seleccione la opción completa:


Esta versión se puede instalar como servicio pero en mi equipo decidí no instalarlo como servicio para levantar el server a demanda.


También deje seleccionada la opción de instalar el MongoDB Compass (Herramienta Gráfica) que viene por defecto para poder probarla (prefiero trabajar en consola).

Una vez que finaliza la instalación tuve que agregar a la variable de ambiente "PATH" la ruta de Mongo para poder levantar el servidor por consola como me gusta.

Para levantar el server tengo que hacer lo siguiente:

C:\Users\uruli>mongod

Con este comando les levanta el server y en la consola van a poder visualizar algo similar a lo que muestra la siguiente imágen:



Para acceder al cliente alcanza con ejecutar en consola el comando: mongosh y presenta una pantalla como la se muestra en la siguiente imágen:




Una cosa que puede pasar es que si manejamos toda la instalación por defecto se debe crear la siguiente carpeta: "C:\data\db" de lo contrario el MongoDB server no levanta. Dado que estoy probando hice la creación de esas carpetas y todo funciona correctamente.













jueves, diciembre 01, 2022

tsc : The term 'tsc' is not recognized as the name of a cmdlet...

 Realizando un curso de typescript veo que me aparece el siguiente error:


La verdad que lo primero que hice fue ejecutar:

>npm install typescript --save

El error seguía por lo que búscando en google encontre que la forma de "fixear" esto era haciendo lo siguiente:

> npm install typescript@latest -g

Luego de hacer esto pude ejecutar tsc test.ts y se genero mi archivo test.js sin problemas.


viernes, noviembre 25, 2022

ng.ps1 cannot be loaded because running scripts is disabled on this system

 Seguramente si te topas con este mensaje de error al querer generar un componente en Angular se debe a que estas usando Windows :-)

En mi caso tengo el siguiente error:

> ng g c components/Saludo

ng : File C:\Users\uruli\AppData\Roaming\npm\ng.ps1 cannot be loaded because running scripts is disabled on 

this system. For more information, see about_Execution_Policies at 

https:/go.microsoft.com/fwlink/?LinkID=135170.

At line:1 char:1

+ ng g c components/Saludo

+ ~~

    + CategoryInfo          : SecurityError: (:) [], PSSecurityException

    + FullyQualifiedErrorId : UnauthorizedAccess

Esto se debe a que Windows por defecto tiene directivas para no permitir que scripts mal intencionados se ejecuten en tu equipo. Para poder ver estas directivas puedes hacer lo siguiente:

> Get-ExecutionPolicy -List que te dara una salida similar a esta:

La solución sencilla es ejecutar power-shell como administrador, de lo contrario si estas usando Windows te recomiendo cambiar la politica para CurrentUser, ejemplo:

$> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Luego de ejecutar este comando si ejecuto Get-ExecutionPolicy -List el resultado debería ser el siguiente:



Al realizar este cambio pude mi componente de forma satisfactoria:
$> ng g c components/Saludo
CREATE src/app/components/saludo/saludo.component.html (21 bytes)
CREATE src/app/components/saludo/saludo.component.spec.ts (599 bytes)
CREATE src/app/components/saludo/saludo.component.ts (202 bytes)
CREATE src/app/components/saludo/saludo.component.css (0 bytes)
UPDATE src/app/app.module.ts (487 bytes)



Fuente: Microsoft




Retomando con Angular

Desde hace un tiempo que no tocaba Angular en mi equipo por lo que me ha tocado actualizar la versión como muestra la siguiente imágen:


Vamos a ver como me va con esta verisón

miércoles, febrero 16, 2022

Upgrade macOS Monterey

 Desde hace tres meses me convertí  en usuario MAC, basicamente cambie de trabajo y me asignaron una MAC para trabajar. La verdad que el equipo vuela y hace poco tuve que ejecutar una actualización del SO llamada Monterey. 


En principio no tuve mayores problemas hasta que tuve que usar la terminal y me tope con el siguiente error a la hora de ejecutar diferentes comandos:

-bash: /usr/local/bin/fury: /Library/Developer/CommandLineTools/usr/bin/python3: bad interpreter: No such file or directory


La solución a este problema fue ejecutar el siguiente comando:


$ xcode-select --install



miércoles, agosto 26, 2020

Recuperar contraseña postgres 12 en Linux Mint

En mi equipo tengo instalado Linux Mint 20 y para un proyecto instale PostgreSQL, no lo use por un tiempo y ahora que quiero usarlo me pide contraseña para el usuario postgres. La verdad que no recuerdo haber puesto una contraseña y no encuentro cual es la contraseña por defecto. No soy un guru en este tema por lo que me puse a investigar como restablecer la contraseña, lo dejo aquí por si otro es igual de despistado que yo.

Esto lo hice de la siguiente manera:

Lo primero es editar el archivo pg_hba.conf y agregarle la siguiente línea:

host    all      postgres    127.0.0.1/32     trust


 


Luego de editar el archivo hay que reiniciar el servicio:

service postgresql restart

Luego de reiniciar el servicio pude entrar a cambiar la contraseña del postgres:

psql -h localhost -U postgres

ALTER USER postgres with password 'NuevaPassword';
\q

Después de cambiar el password edite el archivo pg_hba.conf, reinicie el servicio de postgresql nuevamente y pude verificar que efectivamente había podido cambiar la contraseña.




 

 

miércoles, julio 29, 2020

HAPI FHIR for Dummies (20200601)

Cuando estamos arrancando con HAPI FHIR una cosa que me ayudo mucho es que existe un servidor público de test. Para acceder al servidor público tengo que acceder a la siguiente url: http://hapi.fhir.org/


Este servidor de test fue muy útil al comienzo de mi investigación sobre HAPI FHIR.

HAPI FHIR for Dummies (20200701)

Si te encuentras en la etapa de aprender sobre HAPI FHIR aquí va un Tip de los mas básicos.
Cuando te encuentras frente a un servidor HAPI FHIR lo primero que debes hacer para saber que es lo que se encuentra disponible en ese servidor es acceder a su "metadata". Para hacer una prueba puedo acceder al servidor de test de hapi: http://hapi.fhir.org/baseR4/metadata




Ejemplo de la respuesta:


HTTP 200 OK
Response Headers
X-Powered-By: HAPI FHIR 5.1.0-SNAPSHOT REST Server (FHIR Server; FHIR 4.0.1/R4)
Content-Type: application/fhir+xml;charset=utf-8
X-Request-ID: NhDkIGO8AFlOSg6K
Response Body
{
"resourceType": "CapabilityStatement",
"status": "active",
"date": "2020-07-29T15:43:40+00:00",
"publisher": "Not provided",
"kind": "instance",
"software": {
"name": "HAPI FHIR Server",
"version": "5.1.0-SNAPSHOT"
},
"implementation": {
"description": "UHN Test Server (R4 Resources)",
"url": "http://hapi.fhir.org/baseR4"
},
"fhirVersion": "4.0.1",
"format": [ "application/fhir+xml", "application/fhir+json" ],
"rest": [ {
"extension": [ {
"url": "http://hl7.org/fhir/StructureDefinition/capabilitystatement-websocket",
"valueUri": "/websocketR4"
} ],
"mode": "server",
"resource": [ {
"extension": [ {
"url": "http://hl7api.sourceforge.net/hapi-fhir/res/extdefs.html#resourceCount",
"valueDecimal": 500
} ],
"type": "Account",
"profile": "http://hl7.org/fhir/StructureDefinition/Account",
"interaction": [ {
"code": "read"
}, {
"code": "vread"
}, {
"code": "update"
}, {
"code": "patch"
}, {
"code": "delete"
}, {
"code": "history-instance"
}, {
"code": "history-type"
}, {
"code": "create"
}, {
"code": "search-type"
} ],
"versioning": "versioned-update",
"conditionalCreate": true,
"conditionalUpdate": true,
"conditionalDelete": "multiple",
"searchInclude": [ "*", "Account:owner", "Account:patient", "Account:subject" ],
"searchParam": [ {
"name": "_language",
"type": "string",
"documentation": "The language of the resource"
}, {
"name": "owner",
"type": "reference",
"documentation": "Entity managing the Account"
}, {
"name": "identifier",
"type": "token",
"documentation": "Account number"
}, {
"name": "period",
"type": "date",
"documentation": "Transaction window"
}, {
"name": "patient",
"type": "reference",
"documentation": "The entity that caused the expenses"
}, {
"name": "subject",
"type": "reference",
"documentation": "The entity that caused the expenses"
}, {
"name": "SearchByMsgDate",
"type": "date",
"documentation": "Search by patient for a MSH.7 agreement, which is stored in Patient Resource"
}, {
"name": "name",
"type": "string",
"documentation": "Human-readable label"
}, {
"name": "_id",
"type": "token",
"documentation": "The ID of the resource"
}, {
"name": "type",
"type": "token",
"documentation": "E.g. patient, expense, depreciation"
}, {
"name": "status",
"type": "token",
"documentation": "active | inactive | entered-in-error | on-hold | unknown"
} ]
}, {
"extension": [ {
"url": "http://hl7api.sourceforge.net/hapi-fhir/res/extdefs.html#resourceCount",
"valueDecimal": 83
} ],
"type": "ActivityDefinition",
"profile": "http://hl7.org/fhir/StructureDefinition/ActivityDefinition",
"interaction": [ {
"code": "read"
}, {
"code": "vread"
}, {
"code": "update"
}, {
"code": "patch"
}, {
"code": "delete"
}, {
"code": "history-instance"
}, {
"code": "history-type"
}, {
"code": "create"
}, {
"code": "search-type"
} ],
"versioning": "versioned-update",
"conditionalCreate": true,
"conditionalUpdate": true,
"conditionalDelete": "multiple",
"searchInclude": [ "*", "ActivityDefinition:composed-of", "ActivityDefinition:depends-on",
"ActivityDefinition:derived-from", "ActivityDefinition:predecessor", "ActivityDefinition:successor" ],
"searchParam": [ {
"name": ....


La lista es muy extensa ya que es el servidor público de hapi pero seguramente el servidor que me encuentro desarrollando tenga una lista menor, por ejemplo mi servidor local tiene la siguiente lista:


http://localhost:7070/hapilocal/fhir/metadata


Al acceder a la "metadata" de mi implementación se muestra lo que tengo disponible hasta el momento.




HTTP 200 OK
Response Headers
X-Powered-By: HAPI FHIR 5.0.2 REST Server (FHIR Server; FHIR 1.0.2/DSTU2)
X-Request-ID: lbcIeZTv5EZMae6L
Response Body
{
"resourceType": "Conformance",
"publisher": "Not provided",
"date": "2020-07-29T12:04:08-03:00",
"kind": "instance",
"software": {
"name": "HAPI FHIR Server",
"version": "5.0.2"
},
"implementation": {
"description": "HAPI FHIR",
"url": "http://localhost:7070/hapilocal/fhir"
},
"fhirVersion": "1.0.2",
"acceptUnknown": "extensions",
"format": [ "application/xml+fhir", "application/json+fhir" ],
"rest": [ {
"mode": "server",
"resource": [ {
"type": "Location",
"profile": {
"reference": "http://hl7.org/fhir/profiles/Location"
},
"interaction": [ {
"code": "read"
}, {
"code": "vread"
}, {
"code": "update"
}, {
"code": "create"
}, {
"code": "search-type"
} ]
}, {
"type": "OperationDefinition",
"profile": {
"reference": "http://hl7.org/fhir/profiles/OperationDefinition"
},
"interaction": [ {
"code": "read"
} ]
}, {
"type": "Organization",
"profile": {
"reference": "http://hl7.org/fhir/profiles/Organization"
},
"interaction": [ {
"code": "read"
} ]
}, {
"type": "Patient",
"profile": {
"reference": "http://hl7.org/fhir/profiles/Patient"
},
"interaction": [ {
"code": "read"
}, {
"code": "vread"
}, {
"code": "update"
}, {
"code": "create"
}, {
"code": "search-type"
} ],
"searchParam": [ {
"name": "family",
"type": "string",
"documentation": "A portion of the family name of the patient"
} ]
}, {
"type": "Practitioner",
"profile": {
"reference": "http://hl7.org/fhir/profiles/Practitioner"
},
"interaction": [ {
"code": "read"
}, {
"code": "vread"
}, {
"code": "update"
}, {
"code": "create"
}, {
"code": "search-type"
} ],
"searchParam": [ {
"name": "family",
"type": "string",
"documentation": "A portion of the family name"
} ]
}, {
"type": "StructureDefinition",
"profile": {
"reference": "http://hl7.org/fhir/profiles/StructureDefinition"
},
"interaction": [ {
"code": "read"
}, {
"code": "search-type"
} ]
} ]
} ]
}
Wrote 2,4 KB (32,6 KB total including HTML) in estimated 16ms

martes, mayo 19, 2020

Actualizar versión de Git en Linux Mint

Estoy en un proyecto que necesito usar Git y me pidieron que usara una versión nueva pero en mi Linux Mint tenía la versión 2.7.4 como muestra la siguiente imagen:


A pesar de que podría haber trabajado con la versión actual seguí el consejo y actualice a la última versión estable de Git. Para hacer esto tuve que agregar un repositorio y actualizar la versión. Para esto tuve que ejecutar el siguiente comando:

cgomez@cgomez-urulinux ~ $ sudo add-apt-repository ppa:git-core/ppa

Luego de agregar el repositorio de git lo que hice fue actualizar git como muestra la siguiente imagen:




Después de actualizar me quedo actualizado Git



domingo, mayo 17, 2020

Hacer un procedimiento sin hacer Unit Test "Es una irresponsabilidad"

El título de este artículo lo tome de la charla que dio Gaston Milano en el GUG Montevideo, la misma se llama: "Gente, Ideas, Herramientas - Gaston Milano sobre App Coronavirus UY".

En la charla Gaston explica el proceso de desarrollo de la aplicación "Coronavirus UY", cuando se refiere al testing que se le hizo a la aplicación hace hincapié en los Unitt Test.  Sin dudas que esto es importante pero en ocasiones hay que lograr que los equipos y las organizaciones se encuentren maduros para sumar al proceso de desarrollo esta buena práctica.

Hace casi un año escribía algunos artículos sobre "Pruebas unitarias en GeneXus", no fue nada técnico pero conté un poco mi proceso para llegar a la necesidad de contar con Unit Test. Tuve un largo camino dado que primero debía lograr migrar a GeneXus 16 para lograr usar GXTest

Tuve que atravesar algunos problemas antes de poder llegar a implementar Unit Test con GeneXus pero luego de migrar la aplicación de GX9 a GX 15 y por último a GX16 pude llegar a comenzar a implementar mis primeros Unit Test.

En nuestra experiencia tuvimos algunos problemas que fuimos resolviendo pero que nos hicieron cambiar de parecer a la hora de hacer pruebas unitarias para cada procedimiento de nuestra KB. Los principales problemas que encontramos fueron los siguientes:

  • La KB creció considerablemente: por defecto se crean tres objetos (Unit Test, SDT y un Data Provider). 
  • Se necesita Licencia para usar GX-Server y para usar con integración continua
  • No es una práctica extendida dentro de los desarrolladores

En realidad el problema mas complejo de resolver es que los unit test no son una práctica extendida dentro de los desarrolladores genexus y esto hace que no se tenga apoyo para poder lograr recursos para usar GX-Test.

El problema del crecimiento de la kb se puede solucionar modificando los unit test en los casos que sea posible (En un próximo artículo voy a explicar como lo hacemos).

El licenciamiento se puede solucionar pero todavía no pude lograr que se vean los beneficios de esto para obtener los recursos necesarios (Estoy en proceso).

En resumen considero que debemos comenzar a utilizar las pruebas unitarias y extender esta práctica entre la comunidad genexus para poder enriquecer la herramienta, logrando que las organizaciones tengan esto como obligatorio.

El principal debe en la utilización de los unit test esta del lado de los desarrolladores que todavía no han integrado esto a su forma de trabajo y esto hace que en equipos grandes sea complejo implementar esta práctica.

En otro artículo voy a explicar como usamos los unit test en una KB grande que esta teniendo liberaciones de versiones a producción de forma mensual.







domingo, abril 12, 2020

Kotlin Bootcamp for Programmers

Dado que estoy por comenzar un proyecto para mobile estoy investigando Kotlin dado la importancia que esta tomando en el desarrollo para Android. Lo primero que hice fue instalar el Android Studio y ahora estoy investigando un poco Kotlin.
La verdad que estoy fascinado por la cantidad de recursos que tenemos disponibles para los desarrolladores, por ejemplo al entrar a la sección de Kotlin se encuentra disponible un curso en UDACITY totalmente gratis llamado "Kotlin Bootcamp for Programmers".
Aprovechando la cuarentena por el COVID-19 lo estoy siguiendo dado que no tenia ni idea de Kotlin.


Espero poder terminarlo para comenzar rápidamente a realizar alguna app, en principio voy a intentar comparar esto con lo que puedo hacer con el Generador Mobile de GeneXus.

Curso GeneXus for mobile

Este lunes comienzo el curso on-line de GeneXus Mobile en GX 16, el cual se esta dando por una iniciativa de GeneXus de poner disponible este curso a la comunidad.
Este curso siempre se encuentra on-line en modalidad auto-estudio pero en esta oportunidad se hizo una publicación en donde los interesados se anotaban para seguir el curso junto al equipo de capacitación de GeneXus.
La verdad que en versiones pasadas había realizado un acercamiento al generador Mobile pero nunca pude avanzar mucho por falta de tiempo, en esta oportunidad voy a sacarle el máximo provecho que pueda.
Lo poco que pude ver hasta el momento veo que se ha mejorado mucho en la ayuda para instalar el ambiente dado que ahora existe "Android Requirements Installer", esto facilita mucho la instalación cosa que antes era todo manual.


Hasta el momento solo configure el ambiente y estoy a la espera de comenzar este curso para poder implementar un proyecto que tengo en mente. Una aclaración es que si se instala la versión trial la parte de Android se instala sola, en mi caso voy a usar la versión que ya tengo por lo que tuve que instalar el ambiente para Android mediante el "Android Requirements Installer".


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.