tag:blogger.com,1999:blog-59805982024-03-18T00:03:14.668-03:00Desarrollando desde la trinchera.El blog de Enrique Almeida. Desarrollo de aplicaciones, GeneXus y otros divagues.Enrique Almeidahttp://www.blogger.com/profile/13964187630117314432noreply@blogger.comBlogger1227125tag:blogger.com,1999:blog-5980598.post-70381796893534468082024-03-13T18:28:00.002-03:002024-03-14T09:26:51.832-03:00Personalizar el DEPLOY con GeneXus<p></p><div class="separator" style="clear: both; text-align: left;">En los ciclos de desarrollo se necesita hacer llegar desde la KB hasta el ambiente de producción, con una determinada personalización, para que el sistema funcione en producción. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiq0zB576USo2Hbmu9qAoqT8vklVo3Awq_UDhtaPLg5zxhM7E8y2sx4lB0eLoaoLjiNkX6b8ZqsTEKMFP8p-s-aEEJg5peLNy7f8hMxAPJiejzVUrG_VsJBm1gPC4PeGUurEuDITJpKommkbmATc2HX1q8pt9e4-6XC6VJYPPExsRy6qeg6dTjSxw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="639" data-original-width="1776" height="230" src="https://blogger.googleusercontent.com/img/a/AVvXsEiq0zB576USo2Hbmu9qAoqT8vklVo3Awq_UDhtaPLg5zxhM7E8y2sx4lB0eLoaoLjiNkX6b8ZqsTEKMFP8p-s-aEEJg5peLNy7f8hMxAPJiejzVUrG_VsJBm1gPC4PeGUurEuDITJpKommkbmATc2HX1q8pt9e4-6XC6VJYPPExsRy6qeg6dTjSxw=w640-h230" width="640" /></a></div><br /><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div>GeneXus tiene la tarea de Build all bien resuelta, pero aun no contempla el Package ALL, ni el Deploy All, sino que hace el deploy para una deployment unit en forma aislada. <p></p><p>En varias oportunidades surge la necesidad de personalizar los archivos que se necesitan enviar para el deploy. Esto implica cambiar archivos del tipo web.config, appsettings.json, client.cfg, etc. </p><p>La personalización permite el ajuste necesarios para un correcto deploy de la aplicación. </p><p>De que forma se puede hacer?</p><p>En un esquema general, se puede hacer el deploy de cada Deployment Unit. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhVperHrLPRPNUnZMVuvAIC-j_DTiS00Ytl82Pe08vVA0AglKMsSScJ_TjV0DfRrp2-eh6CKDiFhP9p4l-5vncsShz24EnTuNgg2smkDjhf6axLaR0wU0PJ0WhCMN6xaVDK5NheB6QnggdwY-xNMFf_-8D9OtL8MG6vfjAX7lWb8FA0_FogmBGstw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="693" data-original-width="1244" height="356" src="https://blogger.googleusercontent.com/img/a/AVvXsEhVperHrLPRPNUnZMVuvAIC-j_DTiS00Ytl82Pe08vVA0AglKMsSScJ_TjV0DfRrp2-eh6CKDiFhP9p4l-5vncsShz24EnTuNgg2smkDjhf6axLaR0wU0PJ0WhCMN6xaVDK5NheB6QnggdwY-xNMFf_-8D9OtL8MG6vfjAX7lWb8FA0_FogmBGstw=w640-h356" width="640" /></a></div><br /><p></p><p>Tanto si se ejecuta la tarea de Deploy desde el IDE de GeneXus, como automatizando las tareas con MSBUILD y jenkins el proceso es similar. </p><p>La personalización se puede hacer con el proyecto <a href="https://wiki.genexus.com/commwiki/wiki?45672,Customize+GeneXus+Deployment+capabilities"><DUName>_user.gxdproj</a>, que es un proyecto del usuario, donde se pueden poner diferentes comandos para borrar, copiar, renombrar o personalizar archivos. </p><p>La sintaxis de los proyectos MSBUILD no es demasiado amigable, pero una vez que se practica un poco, es fácil de entender. <br /><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjUuIfoNojHH_i6mCO9j9KHHEU8GemaijkcBg3l_NRd8C1RR-8zuTM52z4pI2L-hp8XoY-g1dMmjg1mMxgNVU6C_ZBA-Nk7oN5UhbzW4WEJTKDnb-VB3DaaVzqZQKuep2TyYYPiQ-h40J2FGPRw1SEiw9FNWx6XVpPuEu4DlJXeyI6MRxdliAt08Q" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="914" data-original-width="1437" height="408" src="https://blogger.googleusercontent.com/img/a/AVvXsEjUuIfoNojHH_i6mCO9j9KHHEU8GemaijkcBg3l_NRd8C1RR-8zuTM52z4pI2L-hp8XoY-g1dMmjg1mMxgNVU6C_ZBA-Nk7oN5UhbzW4WEJTKDnb-VB3DaaVzqZQKuep2TyYYPiQ-h40J2FGPRw1SEiw9FNWx6XVpPuEu4DlJXeyI6MRxdliAt08Q=w640-h408" width="640" /></a></div><br />En el ejemplo, en el primer recuadro, se copia un directorio entero. <p></p><p>En el segundo, se establecen algunas variables útiles para lo que viene mas abajo. <br /><br />En el tercer recuadro, se arma una lista de los archivos a copiar y se puede establecer cual será el directorio destino de dichos archivos. </p><p>En el cuarto, se establece la tarea RemoveExtraFiles que permite borrar archivos. <br /><br />En el quito, se hacen 2 cosas, se copia un archivo cambiandole el nombre y también se ejecuta un comando que tiene el nombre de la DeploymentUnit antes de empaquetar la solución, si el mismo existe. <br /><br />Es bueno destacar que se pueden condicionar la ejecución de los comando con la palabra clave <span style="font-family: courier;">Condition</span>, como esta en el ejemplo. <br /><br />En la <span style="font-family: courier;">Condition</span>, se pueden usar propiedades ya existentes, como por ejemplo<br /><span style="font-family: courier;"><b>$(DeploymentUnit)</b></span> - El nombre de la deployment unit que estoy empaquetando. </p><p><b><span style="font-family: courier;">$(Generator)</span></b> - Vale Java, C#, .NET, etc. Es bueno para poder condicionar por generador. <br /></p><p><span style="font-family: courier;"><b>$(DeployTarget)</b></span> - Puede valor Local / Docker, etc... son todas las opciones que a la que puede hacerse deployment. </p><p>Hay muchas mas que se pueden listar, corriendo la tarea msbuild con la opción <b><span style="font-family: courier;">/verbosity:diagnostic</span></b>, y va a listar en el log, todas las propiedades y sus valores. <br /><br />Con la potencia de poder ejecutar comandos, y con <a href="https://ealmeida.blogspot.com/2024/02/herramientas-para-personalizacion-de.html">las herramientas de personalizacion de archivos que nombre en un articulo pasado</a>, se pueden realizar la mayoría de las tareas de personalización a las que nos hemos enfrentado. </p><p>El DEPLOY ALL queda para otro post, porque tambien necesita personalización, pero ya depende de las caracteristicas de cada instalación. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-11107633916419834702024-02-28T11:25:00.015-03:002024-02-28T11:25:57.419-03:00Herramientas para personalización de instalaciones<p> En el proceso de desarrollo con GeneXus, surge la necesidad de personaliza archivos en el momento de la instalación cuando se quiere instalar la misma versión para diferentes clientes o en diferente infraestructura. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1CfCfi1sBGY8zbrtpYROs0MKDCQVMJjnotrxLVrwBbCI-o5dWBck2TywWt1Lk-K4-ZBHvFCcnNEWPkqav1hQ3BEQJJAQbdvQDzZpAg1ZW_z-l3_vDgDXiA4dl5XqrBAWVxctYCvOGnK3fI2YMkjSuxkyA1IAr0c9lEEBc021BN0PbR1m405Ldjw/s512/empaquetado.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="136" data-original-width="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1CfCfi1sBGY8zbrtpYROs0MKDCQVMJjnotrxLVrwBbCI-o5dWBck2TywWt1Lk-K4-ZBHvFCcnNEWPkqav1hQ3BEQJJAQbdvQDzZpAg1ZW_z-l3_vDgDXiA4dl5XqrBAWVxctYCvOGnK3fI2YMkjSuxkyA1IAr0c9lEEBc021BN0PbR1m405Ldjw/s16000/empaquetado.png" /></a></div><br /><p></p><p>En el pasaje a producción, en algunos ambientes se puede utilizar la personalización a través de variables de ambientes (por ejemplo con Docker / Kubernetes) pero en otros ambientes esto no es una posibilidad válida, y hay que cambiar archivos de configuración para lograr que todo funcione correctamente. </p><p>Algunas de las cosas que es necesario personalizar son los siguientes archivos</p><p></p><ul style="text-align: left;"><li>web.config y client.exe.config</li><li>client.cfg</li><li>PDFReport.ini</li><li>CloudServices.config</li><li>rewrite.config</li><li>log.config y log.console.config</li><li>log4j.xml</li><li>connection.gam</li><li>dockerfile</li><li>web.xml</li><li>appsettings.json</li></ul><div>Con seguridad me faltan varios mas. </div><div><br />El formato de estos archivos es variado (xml, json, txt, ini) y por lo tanto las herramientas que usamos para hacer su personalización también varia. <br /><br />La personalización puede hacerse con una sustitución de archivos completa o con una modificación de algunas líneas del mismo. Esto es necesario cuando necesitamos por ejemplo la ultima version que sale de la KB del web.config, pero queremos modificar a que base de datos, usuario y password se conecta. <br /><br />En ese caso, hay que tener una herramienta que permita sustituir parte del archivo xml por otra parte. <br />También debe agregar esa texto, en caso que no exista la entrada correspondiente en el archivo. </div><div>Como son archivos que pueden tener jerarquía o anidaciones, estas sustituciones o agregados no son triviales. </div><div><br />A lo largo de los años, hemos ido acumulado algunas herramientas para hacer la tarea de la personalización de archivos para producción y están especializados por formato. </div><div><br /></div><h3 style="text-align: left;">IniFile - Edición batch de archivos INI</h3><div><a href="https://www.horstmuc.de/wbat32.htm#inifile">https://www.horstmuc.de/wbat32.htm#inifile</a></div><div><br /></div><div>Es útil por ejemplo para el client.cfg</div><div><br /></div><div>Ejemplo que cambia en la sección del ini de DataStore DEFAULT, el usuario y si no esta lo agrega. </div><div><br /></div><div><span style="font-family: courier;">INIFILE client.cfg [com.name|DEFAULT]] USER_ID=Elj20MqY44RPdvT8FEpDD0==</span></div><h3 style="text-align: left;">jq - Edición batch de archivos json</h3><div><a href="https://jqlang.github.io/jq/">https://jqlang.github.io/jq/</a></div><div><br /></div>Esto es útil por ejemplo para personalizar el appsettings.json<p></p><div><span style="font-family: courier;">jq '.</span><span style="font-family: courier;">Connection-Default-User</span><span style="font-family: courier;"> = "</span><span style="font-family: courier;">Elj20MqY44RPdvT8FEpDD0==</span><span style="font-family: courier;">"' appsettings.json > new_appsettings.json</span></div><div><br /></div><div>Es muy poderoso y la sintaxis no es trivial, pero hace su trabajo. </div><div><span style="font-family: courier;"></span></div><p></p><h3 style="text-align: left;">fnr para archivo de texto</h3><div><a href="https://github.com/KimDebroye/Find-And-Replace-Tool">https://github.com/KimDebroye/Find-And-Replace-Tool</a></div><div><br /></div><div>Cuando se tiene un archivo de texto y se quieren hacer sustituciones de búsqueda sencilla o usando expresiones regulares, se puede usar fnr</div><div><br /></div><h3 style="text-align: left;">ctt para xml </h3><div><a href="https://github.com/giansalex/ctt">https://github.com/giansalex/ctt</a></div><div><br /></div><div>Esta herramienta es útil para cambiar el web.config, client.exe.config, rewrite.config, log.config, log.console.config, etc. </div><div><br /></div><div>Necesita archivos de configuración de las transformaciones, en xml, que es un poco pesado, pero no es difícil de programar. El ejemplo de abajo, sustituye el executionTimeout y le pone 1800 en el web.config<div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVXYgr40ttLG-nTY1TC1v11jGPOUAYsVR_N-e8lYaPyJGvE5KadVr1j2J33BYu6kIbIuRJY2EB2tYsDGBjuK4GdqJKotUdAjifa7ZNCDBpUPHmJGsOlZ9Yz21e6qut1xWLb-hHo1D7MkP_8hpeZxIz9jqUtQI4ueZ22pNGRWWtVTppwRUYsPu6Ug/s1101/Imagen%20003.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="143" data-original-width="1101" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVXYgr40ttLG-nTY1TC1v11jGPOUAYsVR_N-e8lYaPyJGvE5KadVr1j2J33BYu6kIbIuRJY2EB2tYsDGBjuK4GdqJKotUdAjifa7ZNCDBpUPHmJGsOlZ9Yz21e6qut1xWLb-hHo1D7MkP_8hpeZxIz9jqUtQI4ueZ22pNGRWWtVTppwRUYsPu6Ug/s16000/Imagen%20003.png" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div>Estas herramientas nos ayudan a que lo que instalamos en producción tenga siempre los mismos valores en algunas secciones críticas de la configuración. </div><p></p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-71184702655048965292024-01-11T12:42:00.003-03:002024-01-11T14:45:24.670-03:00Programa Genexus para cambiar codigo GeneXus usando expresiones regulares.<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhfnT07Qrnyu3ebYcD3D1YFdDH1bt3f20hx9Hhu2bhC1ZERJv_1o6437bRFKsBD73VMDJ5EdZYUBkusxze28ljqnvqAz6LwDJ6aCj3OFUI6pAmC1x3T6q3e7tTjIp0_u4K_nwQjE1EIgvwWIW6vMtMf6ru71Vrpt2IxCMuvhuq3cTe7n-4imuursg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1024" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEhfnT07Qrnyu3ebYcD3D1YFdDH1bt3f20hx9Hhu2bhC1ZERJv_1o6437bRFKsBD73VMDJ5EdZYUBkusxze28ljqnvqAz6LwDJ6aCj3OFUI6pAmC1x3T6q3e7tTjIp0_u4K_nwQjE1EIgvwWIW6vMtMf6ru71Vrpt2IxCMuvhuq3cTe7n-4imuursg" width="240" /></a></div><br />En una KB que tenia muchos años tuvimos que hacerla multi-idioma. <p></p><p>Hay un trabajo grande de poner a los string que no son traducibles el símbolo ! delante. </p><p>Por ejemplo donde antes decía</p><p><span style="font-family: courier;">where ClienteActivo = 'S'</span></p><p>hay que poner</p><p><span style="font-family: courier;">where ClienteActivo = EstadoCliente.Activo </span></p><p>o</p><p><span style="font-family: courier;">where ClienteActivo = !'S'</span></p><p>Hice un programa para leer un archivo de un export de GeneXus y cambiar el código para hacer el segundo cambio. </p><p>Lo que hace es recorrer el archivo del export y se fija si esta en una parte modificable (Source, Rules, Conditions, Source de DataProvider o Data Selector, etc)</p><p>Dentro de esas partes, hay también propiedades, variables, etc que no deberían cambiarse por lo que solo cambia algo si está dentro de una sección <!CDATA. </p><p>A su vez, hay varias excepciones que deben contemplarse, por ejemplo cuando se tiene codigo javascript embebido en el código, o comandos CSHARP, JAVA, SQL o los nombres de las Subrutinas que no deben cambiarse, y no se pueden marcar como no traducibles. </p><p>Solo cambia aquellos strings que son mayúsculas y que tienen por alguna letra y números (si tiene algún carácter raro o es solo números no lo cambia). </p><p>Una vez que tengo esto, utilizo la expresión regular</p><p><span style="font-family: courier;">&Pattern= "(?<!!)(?:'([^']{1,8})')" </span></p><p>para buscar todos los string de largo hasta 8 caracteres, que no tengan un ! delante y solo con comillas simples y luego realizo el reemplazo.</p><p>Cambiar código reemplazando texto con expresiones regulares, es una actividad de riesgo, pero ahorra muchísimas horas de trabajo manual y aburridísimo.<br /><br />Si alguien necesita hacer algo parecido (y lo quiere) le paso el código. </p><p> </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-67467525991113561582023-12-20T09:06:00.002-03:002023-12-20T09:06:49.822-03:00Cambiar atributo a usar valores enumerados<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiQe7QVDZwh71SLA_csbLiXmoUTSMLx5Z3S2KBXpryM1Uj0rUmF7F148nQW8oyU2MhBDHjkptOf-_aCw7ZyIerMDDH6BtHO2JgZ3JsPE3P6R6nC0cAWH2Bp2pFaWLptr1fJHl0tuqATG1PpqFQwes0xNEMHO6au1jPBUfy7_01im-IgDFh3vGkA2g" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="500" data-original-width="750" height="213" src="https://blogger.googleusercontent.com/img/a/AVvXsEiQe7QVDZwh71SLA_csbLiXmoUTSMLx5Z3S2KBXpryM1Uj0rUmF7F148nQW8oyU2MhBDHjkptOf-_aCw7ZyIerMDDH6BtHO2JgZ3JsPE3P6R6nC0cAWH2Bp2pFaWLptr1fJHl0tuqATG1PpqFQwes0xNEMHO6au1jPBUfy7_01im-IgDFh3vGkA2g" width="320" /></a></div><br />En versiones anteriores de Genexus, no se podían tener dominios con valores enumerados. <br />Esto es un atributo que solo pueda tener los valores que se ponen en una lista y nada mas que esos. <div>Esta muy bueno también para poner constantes en los programas, sin tener que poner numero o strings con significados mágicos. </div><div><br /></div><div>Por ejemplo, antes poniamos:<br /><br />PedidoEstado<><b> !'I' </b> and PedidoEstado <> <b>!'F' </b> </div><div><br /></div><div>y con un dominio enumerado se pone</div><div><br /></div><div>PedidoEstado<> <b>Estado.Inicial</b> and PedidoEstado <> <b>Estado.Final</b></div><div><b><br /></b></div><div>* La nomenclatura no es la mejor, pero es para que quede fácil de entender</div><div><br /></div><div>Las ventajas es que el código queda mucho mas claro, y queda referencias donde se utilizan los diferentes valores. <br />La relación entre el valor que se guarda en la base de datos y lo que tienen los programas esta concentrada en la lista de valores enumerados del dominio o del atributo y no por todos los programas. Cuando cambio la lista, cambia automáticamente en toda la aplicación. </div><div>También tiene ventajas si necesito traducir la aplicación a otros idiomas. </div><div><br /></div><div>Ahora, que debo hacer si quiero cambiar un atributo que no tiene valores enumerados a que use valores enumerados? </div><div><br /></div><div>Una forma es recorrer todos los programas que hagan referencia al atributo y revisarlos uno a uno. </div><div><br /></div><div>Otra forma que a mi me resulta mas facil, aunque poco intuitiva, es hacer un cambio de tipo de datos en forma temporal, para detectar donde debo hacer los cambios. </div><div><br /></div><div><b>IMPORTANTE: Hacer esto en una KB de copia de trabajo y que no reorganice la base de datos. </b></div><div><br /></div><div>Por ejemplo, si tengo </div><div><br /></div><div>PedidoEstado <b>Character(1) </b> //Puede tener los valores I, R, F</div><div><br /></div><div>lo cambio a (puede ser a cualquier tipo que la conversión no sea automática y de error)</div><div><br /></div><div>PedidoEstado <b>Numeric(1) </b> //Le pongo un valor enumerado con 1,2,3</div><div><br /></div><div>y hago un build all. </div><div><br /></div><div>Esto hará que la mayoría de los programas que usan el atributo PedidoEstado fallen porque realizan operaciones de Character en vez de Numericos, pero Genexus me dice exactamente en que linea se realiza esta operacion y me da una lista de todos los objetos que tengo que corregir. En KB grandes, esto ayuda muchísimo <br />Hago el cambio solo en los programas, cambiando las constantes, en los lugares que correspondan sustituyendolas por los valores del dominio enumerado. </div><div><br /></div><div>Paso a Paso.</div><div><br /></div><div>1) Hacer un backup de la KB o un export o crear una versión para tener donde volver si hay errores. </div><div><br /></div><div>2) Cambiar la propiedad del generador para no reorganizar</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh9qw-aYrOM7qFTeYF1nVgwq2MUDWqzNTcOaKO0ChCtxV5nWi_IGDgsUoLtLifT8p4r4QAe1XGVYXg1k5JUn-88LM-0eV99OwwDNjZEo0jJoQo55B86EVmbTrPVQN4NRDnQKv5ZnioCbFq6cm-94wvr4S6Qo71fflW726tt8I4UyTHFgwRiK_reUw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="214" data-original-width="451" height="190" src="https://blogger.googleusercontent.com/img/a/AVvXsEh9qw-aYrOM7qFTeYF1nVgwq2MUDWqzNTcOaKO0ChCtxV5nWi_IGDgsUoLtLifT8p4r4QAe1XGVYXg1k5JUn-88LM-0eV99OwwDNjZEo0jJoQo55B86EVmbTrPVQN4NRDnQKv5ZnioCbFq6cm-94wvr4S6Qo71fflW726tt8I4UyTHFgwRiK_reUw=w400-h190" width="400" /></a></div><br /><br /></div><div><br /></div><div>3) Cambiar el dominio del atributo a un tipo de datos incompatible y poner valores enumerados que se quieran mantener <br /><br /><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiYYVbqfM_SxMsBn8DKFLkAx6PEl2xdcynoo6Yjx6JycOYFoVgosnfOl3myfpBa4xC2_YkyXVHqwIP_xrlmkVlhgQ3kNtEVen6cFDDD8aSVhjLdupYjDRfgiJjWU4dQPoRCfCjSfdTyS1WPEdmBkfievqlm43niqbiZLAm-1KHoMzaYO6nxBNePJg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="155" data-original-width="649" height="76" src="https://blogger.googleusercontent.com/img/a/AVvXsEiYYVbqfM_SxMsBn8DKFLkAx6PEl2xdcynoo6Yjx6JycOYFoVgosnfOl3myfpBa4xC2_YkyXVHqwIP_xrlmkVlhgQ3kNtEVen6cFDDD8aSVhjLdupYjDRfgiJjWU4dQPoRCfCjSfdTyS1WPEdmBkfievqlm43niqbiZLAm-1KHoMzaYO6nxBNePJg" width="320" /></a></div><br /><br /></div><div><br /></div>El campo VALUE hay que cambiarlo para que tengan el tipo que corresponda en ese momento. </div><div><br /></div><div>5) Revisar la reorg que se genera y verificar que cambian todos los atributos necesarios y solo esos. </div><div><br /></div><div>6) Hacer un build all y van a aparecer errores de asignación de tipos de datos incorrectos y de comparación de tipos de datos. Si son muchos, se puede generar una Categoria con todos los objetos que hay que revisar/corregir. </div><div><br /></div><div>7) Corregir todos los errores del tipo en selecciones</div><div><br /></div><div><span style="font-family: courier;">where PedidoEstado = <b>!'I'</b></span></div><div><br /></div><div>por </div><div><br /></div><div><span style="font-family: courier;">where PedidoEstado = <b>PedidodEstado.Inicial</b></span></div><div><br /></div><div>8) Corregir todos los errores del tipo en asignaciones</div><div><br /></div><div><span style="font-family: courier;">PedidoEstado = <b>!'F'</b></span></div><div><br /></div><div>por</div><div><br /></div><div><span style="font-family: courier;">PedidoEstado = <b>PedidoEstado.Final</b></span></div><div><br /></div><div>9) Van a existir algunos errores que no conviene corregir por ejemplo si tengo concatenación de string para mostrar mensajes o cosas asi. </div><div><br /></div><div>10) Volver a hacer un build all (seguirán habiendo errores). </div><div><br /></div><div>11) Volver el dominio al tipo de datos correcto</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEieRlk09on2sJ6HRAaXl0L9YXyrtBtw05IN1Jqa9H5cPZrJwdeHEXF9ZfpxR_02liE0RTIK3Y8mvv2WidUoz3_CjXdQK__k-DVG7Qsw_UdUHFlGMtZYY322Ql0PJgktmdFRAJxYN58RcRvgnI_U2yyyMsq_iRCzK2poyPuyfruzZM7-cWlUtn-TIw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="156" data-original-width="656" height="95" src="https://blogger.googleusercontent.com/img/a/AVvXsEieRlk09on2sJ6HRAaXl0L9YXyrtBtw05IN1Jqa9H5cPZrJwdeHEXF9ZfpxR_02liE0RTIK3Y8mvv2WidUoz3_CjXdQK__k-DVG7Qsw_UdUHFlGMtZYY322Ql0PJgktmdFRAJxYN58RcRvgnI_U2yyyMsq_iRCzK2poyPuyfruzZM7-cWlUtn-TIw=w400-h95" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>12) Hacer un Build All y ya no deberían haber errores. </div><div><br /></div><div>13) Volver el valor de la propiedad del generador para que vuelva a reorganizar la base de datos. </div><div><br /></div><div>14) Testear y volver los cambios al server. <br /></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-57983014348046559142023-12-05T10:00:00.008-03:002023-12-06T09:10:52.059-03:00Sistema LUCIA: 25 años de una KB GeneXus en producción<p style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi1nCzyNnX_w3dZvoK8m94T34pHO061-z2Lts5FoYbCeW5q95FpF9_qbRFPIvCVUMZGC4aWk5dRhdses0J9vVdAyZfHGvlI0aJHINxu6d7ncTj9pf04MjcMNzTUY6lWBEHelPCr-3xOYEO61JsdL9v1mOTa0eEmNrcRNHF8jwC2sJt3AnDbKb-h9w" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1024" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEi1nCzyNnX_w3dZvoK8m94T34pHO061-z2Lts5FoYbCeW5q95FpF9_qbRFPIvCVUMZGC4aWk5dRhdses0J9vVdAyZfHGvlI0aJHINxu6d7ncTj9pf04MjcMNzTUY6lWBEHelPCr-3xOYEO61JsdL9v1mOTa0eEmNrcRNHF8jwC2sJt3AnDbKb-h9w" width="240" /></a> </p><p>Se cumplieron los 25 años del Sistema LUCIA en producción (ver el <a href="https://ealmeida.blogspot.com/2018/11/sistema-lucia-20-anos-de-una-kb-en.html">post de los 20 años</a>) .<br />Es un <b>sistema aduanero</b>, que permite la declaración aduanera de I<b>mportaciones, Exportaciones, Tránsitos </b>y la liquidación de los tributos correspondientes. <br /><br />También se controlan los requisitos documentales y de controles de diferentes organismos para poder realizar estas operaciones. </p><p>Adicionalmente controla las <b>cargas marítimas, aéreas, terrestres, fluviales</b> que entran y salen del país, cruzando las declaraciones de cargas, con las operaciones aduaneras. </p><p>Tenemos un <b>equipo maravilloso</b> de arquitectos, programadores, testers, documentadores, mesa de ayuda, abogados, funcionales, dba, devops. Somos 23 personas las que participamos. Si lo comparamos con países de sistemas aduaneros de tamaño similar, logramos mantener el sistema actualizado con menos personas. La instalacion, operacion del sistema y administración de la infraestructura es realizada por otra empresa.</p><p>Durante 25 años muchos mas han colaborado para llegar hasta aca. A todos ellos gracias!.</p><p>Para actualizar algunos de los datos que puse hace 5 años<br /><br /><google-sheets-html-origin></google-sheets-html-origin></p><table border="1" cellpadding="0" cellspacing="0" data-sheets-root="1" dir="ltr" style="border-collapse: collapse; border: none; font-family: Arial; font-size: 10pt; table-layout: fixed; width: 0px;" xmlns="http://www.w3.org/1999/xhtml"><colgroup><col width="217"></col><col width="123"></col><col width="118"></col><col width="100"></col></colgroup><tbody><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Item"}" style="background-color: #c9daf8; border: 1px solid rgb(0, 0, 0); font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: center; vertical-align: bottom;">Item</td><td data-sheets-value="{"1":2,"2":" Acumulado 2018"}" style="background-color: #c9daf8; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: center; vertical-align: bottom;">Acumulado 2018</td><td data-sheets-value="{"1":2,"2":"Acumulado 2023"}" style="background-color: #c9daf8; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: center; vertical-align: bottom;">Acumulado 2023</td><td data-sheets-value="{"1":2,"2":"Unidad"}" style="background-color: #c9daf8; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Unidad</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Recaudación"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Recaudación</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":38627870023}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">38,627,870,023</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":54228422405.42}" style="border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">54,228,422,405</td><td data-sheets-value="{"1":2,"2":"U$S"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">U$S</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Recaudación diaria (promedio)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Recaudación diaria (promedio)</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":2,"2":"5.291.489"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">5.291.489</td><td data-sheets-formula="=R[-1]C[0]/25/365" data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":5942840.811552876}" style="border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">5,942,841</td><td data-sheets-value="{"1":2,"2":"U$S / dia"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">U$S / dia</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Declaraciones (DUA)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Declaraciones (DUA)</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":6495684}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">6,495,684</td><td data-sheets-formula="=R[0]C[-1]+R[36]C[7]" data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":8400006}" style="border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">8,400,006</td><td data-sheets-value="{"1":2,"2":"DUA"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">DUA</td></tr></tbody></table><p>Recaudar casi 6 millones de dolares por dia, es toda una responsabilidad. </p><table border="1" cellpadding="0" cellspacing="0" data-sheets-root="1" dir="ltr" style="border-collapse: collapse; border: none; font-family: Arial; font-size: 10pt; table-layout: fixed; width: 0px;" xmlns="http://www.w3.org/1999/xhtml"><colgroup><col width="381"></col><col width="96"></col><col width="93"></col></colgroup><tbody><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Datos de la KB"}" style="background-color: #c9daf8; border: 1px solid rgb(0, 0, 0); font-family: docs-Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Datos de la KB</td><td data-sheets-value="{"1":3,"3":2018}" style="background-color: #c9daf8; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: center; vertical-align: bottom;">2018</td><td data-sheets-value="{"1":3,"3":2023}" style="background-color: #c9daf8; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: center; vertical-align: bottom;">2023</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Tablas"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Tablas</td><td data-sheets-value="{"1":3,"3":999}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">999</td><td data-sheets-value="{"1":3,"3":1259}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1259</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Objetos (programas)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Objetos (programas)</td><td data-sheets-value="{"1":3,"3":11.612}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">11.612</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":17459}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">17,459</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Objetos (programas + atributos + temas + archivos, etc)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Objetos (programas + atributos + temas + archivos, etc)</td><td data-sheets-value="{"1":3,"3":27.214}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">27.214</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":38011}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">38,011</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Módulos"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Módulos</td><td data-sheets-value="{"1":3,"3":102}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">102</td><td data-sheets-value="{"1":3,"3":149}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">149</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Bases de Datos (Instancias Oracle)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Bases de Datos (Instancias Oracle)</td><td data-sheets-value="{"1":3,"3":4}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">4</td><td data-sheets-value="{"1":3,"3":4}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">4</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Bases de Datos (Tamaño en TB)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Bases de Datos (Tamaño en TB)</td><td data-sheets-value="{"1":3,"3":4.5}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">4.5</td><td style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">8</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Lineas de Codigo (millones)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Lineas de Codigo (millones)</td><td data-sheets-value="{"1":3,"3":16.7}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">16.7</td><td data-sheets-value="{"1":3,"3":15.1}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">14.1</td></tr><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"Archivos fuentes (*.cs)"}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; vertical-align: bottom;">Archivos fuentes (*.cs)</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":21000}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">21,000</td><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":24500}" style="background-color: white; border-color: rgb(204, 204, 204) rgb(0, 0, 0) rgb(0, 0, 0) rgb(204, 204, 204); border-image: initial; border-style: solid; border-width: 1px; font-family: Roboto; font-size: 11pt; font-weight: normal; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">18,587</td></tr></tbody></table><p>Es llamativo ver como bajo la cantidad de archivos y las líneas de código, a pasar de haber agregado muchas tablas y tener mas objetos. Lamentablemente use herramientas diferentes para contar los archivo y las líneas de código. La que uso ahora, no toma en cuenta archivos repetidos. </p><p><google-sheets-html-origin></google-sheets-html-origin>No voy a repetir la historia de la KB y sus instalaciones, porque ya esta escrito en el post anterior. </p><p>En estos años incorporamos GAM, GXFlow, Firma Digital, servicios REST y se hicieron cubos con Pentaho y SuperSet para resolver parte de la Analitica. <br /></p><p>Actualmente tenemos 5 KB estamos en pleno proceso de migración de las mismas a GeneXus 18 Upgrade 6. </p><p>Se hicieron 11.639 Commits en 5 años, o sea mas de 6 Commits por dia en GXServer (esto es en la KB mayor, las otras tienen un poco menos de actividad). </p><h3 style="text-align: left;">Proceso de build, pack, deploy y test automatizado. </h3><p>Algunas cosas a destacar:</p><p><b>Build </b>- Chequea si hay cambios en el servidor. Si no cambio nada, no hace nada. <br />Si hay cambios baja los cambios del server, salva la reorg si cambia la estructura de la base de datos, hace un build all.</p><p><b>Pack </b>- Para cada uno de las Deployment Units separa los archivos en directorios para instalar. <br />Se agregan archivos adicionales que no brinda GeneXus, necesario para producción</p><p><b>Deploy Simple </b>- Es el proceso que copia los cambios a los ambientes y personaliza los archivos de configuración para los diferentes ambientes (TesteoManual, TesteoAutomatizado, Stage). Es relativamente rapido y puede correr varias veces al dia. <br /><br /><b>Deploy Completo</b> - Se borra toda la infraestructura y se vuelve a crear. Se borran sitios, directorios virtuales, se instalan certificados, se configuran bindings, etc. Luego se copia el 100% de los ejecutables. Esto ejecuta una vez por noche. </p><p><b>Test Automatizado </b>- Se ejecutan los UnitTest y los UITest. Esta es una etapa que nos gustaría tener mas casos automatizados, pero es bastante costoso crearlos y mantenerlo. </p><p><b>API Test</b> - Antes de instalar, se ejecuta un proceso manual que chequea que los servicios brindados por el sistema, no cambiaron con respecto a la versión anterior. </p><p>Algo que nos resultó útil, es manejar un código de versión para cada uno de estos pasos. </p><p>Usamos una nomenclatura que es esta:<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgZCkKee77G2hNj13ktfkZDxqKda9o-f78NCLLI92AyY_BXr0G_XA_aQrewJw5kiqEbeoJnjECvWAU1KN74e9lrBIH1GIs5wSvJLS-fLAJ5McHHsK6AgCHIBccjJsznJQe7wI-fjxxU7BH4f8BPu01UJBij5UGEq__7giSdZieE5dHdArnWgGXIfw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="149" data-original-width="669" height="71" src="https://blogger.googleusercontent.com/img/a/AVvXsEgZCkKee77G2hNj13ktfkZDxqKda9o-f78NCLLI92AyY_BXr0G_XA_aQrewJw5kiqEbeoJnjECvWAU1KN74e9lrBIH1GIs5wSvJLS-fLAJ5McHHsK6AgCHIBccjJsznJQe7wI-fjxxU7BH4f8BPu01UJBij5UGEq__7giSdZieE5dHdArnWgGXIfw" width="320" /></a></div>Esto nos facilitó muchísimo todo el proceso del manejo del flujo. Esto se va a completando a medida que avanza el proceso. <div><br /></div><div>Por ejemplo, si cambia la versión de GeneXus, en vez de hacer un build all, hacemos una limpieza y un REBUILD ALL. </div><div><br />Si solo cambia el número de Commit, solo hay que hacer un build all. </div><div><br /></div><div>Además, es bueno hacer llegar eso a producción, para tener trazabilidad hasta que commit esta instalado. </div><div><br /></div><h3 style="text-align: left;">Futuro</h3><div>En los próximos meses, vamos a hacer la instalación de todo esto en GeneXus 18. <br />También vamos a empezar una migración de .NET Framework a .NET Core y a .NET 8.</div><div><br /></div><div>A nivel de infraestructura estamos empezando a usar contenedores y Kubernetes<br /><br />Vamos a tener que buscar (o inventar) las herramientas para ajustar los archivos de configuración json para los diferentes ambientes (hoy lo tenemos para xml). Van a estar divertidos los próximos meses. </div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com1tag:blogger.com,1999:blog-5980598.post-38826166829360248552023-11-13T10:58:00.002-03:002023-11-13T11:02:56.226-03:00Estado de automatización del proceso del desarrollo con GeneXus (2023)<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiC-aV36HEBqy9mAx9QkyKPv0b5JXZivN1GVQFj4f4wAG8d8KXnQbSlEyQuF96RTKa5BJP3h63IOVz7oNV92byicMRQl1rLITumzlnbhLoTjoj_1tAypxPeHfxGrA6Jn71uE_iv7JOc4qu_vZITBoiQkyBkDozV226XmUUaiLMlovv15yH5z8EeDw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1024" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEiC-aV36HEBqy9mAx9QkyKPv0b5JXZivN1GVQFj4f4wAG8d8KXnQbSlEyQuF96RTKa5BJP3h63IOVz7oNV92byicMRQl1rLITumzlnbhLoTjoj_1tAypxPeHfxGrA6Jn71uE_iv7JOc4qu_vZITBoiQkyBkDozV226XmUUaiLMlovv15yH5z8EeDw" width="240" /></a></div><br />Hace 4 años publiqué una artículo sobre <a href="https://ealmeida.blogspot.com/2019/10/estado-de-automatizacion-del-proceso-de.html">Estado de automatización del proceso de desarrollo con Genexus.</a><p></p><p>Con la aparición de los modelos LLM y el ChatGPT (y los modelos similares) se hace posible automatizar algunas tareas del ciclo de desarrollo que antes era imposible hacer en forma automática. </p>
<h3 style="text-align: left;"> 1 ) ANALISIS - Captura de Requerimientos</h3> <h4>Herramientas:</h4> Issue Tracking, Mind Mappers <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4><div>En esta etapa, creo que la inteligencia artificial (IA) puede mejorar significativamente la etapa de análisis de requerimientos en el desarrollo de software de las siguientes maneras: </div><div><b> Automatización en la Captura de Requerimientos:</b> Utilizando técnicas de procesamiento de lenguaje natural (NLP), la IA puede analizar y extraer requisitos clave automáticamente de documentos, correos electrónicos y notas. </div><div><b> Validación y Consistencia de Requerimientos:</b> Los algoritmos de IA pueden revisar los requerimientos para detectar inconsistencias, ambigüedades o conflictos, asegurando claridad y factibilidad. </div><div><b> Predicción de Impacto del Cambio:</b> La IA puede predecir cómo los cambios en los requerimientos afectarán el proyecto en términos de tiempo, costo y recursos, facilitando la toma de decisiones informada. </div><div><b> Generación Automática de Documentación:</b> La IA ayuda a generar documentación de requerimientos de manera automática, asegurando que todos los detalles importantes estén bien documentados y sean fácilmente accesibles."
<h3 style="text-align: left;"> 2 ) PLANFICACION - Pago de deuda tecnica</h3> <h4>Herramientas:</h4> Issue Tracking <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4><b> Análisis y Priorización de Requerimientos:</b> Mediante el análisis de grandes volúmenes de datos, la IA identifica tendencias y necesidades del usuario, ayudando a priorizar los requerimientos basándose en su impacto y viabilidad.
<h3 style="text-align: left;"> 3 ) PLANIFICACION - Planificacion de un sprint</h3> <h4>Herramientas:</h4> Issue Tracking, GANTT, KANBAN, <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4>En esta etapa crucial, donde se determina la urgencia e importancia de los requerimientos, las herramientas actuales facilitan significativamente el procesamiento del feedback de usuarios y stakeholders. Esto optimiza la planificación, permitiendo un análisis detallado de demoras o márgenes de maniobra en tareas de sprints anteriores. Además, se puede mejorar notablemente la asignación de tareas entre los miembros del equipo, gracias a un mejor entendimiento de su rendimiento y las cargas de trabajo manejadas en sprints previos.<br /><h3 style="text-align: left;"> 4 ) DISEÑO - Base de datos</h3> <h4>Herramientas:</h4> Genexus<h4>Dificultad:</h4> BAJA <h4>Observaciones:</h4>El proceso de diseño de bases de datos relacionales se ha vuelto aún más sencillo, ya que ahora es posible describir un problema y obtener un diseño preliminar que se puede ajustar progresivamente. Sin embargo, es importante destacar que las aplicaciones modernas han evolucionado para requerir múltiples bases de datos o la incorporación de variados repositorios de datos, tales como REDIS, Storage Providers, entre otros, los cuales también necesitan ser reorganizados y mantenidos adecuadamente. Además, ha surgido la necesidad de manejar bases de datos con enfoques distintos, como las orientadas a grafos, vectores, clave-valor, etc., lo cual plantea el desafío de gestionar eficientemente la evolución del modelo de datos en todas sus variantes.<br /><h3 style="text-align: left;"> 5 ) DISEÑO - UX</h3> <h4>Herramientas:</h4> Bocetos, Prototipos <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> La AI puede generar automáticamente wireframes a partir de descripciones escritas o datos de entrada. Por ejemplo, al proporcionar un breve resumen de las funcionalidades deseadas, la AI puede sugerir un diseño de wireframe que incorpore esos elementos. y las mejores practicas de UX/UI. La AI puede ofrecer múltiples versiones de un wireframe, permitiendo a los diseñadores explorar diversas opciones y iterar rápidamente. Esto puede ser particularmente útil en las primeras etapas de diseño, donde la experimentación y la flexibilidad son cruciales. </div><div><br /></div><div>También podría tener integración con herramientas de diseño como Figma o Sketch y luego pasar eso a GeneXus en forma rápida. <span style="color: #0f0f0f; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; white-space-collapse: preserve;">
</span></div><div><h3 style="text-align: left;"> 6 ) DISEÑO - PRESENTACION USUARIO /UI / DISEÑO GRÁFICO</h3> <h4>Herramientas:</h4> Sketch <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> La integración con herramientas como Figma y otras plataformas de diseño de interfaces no ha llevado a una automatización completa, sino más bien a una externalización significativa de una parte del proceso de diseño de UI. Esta especialización presenta una dinámica interesante, aunque aún no la he explorado lo suficiente como para formar una opinión concluyente sobre su eficacia. Lo que resulta evidente es que esta integración ofrece al desarrollador GeneXus una experiencia de trabajo mejorada, al tiempo que permite al diseñador utilizar herramientas con las que está más familiarizado. Sin embargo, el aspecto crucial a considerar es la eficacia a largo plazo de esta metodología: es fundamental evaluar si esta integración contribuye a la creación de aplicaciones de alta calidad que sean sostenibles y fáciles de mantener con el tiempo.
<h3 style="text-align: left;"> 7 ) DISEÑO - ARQUITECTURA</h3> <h4>Herramientas:</h4> Notepad <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4><div>Automatizar el diseño de arquitectura de aplicaciones en GeneXus puede ser un desafío debido a la complejidad y variabilidad de las necesidades de las aplicaciones. Sin embargo, hay varias estrategias y tecnologías que pueden utilizarse para lograr cierto grado de automatización:</div><div><br /></div><div><b>Uso de Plantillas de Arquitectura</b>: Desarrollar y utilizar plantillas de arquitectura predefinidas para diferentes tipos de aplicaciones puede ser un primer paso hacia la automatización. Estas plantillas pueden ser configuradas para cubrir escenarios comunes, reduciendo el trabajo manual en la configuración inicial.</div><div><br /></div><div><b>Automatización de Decisiones de Diseño Basadas en Reglas</b>: Implementar un sistema de reglas que tome decisiones de diseño de arquitectura basadas en parámetros predefinidos. Por ejemplo, según el tamaño del proyecto, el número de usuarios esperados, o la naturaleza de los datos manejados, el sistema podría sugerir ciertas configuraciones de base de datos o enfoques de procesamiento.</div><div><br /></div><div><b>Integración con Herramientas de CI/CD: </b>Automatizar aspectos de la arquitectura relacionados con la integración y despliegue continuos, lo que puede ayudar a implementar prácticas de desarrollo más ágiles y adaptativas. Tambien se podria colaborar con el armado de la infraestructura con herramientas como Terraform / Chef / Puppet / Ansible / Jenkins, etc</div><div><br /></div><div>Es importante destacar que, aunque la automatización puede facilitar y acelerar el proceso de diseño de arquitectura, siempre debe haber un nivel de supervisión y ajuste manual por parte de los desarrolladores para asegurar que la arquitectura final satisfaga todas las necesidades y requisitos específicos del proyecto.</div><h3 style="text-align: left;"> 8 ) DISEÑO - API</h3> <h4>Herramientas:</h4><div>Genexus Next</div> <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4>Actualmente, disponemos de herramientas capaces de automatizar la generación y el mantenimiento de APIs. Por ejemplo, GeneXus Next ya automatiza la generación de APIs para operaciones como Alta, Baja, consulta y modificación de entidades definidas. Sería ventajoso integrar todo este proceso con un objeto API único, en lugar de la gestión actual a través de Business Components (BC), aunque esto representa simplemente un detalle de implementación. Adicionalmente, sería beneficioso contar con herramientas que faciliten el análisis de impacto de las APIs, de manera similar a como se realiza con las bases de datos. Esto permitiría informar y gestionar de manera más eficiente los cambios realizados en las APIs.<br /><h3 style="text-align: left;"> 9 ) DISEÑO - MODULARIZACION</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4>Actualmente, la modularización se realiza manualmente. Sin embargo, con el surgimiento de bases de datos vectoriales, se ha facilitado considerablemente la agrupación de objetos según su proximidad semántica, una tarea que era mucho más compleja en el pasado. A pesar de estos avances, aún no hemos progresado lo suficiente para alcanzar una automatización completa en la tarea de modularización de una base de conocimientos (KB).<br /><h3 style="text-align: left;"> 10 ) DISEÑO - PROGRAMACION</h3> <h4>Herramientas:</h4> GENEXUS <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4> Aunque todavía no es una realidad, parece casi seguro que en un futuro cercano dispondremos de asistentes virtuales especializados para apoyarnos en las tareas de programación. Estos asistentes serían similares a los actuales modelos de Large Language Model (LLM), que ya están facilitando la programación en otros lenguajes.
<h3 style="text-align: left;"> 10bis ) DISEÑO - PRUEBAS / CASOS DE PRUEBA</h3> <h4>Herramientas:</h4><div>GXTest</div> <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4><div>La inteligencia artificial (AI) puede transformar significativamente el proceso de generación de casos de prueba en el desarrollo de software. Aquí hay algunas maneras :</div><div><br /></div><div><b>Identificación Automática de Casos de Prueba:</b> Mediante el análisis de especificaciones de software y documentación, la AI puede identificar automáticamente escenarios relevantes que requieren pruebas. Esto incluye la comprensión de los requisitos funcionales y no funcionales para generar casos de prueba pertinentes.</div><div><br /></div><div><b>Generación de Datos de Prueba:</b> La AI puede generar conjuntos de datos de prueba que simulan diferentes escenarios y condiciones de usuario. Esto es particularmente útil para pruebas de carga y rendimiento, donde se necesitan datos variados y a gran escala.</div><div><br /></div><div><b>Pruebas de Regresión Inteligentes:</b> La AI puede identificar qué partes del software han cambiado y generar automáticamente casos de prueba de regresión específicos para esas áreas, mejorando la eficiencia del proceso de prueba.</div><div><br /></div><div>En resumen, la integración de la AI en la generación de casos de prueba no solo agiliza y mejora la cobertura de las pruebas, sino que también asegura que sean más relevantes y eficientes, alineándolas mejor con las necesidades reales y los cambios dinámicos en los proyectos de desarrollo de software.</div><h3 style="text-align: left;"> 11 ) DESARROLLO - PROGRAMACION</h3> <h4>Herramientas:</h4> Patterns <h4>Dificultad:</h4> BAJA <h4>Observaciones:</h4> Los patterns han mejorado bastante y se han podido generar mas cosas con los GeneXus Patterns. Quedan otras oportunidades de generar automáticamente API, test, etc
<h3 style="text-align: left;"> 12 ) DESARROLLO - DOCUMENTACION</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> BAJA <h4>Observaciones:</h4> Con las herramientas de LLM se facilita la generación de documentación. Tal vez se pueda automatizar aún más, leyendo la KB y generando esquemas de los diferentes documentos que se necesitan. Documentos Técnicos para Desarrolladores, Modelo de Datos, Manuales de Usuario, etc.
<h3 style="text-align: left;"> 13 ) DESARROLLO - BUILD e INTEGRACION</h3> <h4>Herramientas:</h4> Jenkins / aún da mucho trabajo automatizar <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> Hemos logrado un progreso significativo en la automatización de la generación de infraestructura para la Integración y Entrega Continuas (CI/CD). Sin embargo, aún hay mucho por hacer en cuanto a la automatización de la personalización de ambientes y la promoción de un ambiente a otro en el ciclo de aceptación. Es crucial formalizar más las tareas de "Build All" (que ya está automatizada), "Package All" (que está semi-automatizada) y "Deploy All" (que aún no está automatizada). Además, una vez que una aplicación está desplegada, se necesitan mecanismos que permitan habilitar su uso en un momento distinto al del despliegue. Este es un área crítica que requiere atención y desarrollo adicionales para mejorar la eficiencia y eficacia del proceso de CI/CD.
<h3 style="text-align: left;"> 14 ) DESARROLLO - TRAZABILIDAD REQUERIMIENTOS / OBJETOS</h3> <h4>Herramientas:</h4> Issue Tracking <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4>En el área de integración entre sistemas de seguimiento de incidencias y GeneXus o GeneXus Server, se ha progresado muy poco, aunque existen algunos intentos de conexión entre ambos. Resulta esencial desarrollar una funcionalidad que permita identificar qué ticket o requerimiento específico ha originado los cambios. Esto facilitaría un seguimiento más efectivo y una mejor gestión de las modificaciones en los proyectos.<br /><h3 style="text-align: left;"> 15 ) DESARROLLO - MANEJO DE SEGURIDAD</h3> <h4>Herramientas:</h4> Security Scanner <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4>La seguridad en las aplicaciones se ha vuelto cada vez más crítica y, al mismo tiempo, más compleja de gestionar. Esta situación se ve agravada por el creciente tamaño y número de aplicaciones en uso. Herramientas como el Security Scanner son eficaces para detectar ciertos problemas de seguridad. Por otro lado, GAM aborda eficientemente los desafíos relacionados con la autenticación y autorización. No obstante, aún queda un camino considerable por recorrer en la automatización de estos procesos de seguridad, lo que es fundamental para manejar de manera eficiente la creciente complejidad y escala de las aplicaciones modernas.<br /><h3 style="text-align: left;"> 16 ) DESARROLLO - PACK DE LA SOLUCION</h3> <h4>Herramientas:</h4> Se puede automatizar aun da mucho trabajo <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4><div>Seria necesario poder tener mas control de lo que las Deployment Units llevan a cada instalación. <br />Por limitación de como son las referencias en Genexus, en varias oportunidades se lleva de mas o de menos al generar el zip/war de una Deployment Unit. <br />Se necesitaría también tener un "Package All" (equivalente al "Build all") para poder recorrer todas las Deployment Units y empaquete los diferentes componentes a instalar. </div>
<h3 style="text-align: left;"> 17 ) PRUEBAS/TEST - CHEQUEOS UNITARIO / REGRESION</h3> <h4>Herramientas:</h4> GXTest - Esta mejorando mucho. Falta trabajar en generacion de datos para pruebas <h4>Dificultad:</h4> BAJA <h4>Observaciones:</h4> Se adelanto muchisimo en la generacion de pruebas unitarias mas automáticas. Se pueden establecer datos a usar en los test y generar test automaticos basicos de los objetos, chequeando contra los resultados esperados.
<h3 style="text-align: left;"> 18 ) PRUEBAS/TEST - CHEQUEO PERFORMANCE / CARGA</h3> <h4>Herramientas:</h4> Se puede automatizar, da mucho trabajo aun <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> No es un tema que domine, pero supongo que con inteligencia artificial podremos generar estos artefactos para probar la carga de nuestro sistema de forma mucho mas fácil que hoy.
<h3 style="text-align: left;"> 19 ) PRUEBAS/TEST - TESTING</h3> <h4>Herramientas:</h4><div>GXTest</div> <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4> El testeo de la aplicación, sigue siendo una tarea manual y creo que va a seguir siendo lo mismo. Comprobar que los requerimientos nuevos se cumplen, va a tener que ser realizado por humanos en el futuro proximo.
<h3 style="text-align: left;"> 20 ) PRUEBAS/TEST - ANALISIS DE IMPACTO DE LA API DE LA KB</h3> <h4>Herramientas:</h4> Se puede automatizar pero da mucho trabajo <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> Se avanzo bastante en el diseño y manejo de API. Hay herramientas automatizadas de monitoreo, que detectan diferencias. Seria bueno tener alguna integrada y poder generarle automaticamente las pruebas.
<h3 style="text-align: left;"> 21 ) PRUEBAS/TEST - COMPARACION DE NAVEGACIONES</h3> <h4>Herramientas:</h4> Comparador de Navegaciones (esta desactualizado)<h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4>En lo que respecta a esta herramienta, no solo no hemos visto avances, sino que también se ha observado un estancamiento en su desarrollo. Sin embargo, este problema es menos significativo en las versiones más recientes de GeneXus, ya que los cambios drásticos que solían ser comunes en versiones anteriores ya no ocurren con tanta frecuencia. A pesar de esto, sigue siendo un aspecto que requiere atención y trabajo.<br /><br /><br />Con los avances tecnológicos actuales, sería factible desarrollar un asistente inteligente que analice la base de conocimientos (KB) en GeneXus. Este asistente podría ayudarnos a identificar posibles problemas de compatibilidad que podrían surgir al instalar nuevas versiones de GeneXus. Este análisis podría basarse en un estudio detallado de las notas de lanzamiento (Release Notes) de estas nuevas versiones, proporcionando así una valiosa orientación para la transición y actualización.</div><div><h3 style="text-align: left;">22 ) LIBERACION/INSTALACION - MANEJO DE VERSIONES</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4><div>Deberíamos poder modelar esta realidad en aplicaciones GeneXus, donde le podamos decir cuales son los diferentes ambientes donde la aplicación va a ejecutar y tener parametrizado las diferentes configuraciones. <br /> Luego de empaquetar una aplicación (en zip, war/ear, apk, imagen docker, etc), se debe poder personalizar la configuración de la aplicación para el ambiente. Esto incluye strings de conexión a bases de datos, variables de entorno, configuraciones de seguridad, location desde donde debe consumir servicios, entre otros.</div>Asegurarse de que todos los servicios y recursos externos a los que la aplicación necesita conectarse estén accesibles y correctamente configurados.<h3 style="text-align: left;"> 23 ) LIBERACION/INSTALACION - DEPLOY</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4><div>Esta muy relacionado con el paso anterior. </div><div><br /></div>
<h3 style="text-align: left;"> 24 ) LIBERACION/INSTALACION - REORGANIZACION DE BASE DE DATOS</h3> <h4>Herramientas:</h4> Proceso semi automatizado <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> Sigue igual, un proceso semi automatizado.</div><br />Para bases de datos de gran tamaño, sería extremadamente útil disponer de un analizador de reorganizaciones. Este analizador debería ser capaz de dividir una reorganización en dos partes distintas:<br /><br /><b>Script BackCompatible:</b> Este script se ejecutaría <b>ANTES </b>de instalar la nueva versión de la base de datos y sería compatible con la versión actual. La ejecución de este script podría realizarse días antes de la actualización para minimizar el tiempo de inactividad de la base de datos. Este script incluiría tareas como la creación de nuevos índices, la adición de atributos nulables o con valores por defecto, y la creación de nuevas tablas.<br /><br /><b>Script de Ejecución Durante la Instalación:</b> Este script incluiría cambios que no son compatibles hacia atrás y que, por lo tanto, deben realizarse durante la instalación de la nueva versión. Esto podría abarcar la modificación de tipos de datos o longitudes de campos, la eliminación de objetos obsoletos, el renombramiento de objetos, entre otros cambios críticos.<br /><br />El objetivo de este enfoque es facilitar una transición suave y eficiente durante las actualizaciones de bases de datos, minimizando los riesgos y el impacto en la disponibilidad del sistema.<div><br /></div><div>El manejo de modulos, podrían manejar diferentes schemas para cada modulo y poder reorganizar con diferentes schemas. <br /> <div><h3>25 ) LIBERACION/INSTALACION - MANEJO DE METADATA (GAM, WORKFLOW, SISTEMA)</h3> <h4>Herramientas:</h4><div>Las herramientas que hay son difíciles de automatizar. </div> <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4>La gestión del impacto de la metadata en las aplicaciones modernas aún no está adecuadamente resuelta, a pesar de ser un aspecto crítico para el funcionamiento óptimo de los sistemas. Es esencial poder transferir la metadata, como la de GAM, Workflow y Reportes con Layout Dinámico, de un ambiente a otro de manera eficiente. Además, se vuelve imperativo poder versionar estos cambios y realizar un seguimiento detallado de los mismos. Igualmente importante es la capacidad de evaluar el impacto que dichos cambios pueden tener en el sistema.<br /><br /><br />En el contexto actual de desarrollo de software, la metadata ha adquirido una importancia considerable. Actúa como el esqueleto de información que define cómo los datos son procesados, almacenados y utilizados dentro de una aplicación. La metadata no solo mejora la comprensión y la gestión de los datos, sino que también facilita la interoperabilidad entre diferentes sistemas y módulos. En sistemas complejos, una gestión eficaz de la metadata puede significar la diferencia entre un ecosistema de software ágil y adaptable y uno que es rígido y propenso a errores. Por lo tanto, desarrollar estrategias robustas para la gestión de metadata, incluyendo su versionado, seguimiento y evaluación de impacto, es fundamental para mantener la integridad, la eficiencia y la escalabilidad de las aplicaciones modernas.<h3 style="text-align: left;"> 26 ) MANTENIMIENTO/MONITOREO - ANALISIS DE ERRORES / PROCESO DE LOGS</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4>En el ámbito del análisis de errores, la inteligencia artificial (IA) puede simplificar considerablemente el proceso, facilitando la detección de los objetos específicos que requieren cambios para prevenir la recurrencia de errores. Con el uso de IA, al identificar un error y analizar el call stack correspondiente, se puede rastrear eficazmente hasta la fuente del problema. Esto incluye no solo el objeto donde se originó el error, sino también aquellos objetos que contribuyen a su aparición. De esta manera, la IA puede proporcionar recomendaciones claras y detalladas para soluciones efectivas, las cuales serían comprensibles y aplicables por parte de los desarrolladores de GeneXus. Este enfoque no solo mejora la eficiencia en la resolución de problemas, sino que también ayuda a identificar y abordar las causas fundamentales, mejorando así la calidad y estabilidad del software desarrollado.<br /><h3 style="text-align: left;"> 27 ) MANTENIMIENTO/MONITOREO - PERFORMANCE-ANALISIS</h3> <h4>Herramientas:</h4> Registro de incidentes / Herramienta de monitoreo <h4>Dificultad:</h4> BAJA <h4>Observaciones:</h4> Se ha logrado un progreso significativo en la observabilidad de las aplicaciones, lo que facilita la detección temprana de demoras y problemas. Esta mejora es particularmente valiosa en aplicaciones de gran escala, donde se hace imprescindible automatizar el proceso de monitoreo. La automatización permite identificar y resolver problemas de rendimiento antes de que los usuarios los perciban y reporten, mejorando así la experiencia del usuario y la eficiencia operativa del sistema.
<h3 style="text-align: left;"> 28 ) MANTENIMIENTO/MONITOREO - HELP DESK</h3> <h4>Herramientas:</h4> Registro de incidentes <h4>Dificultad:</h4> MEDIA <h4>Observaciones:</h4> En la mesa de ayuda deberia ser mas facil el registro de incidentes y se puede tener un bot que solucione los casos repetitivos o que ya han sucedido
<h3 style="text-align: left;"> 29 ) TAREAS DE APOYO - INSTALACION DE GENEXUS</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4> No tenemos nada automatizado, ni automatizable en la instalación de GeneXus. Se mejoro con la instalacion de modulos, pero aun no es posible hacer una instalación y replicarla en un grupo de desarrollo de forma fácil. La instalación de una extensión nueva (o una versión de un pattern) implica un trabajo a realizar en varias maquinas que no ha podido ser automatizado.
<h3 style="text-align: left;"> 30 ) TAREAS DE APOYO - AMBIENTE DE DESARROLLO / tomcat/ iis/ etc</h3> <h4>Herramientas:</h4><div>No existe</div> <h4>Dificultad:</h4> ALTA <h4>Observaciones:</h4> La automatización de la instalación de los pre-requisitos para el ambiente de desarrollo es factible, aunque implica un esfuerzo considerable. Sería muy beneficioso contar con un conjunto de plantillas de instalación básica, las cuales podrían descargarse para simplificar y agilizar este proceso. Estas plantillas facilitarían significativamente la configuración inicial, reduciendo la carga de trabajo y mejorando la eficiencia en la preparación de entornos de desarrollo.
<h3 style="text-align: left;"> 31 ) TAREAS DE APOYO - INSTALACION MANTENIMIENTO GXSERVER</h3> <h4>Herramientas:</h4> <h4>Dificultad: <span style="font-weight: normal;">ALTA</span></h4><h4>Observaciones:</h4> Lo mismo que para GeneXus, no ha avanzado demasiado. Tal vez se soluciones con las proximas versiones.
<h3 style="text-align: left;"> 32 ) TAREAS DE APOYO - CAPACITACION</h3> <h4>Herramientas:</h4> <h4>Dificultad: <span style="font-weight: normal;">ALTA</span></h4><h4>Observaciones:</h4> La generacion de manuales, videos de como usar la aplicacion, es una tarea que lleva mucho tiempo. Si bien hay algunas herramientas que ayudan en el proceso aun son tareas poco automatizadas. </div></div><div>Además le vamos a agregar asistentes a las aplicaciones, que la van a hacer mas fáciles de usar, por lo que los usuarios van a necesitar menos capacitacion para usar los sistemas. <br /><br />* La imagen fue generada con Bing<br />* El texto fue corregido y mejorado con ChatGPT. </div><div><br /></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-7702563266072569782023-11-01T14:16:00.009-03:002023-11-03T13:29:08.125-03:00KBLogAnalyzer - Analizando logs de aplicaciones Genexus (.NET). <h2 style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjCeYyu_1-oL4U6hN0_Z2giSMB85mZLZubg4lSmOQz67ZHP43rKjAk6rD9O0oVJVbn70-Mjb6FDelloP4NxZljbB5OIwgbxVz_ejRSJYmVSIhtQXUKKAp8ukB8B83X3I6TNgRoafSSnXPNpDIFtsYZEY_NHaXU1pO0MZGDjhuOGqGQaOGuWQaSMcw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="691" data-original-width="1064" height="416" src="https://blogger.googleusercontent.com/img/a/AVvXsEjCeYyu_1-oL4U6hN0_Z2giSMB85mZLZubg4lSmOQz67ZHP43rKjAk6rD9O0oVJVbn70-Mjb6FDelloP4NxZljbB5OIwgbxVz_ejRSJYmVSIhtQXUKKAp8ukB8B83X3I6TNgRoafSSnXPNpDIFtsYZEY_NHaXU1pO0MZGDjhuOGqGQaOGuWQaSMcw=w640-h416" width="640" /></a></div><br /><br /></div><br />Problema:</h2><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Tengo un conjunto de archivos de log, generados con GeneXus, generalmente bastante grandes y tengo que procesarlos para encontrar lentitudes, errores o cosas a mejorar. </div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></div><div style="background-color: white; color: #222222; font-size: small;"><span face="Arial, Helvetica, sans-serif">Los registros son de la forma:</span><br /><br /><span style="font-family: courier;">2023-10-09 16:01:28,930 [31] DEBUG GeneXus.Data.ADO.<wbr></wbr>GxConnectionManager - GxConnectionManager.<wbr></wbr>DecOpenHandles handle '3799', datasource 'Default', openhandles 1<br />2023-10-09 16:01:28,991 [31] DEBUG GeneXus.Data.NTier.<wbr></wbr>DataStoreProvider - gxObject:GeneXus.Programs.<wbr></wbr>pxmlconceptos__default, handle '3799' cursorName:P00ME5<br />2023-10-09 16:01:28,991 [31] DEBUG GeneXus.Data.ADO.GxCommand - ExecuteReader: Parameters @ConId='53'</span></div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Hice un pequeño utilitario que facilita o acelera el procesamiento</div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Es un cmd llamado KBLogAnalyzer.cmd, que al correrlo pregunta el directorio de logs, el directorio de salida (procesa todos los archivos que estén en ese directorio) y que tipo de procesos se quiere realizar</div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></div><div><div class="separator" style="background-color: white; clear: both; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgTSPk9CppfpTf-qHemuKW515g105fWeoFLRQCZcDktdWmWie5xXBxuaXXa7jjZwuXLL0sGuURIGF7-43R0i2US7LC4cFX933OEpxAdyAlmFx7oEAOXOPNwPnAF4KgqSQHAkNDDRGeshjDBoia_3fKgvK12BAUiRRFj2ULvj1a1dMGnqy3cQ50f_g" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="318" data-original-width="825" src="https://blogger.googleusercontent.com/img/a/AVvXsEgTSPk9CppfpTf-qHemuKW515g105fWeoFLRQCZcDktdWmWie5xXBxuaXXa7jjZwuXLL0sGuURIGF7-43R0i2US7LC4cFX933OEpxAdyAlmFx7oEAOXOPNwPnAF4KgqSQHAkNDDRGeshjDBoia_3fKgvK12BAUiRRFj2ULvj1a1dMGnqy3cQ50f_g=s16000" /></a></div><br />Con eso, procesa los archivos de log, y permite generar los archivos:<br /><ul style="text-align: left;"><li><b>totalByPrograms.txt </b>Ranking de cantidad de veces que ejecuto un programa</li><li><b>totalByStmt.txt</b> Ranking de cantidad de veces que ejecuto una sentencia SQL</li><li><b>detectDelays.txt</b> Entrdas de log, que demoraron mas que un umbral (threshold) dado </li><li><b>unknounLogType.txt</b> Entradas de log, que no tiene un tipo de log conocido</li><li><b>ErrorWarning.txt</b> Entrdas de log, que son ERROR/FATAL/WARN </li></ul><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><span style="font-family: monospace;"><br /></span></div><h2 style="text-align: left;">Ejemplos de salida</h2><h3 style="text-align: left;">Total por programa</h3><div><div style="background-color: white;"><span style="color: #222222; font-family: courier; font-size: x-small;">Cantidad_de_Veces;Programa</span></div><div style="background-color: white;"><span style="color: #222222; font-family: courier; font-size: x-small;">979831;chequeoSeguridad</span></div><div style="background-color: white;"><span style="color: #222222; font-family: courier; font-size: x-small;">281911;liquidacion</span></div><div style="background-color: white;"><span style="color: #222222; font-family: courier; font-size: x-small;">59245;usuariovalido</span></div><div style="background-color: white;"><span style="color: #222222; font-family: courier; font-size: x-small;">39352;liquidaciondetalle</span></div><div style="background-color: white;"><span style="color: #222222; font-family: courier; font-size: x-small;">39011;graboliquidacion</span></div><div><span style="background-color: white; color: #222222; font-size: x-small;"><span style="font-family: courier;">......<br /></span><br /></span><h3 style="text-align: left;">Total por Sentencia</h3><span style="background-color: white; color: #222222; font-size: x-small;"><div><div><span style="font-family: courier;">Cantidad_de_Veces;Sentencia</span></div><div><span style="font-family: courier;">551842;SELECT [AumFecha], [AumId], [AumPor] FROM [Tabla1] WITH (NOLOCK) WHERE ([AumId] = @AV23AumId1 and [AumFecha] > @HPLFecha) AND ([AumFecha] <= @AV8PLFecha) ORDER BY [AumId]</span></div><div><span style="font-family: courier;">426781;SELECT [ConId], [AcuTipo], [AcuId], [ConAcuOpe], [ConAcuMult] FROM [Tabla2] WITH (NOLOCK) WHERE [ConId] = @AV32ConId and [AcuTipo] = 'H' ORDER BY [ConId]</span></div><div><span style="font-family: courier;">78658;INSERT INTO [Tabla3]([FunId], [HCorLiq], [HCorLin], [DCTipo], [DCLin], [DCOpe], [DCApar], [DCUsar], [DCNro], [DCAnio], [BasId], [DCCargo], [DCCCosto], [DCMult], [DCDiv], [DCCPar], [DCImpLinea], [DCImpParci], [DCObservac], [DCAporId], [DCConId], [DCRefAux], [DCIniAguin], [DCFinAguin], [DCMovFunAL]) VALUES(@FunId, @HCorLiq, @HCorLin, @DCTipo, @DCLin, @DCOpe, @DCApar, @DCUsar, @DCNro, @DCAnio, @BasId, @DCCargo, @DCCCosto, @DCMult, @DCDiv, @DCCPar, @DCImpLinea, @DCImpParci, @DCObservac, @DCAporId, @DCConId, @DCRefAux, @DCIniAguin, @DCFinAguin, @DCMovFunAL)</span></div><div><span style="font-family: courier;">.....</span></div></div><div style="font-family: Arial, Helvetica, sans-serif;"><br /></div></span></div></div><h3 style="text-align: left;">Sentencias lentas</h3><div style="background-color: white; color: #222222; font-size: small;"><div><span style="font-family: courier;">Diferencia de tiempo: 2341 ms (Anterior: 10/09/2023 15:10:44, Actual: 10/09/2023 15:10:46)</span></div><div><span style="font-family: courier;">2023-10-09 15:10:44,162 [15] DEBUG GeneXus.Data.GxConnectionCache - GetPreparedCommand cached stmt:SELECT [LId], [LFunId], [LCobId], [LFunFicto], [LFunRecibo], [LMovTipo], [LConId], [LConTipo], [LPorR], [LCant], [LUnit], [LImp], [LImpRechaz], [LUnitME], [LImpME], [LMovCCId], [LMovCarId], [LAL], [LMovFechaR], [LMovDescRe], [LMovDetall], [LMovFchMov], [LFunId2], [LClas], [LMovRefAux], [LMovFch], [LMovFchHas] FROM [Liquidac] WITH (UPDLOCK) WHERE [LId] = @AV8LId ORDER BY [LId] ## <b>2341 ms</b></span></div></div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><span style="font-family: monospace;">...</span></div><h3 style="text-align: left;">Errores y Warnings</h3><div><div style="background-color: white; color: #222222; font-size: small;"><span style="font-family: courier;">2023-10-09 16:01:28,993 [31] <b>ERROR </b>GeneXus.Data.NTier.ADO.GXFatFieldGetter - getShort - index : 1 value: 53</span></div><span style="font-family: courier;"><div style="background-color: white; color: #222222; font-size: small;">2023-10-09 16:01:28,993 [31] <b>WARN </b>GeneXus.Data.NTier.ADO.GXFatFieldGetter - getString - index : 2 value: H</div><div style="background-color: white; color: #222222; font-size: small;">....</div></span></div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><span style="font-family: monospace;"><br /></span></div>Hace más fácil encontrar los errores y luego se puede analizar más específicamente en el archivo correspondiente y ver su entorno. <br /><h3>Tipo de log desconocido</h3>Los logs tiene muchas entradas que no tienen fecha y hora y pueden distorsionar los análisis. Generalmente son entradas grabada por el usuario o entradas de log multi-linea. </div><div><br />En este archivo se guardan las entradas del tipo:<br /><div><span style="font-family: courier;">GX_CLIENT_ID:b09938b1-f073-42b6-b308-39a108cf332e</span></div><div><span style="font-family: courier;">GX_SESSION_ID:fTNK4e%2brudk56iNv7YqsrUlZURMihC8pkNyfovvtuOk%3d</span></div><h3 style="text-align: left;">Conclusión</h3><div>Está <a href="https://marketplace.genexus.com/product.aspx?kbloganalyzer,en">publicado en el Marketplace.</a></div><div>Si alguien lo prueba y tiene algún feedback, es bienvenido. <br /><br />PD: No conozco una forma fácil de extraer el programa y las sentencias, que funcione bien el 100% de los casos. Por ahora, funciona con los ejemplos que lo he probado, pero estoy seguro que hay casos que no va a funcionar bien. Los fuentes estan disponibles, por lo que es facil de adaptar si se programa algo de Powershell. </div></div><div><br /><div style="background-color: white; color: #222222; font-size: small;"><span style="font-family: monospace;"><br /></span></div><div style="background-color: white; color: #222222; font-size: small;"><span style="font-family: monospace;"><br /></span></div><div style="background-color: white; color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><span style="font-family: monospace;"><br /></span></div></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-56012637414846794672023-10-30T09:00:00.002-03:002023-10-30T09:00:36.706-03:00Código mas facil de entender - Booleanos positivos<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgnJ8r6Ib3gE19NYGnGMzstApKtwqjv0iBLktm_g3cxN0_TFgniDM3LTrrmA3B2qAnrClfjw_nvihba0xjJiaxV_lGr0kvITqX3QWHnDw_KJS1Ukc1j-uNcPfSbsal-biDGzFxI9Eyv-IhzBZ-m3bu8CU0YmxvXs-zvdfqeCUbz0Uli_TA4bdqtqw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="305" data-original-width="434" height="225" src="https://blogger.googleusercontent.com/img/a/AVvXsEgnJ8r6Ib3gE19NYGnGMzstApKtwqjv0iBLktm_g3cxN0_TFgniDM3LTrrmA3B2qAnrClfjw_nvihba0xjJiaxV_lGr0kvITqX3QWHnDw_KJS1Ukc1j-uNcPfSbsal-biDGzFxI9Eyv-IhzBZ-m3bu8CU0YmxvXs-zvdfqeCUbz0Uli_TA4bdqtqw" width="320" /></a></div><br />Siempre que sea posible, queda mas claro el código para entenderlo mas rapido, cuando se cheque que un booleano sea verdadero (TRUE) en vez de chequear por falso (FALSE). <p></p><p>Por ejemplo, si tenemos</p><p><br /></p><p><span style="font-family: courier;">// &Not_Authorized es booleano que indica que el usuario no esta autorizado. </span></p><span style="font-family: courier;">if <b>NOT &Not_Authorized</b><br /> </span><span style="font-family: courier;"> Operacion()</span><span style="font-family: courier;"><br />else<br /> Msg('Usuario no autorizado')<br />endif</span><p>es bastante mas difícil de leer que </p><br /><span style="font-family: courier;">//&User_Authorized es un boolean que indica si usuario esta autorizado<br /><br />if <b>&User_Authorized</b><br /> Operación()<br />else<br /> Msg('Usuario no autorizado')<br />endif</span><p>Tenemos que recordar que el codigo deberia ser lo mas simple posible de entender como cualquier texto en ingles o pseudocódigo y por lo tanto tener en cuenta el nombre y la semántica de las variables booleanas, es algo importante que ayuda entender más fácil. Este es algo muy sencillo de hacer en el momento que defino la variable booleana, y simplifica su uso posterior. <br /><br />Son los pequeños detalles que se sumados hacen la diferencia entre sistemas fáciles de mantener y los que son difíciles hacerles cambios. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-73087928878340700952023-10-09T20:40:00.001-03:002023-10-09T20:40:57.232-03:00Corregir Errores de Compresión en Archivos JavaScript en Genexus<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjyQAulghUQLUrzzpHYzyHiE_X9O5ZVSfVR2f22yFH4ILj_Oxis3PcCC8nWQG8JzWY5lPKno0cPo2LE_0Yo-un3P4TlG4RIUdix7kKIJK6Sojw_qcQNAAiwESUZChS5N_bG6PeBpbmNtoQ9AoFCpf-7EB2ib67v4V40i5TjyrxRxl_E0R0eNU_s0Q" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="224" data-original-width="662" src="https://blogger.googleusercontent.com/img/a/AVvXsEjyQAulghUQLUrzzpHYzyHiE_X9O5ZVSfVR2f22yFH4ILj_Oxis3PcCC8nWQG8JzWY5lPKno0cPo2LE_0Yo-un3P4TlG4RIUdix7kKIJK6Sojw_qcQNAAiwESUZChS5N_bG6PeBpbmNtoQ9AoFCpf-7EB2ib67v4V40i5TjyrxRxl_E0R0eNU_s0Q=s16000" /></a></div><br /><p></p><p>En algunas ocasiones pasa (generalmente en cambios de versión de GeneXus) que da un error al comprimir los archivos javascript. </p><p>Si bien el mensaje es claro, es un warning y el proceso de build all termina con éxito. Por este motivo, a veces no se detecta el problema hasta que llega a producción y es mucho mas caro de corregir. <br /><br />Por eso, recomiendo mucho sobre todo en las primeras especificaciones/generaciones/compilaciones de una KB en una nueva instalación, prestar especial atención a la compresión de los archivos javascript. </p><h3 style="text-align: left;">Un caso real</h3><p>Por ejemplo, el caso de la imagen, había un webpanel programado sin pattern que utilizaba un User Control que se instalaba con un Pattern. </p><p>Al cambiar la versión del Pattern, se actualizo el UC, cambiando de nombre y todos los objetos generados con el mismo pasaron a utilizar la nueva versión del UC, pero éste webpanel siguió usando el UC viejo, que ya no estaba instalado. </p><p>Al especificarlo, no daba ningún warning y compilaba sin errores. Solo aparecia el warning al comprimir el javascritp. </p><span style="font-family: courier;">Compressing static files...<br />js\hwenviosdnacontingencia.js(121): Expected identifier: (<br />js\hwenviosdnacontingencia.js(121): Expected ';'<br />js\hwenviosdnacontingencia.js(121): Expected expression: )<br />warning: Some files could not be compressed.</span><h3 style="text-align: left;">Como identificar y resolver el problema</h3><p>La forma de identificar el problema es mirar el output y revisar si todos los archivos pueden comprimirse sin errores. <br />Los que no puedan ser comprimidos, conviene mirar el archivo javascript y buscar la linea con problemas, en el ejemplo de arriba es la 121. Generalmente con eso es suficiente para detectar el objeto y la causa del problema. </p><p>En este caso, cambie el UC viejo por el nuevo en forma manual y con eso evite el problema. </p><h3>Conclusión:</h3><p>Dedicarle unos minutos a revisar el output, puede ahorrar varios dolores de cabeza en produccion. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-67876867914013547142023-09-28T10:11:00.000-03:002023-09-28T10:11:41.467-03:00Configurar IIS para ejecutar aplicaciones .NET Core<p>Tenía una aplicación GeneXus funcionando correctamente con el server Kestrel. <br />Cuando cambié la propiedad para ejecutar con el IIS (Internet Information Server) me empezó a dar el error</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjt6t1h74LTQwjIU1ayDY-1dtx-OEK0-vOnWEVz8lHiOW8d2k3fCvQYNTyWcaG5AAOF_RcMSUotFlzMmTkvNGSeCTiBNgHdJTTtAlgyR4cVIZ3NaHy1U1Ffb-Dqry_M2rlnbfxjRKSXiJYNuniNTJPPFFqDshahxXXKT572ALfSRgsAbGVtl6ubPA" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="592" data-original-width="1299" height="292" src="https://blogger.googleusercontent.com/img/a/AVvXsEjt6t1h74LTQwjIU1ayDY-1dtx-OEK0-vOnWEVz8lHiOW8d2k3fCvQYNTyWcaG5AAOF_RcMSUotFlzMmTkvNGSeCTiBNgHdJTTtAlgyR4cVIZ3NaHy1U1Ffb-Dqry_M2rlnbfxjRKSXiJYNuniNTJPPFFqDshahxXXKT572ALfSRgsAbGVtl6ubPA=w640-h292" width="640" /></a></div><br /><span style="background-color: white; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px;">Server Error in Application "application name"</span><br style="background-color: white; box-sizing: inherit; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px; outline-color: inherit;" /><span style="background-color: white; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px;">HTTP Error 500.19 – Internal Server Error</span><br style="background-color: white; box-sizing: inherit; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px; outline-color: inherit;" /><span style="background-color: white; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px;">HRESULT: 0x8007000d</span><br style="background-color: white; box-sizing: inherit; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px; outline-color: inherit;" /><span style="background-color: white; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px;">Description of HRESULT</span><br style="background-color: white; box-sizing: inherit; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px; outline-color: inherit;" /><span style="background-color: white; color: #161616; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px;">The requested page cannot be accessed because the related configuration data for the page is invalid.</span><p></p>Este error me habia pasado antes en aplicaciones .NET Framework (con el generador viejo) y siempre eran por temas de web.config mal formados o por problemas en la configuración del IIS (por ejemplo, quedaba mal el ApplicationHost.config ). <br /><br />En este caso, no parecía ser este el problema y necesité ayuda para encontrarlo. No deja pistas en el Event Viewer ni en los logs mas típicos. <p>Busque por el lado de los componentes de Windows del IIS y no encontré nada. <br /><br />Me faltaba instalar <a href="https://dotnet.microsoft.com/download/dotnet/thank-you/runtime-aspnetcore-web-installer">ASP.NET Core Hosting Bundle</a> que se baja y se instala en forma independiente del IIS. Luego de instalarlo y rebootear el equipo, todo funcionó bien y pude ejecutar la aplicación sin problemas. </p>Todo esto está muy explicado en <a href="https://wiki.genexus.com/commwiki/servlet/wiki?38605,.NET+Generator+Requirements">.NET Generator Requirement</a> pero lo habia leido hace un tiempo, cuando usaba Kestrel no lo necesitaba y no lo recordaba. Lo pongo aca con el código del error, por si alguien mas le pasa. <div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-24118329350717246192023-09-22T16:23:00.002-03:002023-09-22T19:17:10.054-03:00Kestrel y https<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgsppX-Fsr2q8nTp5ooRuBDi2Nb7DrK_PXQ4ixrJT6y0Srezr6aPB4PyPdEcFUvdfwqS9TRSs2AEt_RuZZwYHwcL8FYKwaD3GqRs7xal4DchZgfrVZQ_8dbZPWa2_lOF-ZcL7gy3RE6L0vdrY9HYPPYZgkraBOns60G1dWxx1Smq5SC7O6coKnf2Q" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="900" data-original-width="1200" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEgsppX-Fsr2q8nTp5ooRuBDi2Nb7DrK_PXQ4ixrJT6y0Srezr6aPB4PyPdEcFUvdfwqS9TRSs2AEt_RuZZwYHwcL8FYKwaD3GqRs7xal4DchZgfrVZQ_8dbZPWa2_lOF-ZcL7gy3RE6L0vdrY9HYPPYZgkraBOns60G1dWxx1Smq5SC7O6coKnf2Q" width="320" /></a></div>Cuando se desarrolla con GeneXus y .NET, el server por default es Kestrel. <br />Es practico de usar, porque consume poco, y es fácil de configurar. <p></p><p>En caso de necesitar utilizar https en el ambiente de desarrollo (cosa que todos deberíamos usar) la forma mas facil de configurarlo que encontré fue</p><p>Generar un certificado autofirmado para el ambiente de desarrollo. <br /><br /><span style="font-family: courier;">dotnet dev-certs https -ep <span style="color: red;">rutaAlCertificado\aspnetapp.pfx</span> -p <span style="color: red;">tuContraseñaAqui </span><br />dotnet dev-certs https --trust<br /></span><br />Luego instalarlo en el repositorio de windows<br /><br /><span style="font-family: courier;">certutil -p <span style="color: red;">tuContraseñaAqui</span> -importpfx <span style="color: red;">rutaAlCertificado\aspnetapp.pfx</span></span></p>para ver con que nombre quedó<div><br /></div><div><span style="font-family: courier;">certutil -store My</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">Luego crear el archivo '</span>appsettings.Development.json'<div><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: inherit; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.9em;"><br /></code></div><div><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: inherit; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.9em;">y ponerle el contenido (ver el nombre del certificado autofirmado, en mi caso es locahost.</code></div><br /><br /><div>{</div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Kestrel": {</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Certificates": {</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Default": {</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Subject": "<span style="color: red;">localhost</span>",</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Store": "My",</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Location": "LocalMachine",</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>"AllowInvalid": "true"</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>}</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>}</span></div><div><span style="white-space: normal;"><span style="white-space: pre;"> </span>}</span></div><div>}</div></div><div><br /></div><div>Seguramente existan formas mas faciles de hacerlo, pero esta me funciono bien. </div><div><br /></div><div>También se puede poner</div><div><br /></div><div><div>{</div><div> "Kestrel": {</div><div> "EndPoints": {</div><div> "Http": {</div><div> "Url": "http://localhost:8082"</div><div> },</div><div> "Https": {</div><div> "Url": "https://localhost:8083",</div><div> "Certificate": {</div><div> "Subject": "localhost",</div><div> "Store": "My", </div><div> "Location": "LocalMachine", </div><div> "AllowInvalid": true </div><div> }</div><div> }</div><div> }</div><div> }</div><div>}</div></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com1tag:blogger.com,1999:blog-5980598.post-71356837254143653902023-09-11T15:24:00.007-03:002023-09-11T15:52:28.971-03:00Haciendo una KB GeneXus mas mantenible: Mantener aislado el código externo.<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg_mP8PDLyLr3hF9J7IVN__oV6DS3J8gNj5UfTSiY7HB8qYr7VFyPODsKjREP0bDfRuLFnzjyQzLwx35SWukQiOZ0fKA0kYrCDAI_UDhtV2M1lWKxERjXU9oR86u8gc_UhxrgUynfMKTcQFwjwQuJrRLB4h3ETOYaYqKe3gAaaTiU-RlTi-BCZ4Sw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="219" data-original-width="584" height="120" src="https://blogger.googleusercontent.com/img/a/AVvXsEg_mP8PDLyLr3hF9J7IVN__oV6DS3J8gNj5UfTSiY7HB8qYr7VFyPODsKjREP0bDfRuLFnzjyQzLwx35SWukQiOZ0fKA0kYrCDAI_UDhtV2M1lWKxERjXU9oR86u8gc_UhxrgUynfMKTcQFwjwQuJrRLB4h3ETOYaYqKe3gAaaTiU-RlTi-BCZ4Sw" width="320" /></a></div><br />Con GeneXus se pueden hacer aplicaciones multiplatafoma de manera eficiente en diferentes lenguajes. <br />Sin embargo en algunas ocasiones especificas hay que recurrir a programar en codigo C# o Java.<div><br /></div><div>La que sigue, es una recomendación sencilla, que me hubiese gustado que alguien me la diera hace unos cuantos años, pues simplifica mucho el mantenimiento futuro. <br /><br /><span style="font-size: large;"><b><blockquote style="text-align: justify;">Para hacer que la KB GeneXus sea mantenible en el tiempo y fácil de migrar, es indispensable mantener dicho código en su mínima expresión y lo más aislado posible. </blockquote></b></span><div><br />En particular, existe la posibilidad de incluir código C# o Java dentro de los objetos Genexus, con los comandos<br /><br /><ul style="text-align: left;"><li>CSHARP</li><li>JAVA</li><li>SQL</li><li>EXEC</li></ul></div><div><br />Mi recomendación, para hacer facilitar la migraciones futuras, no tener estos comandos mezclados con el resto del código Genexus. En particular, conviene poner en procedimientos estos comandos, de forma que cuando cambie de sistema operativo (EXEC), de base de datos (SQL) o de lenguaje de programación (CSHARP, JAVA) tenga que revisar solo esos procedures y no complicarme con el resto de la aplicación.<div><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: var(--tw-prose-headings); font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem;"><span color="inherit" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box;">1. Mantenibilidad y Escalabilidad</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; margin: 0px 0px 1.25em;">Cuando trabajamos con aplicaciones de gran escala o que cambian con el tiempo, la mantenibilidad se convierte en una preocupación principal. Introducir código externo directamente en la lógica de negocio principal de una aplicación GeneXus puede complicar las actualizaciones y el mantenimiento. En cambio, al ubicar este código en procedimientos separados y específicos, podemos garantizar que cualquier cambio en el código externo no afectará de manera adversa otras partes de la aplicación.</p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: var(--tw-prose-headings); font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem;"><span color="inherit" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box;">2. Modularidad y Reusabilidad</span></h3>Agrupar el código externo en procedimientos aislados con una funcionalidad específica tiene el beneficio adicional de modularidad. Este enfoque permite que el código se reuse en otras partes de la aplicación o incluso en otros proyectos, evitando la repetición y garantizando una coherencia en su funcionamiento.</div><div><h3 style="text-align: left;">3. Debugging y Resolución de Problemas</h3>Cuando surgen problemas en una aplicación, es crucial poder identificar y resolver rápidamente la causa raíz. Mezclar código externo con la lógica nativa de GeneXus puede hacer que el proceso de depuración sea más complejo. En cambio, al tener código externo en procedimientos específicos, podemos identificar rápidamente si un problema está relacionado con el código GeneXus o con el código externo incorporado.<br />Es recomendable y facil tener Unit Test sobre estos procedimientos.</div><div><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: var(--tw-prose-headings); font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem;"><span color="inherit" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box;">4. Adaptabilidad a Cambios Tecnológicos</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; margin: 0px 0px 1.25em;">La tecnología evoluciona rápidamente, y las soluciones externas que se consideran óptimas hoy pueden no serlo mañana. Al encapsular el código externo en procedimientos aislados, podemos cambiar o reemplazar fácilmente estas soluciones sin tener que reescribir grandes porciones de nuestra aplicación.</p><h3 style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: var(--tw-prose-headings); font-size: 1.25em; line-height: 1.6; margin: 1rem 0px 0.5rem;"><span color="inherit" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box;">Conclusión</span></h3><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; margin: 0px;">Aunque GeneXus ofrece la flexibilidad de integrar código externo, es vital abordar esta integración con cautela y estrategia. Aislar este código en procedimientos con funcionalidades específicas no solo garantiza una estructura organizada y fácil de mantener sino que también asegura que nuestras aplicaciones sean robustas, escalables y preparadas para el futuro. Al seguir esta práctica, podemos aprovechar lo mejor de ambos mundos: la eficiencia de GeneXus y la funcionalidad especializada del código externo.</p><div class="flex justify-between lg:block" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; justify-content: space-between;"><div class="text-gray-400 flex self-end lg:self-center justify-center mt-2 gap-2 md:gap-3 lg:gap-1 lg:absolute lg:top-0 lg:translate-x-full lg:right-0 lg:mt-0 lg:pl-2 visible" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-text-opacity: 1; --tw-translate-x: 100%; --tw-translate-y: 0; align-self: center; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; color: rgba(172,172,190,var(--tw-text-opacity)); display: flex; gap: 0.25rem; justify-content: center; margin-top: 0px; padding-left: 0.5rem; position: absolute; right: 0px; top: 0px; transform: translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); visibility: visible;"><button class="flex ml-auto gap-2 rounded-md p-1 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; appearance: button; background-image: none; border-color: rgb(217, 217, 227); border-radius: 0.375rem; border-style: solid; border-width: 0px; cursor: pointer; display: flex; font-family: inherit; font-size: 16px; font-weight: inherit; gap: 0.5rem; line-height: inherit; margin: 0px 0px 0px auto; padding: 0.25rem;"><svg class="h-4 w-4" fill="none" height="1em" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect height="4" rx="1" ry="1" width="8" x="8" y="2"></rect></svg></button><div class="flex gap-1" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(217, 217, 227); box-sizing: border-box; display: flex; gap: 0.25rem;"><button class="p-1 rounded-md hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; appearance: button; background-image: none; border-color: rgb(217, 217, 227); border-radius: 0.375rem; border-style: solid; border-width: 0px; cursor: pointer; font-family: inherit; font-size: 16px; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0.25rem;"><svg class="h-4 w-4" fill="none" height="1em" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"></path></svg></button><button class="p-1 rounded-md hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; appearance: button; background-image: none; border-color: rgb(217, 217, 227); border-radius: 0.375rem; border-style: solid; border-width: 0px; cursor: pointer; font-family: inherit; font-size: 16px; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0.25rem;"><svg class="h-4 w-4" fill="none" height="1em" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" stroke="currentColor" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"></path></svg></button></div></div></div><button class="cursor-pointer absolute right-6 bottom-[124px] md:bottom-[180px] lg:bottom-[120px] z-10 rounded-full border border-gray-200 bg-gray-50 text-gray-600 dark:border-white/10 dark:bg-white/10 dark:text-gray-200" style="--tw-bg-opacity: 1; --tw-border-opacity: 1; --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-text-opacity: 1; --tw-translate-x: 0; --tw-translate-y: 0; appearance: button; background-image: none; border-color: rgba(217,217,227,var(--tw-border-opacity)); border-radius: 9999px; border-style: solid; border-width: 1px; bottom: 120px; cursor: pointer; font-family: inherit; font-size: 14px; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; position: absolute; right: 1.5rem; z-index: 10;"><br /></button></div></div></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-4679388746132592592023-09-08T09:57:00.003-03:002023-09-08T11:04:14.032-03:00 Haciendo una KB Genexus más mantenible: Evita depender de objetos que cambien fuera de tu control<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg_ptQMx71qOYM8IDQXTgbQiTsNFZK-1QDOy2xTYxlXYJmd7WuzyvTvkPp36ECFI-_3R9KP8QlsJTLnMlP_Iiaqc4TOHC5mbaRzKn0ZeJcZ0vLMUu5shSUOJNe5l9quTFwL8EL-DN8s1znZu7E2BrCN4XVJT5zJI7yRCbUSTFeF6bb7CtZezRSvyA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="225" data-original-width="225" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEg_ptQMx71qOYM8IDQXTgbQiTsNFZK-1QDOy2xTYxlXYJmd7WuzyvTvkPp36ECFI-_3R9KP8QlsJTLnMlP_Iiaqc4TOHC5mbaRzKn0ZeJcZ0vLMUu5shSUOJNe5l9quTFwL8EL-DN8s1znZu7E2BrCN4XVJT5zJI7yRCbUSTFeF6bb7CtZezRSvyA" width="240" /></a></div><br />En el mundo digital, la velocidad con la que se actualizan y cambian las herramientas y tecnologías es asombrosa. Y mientras que estar al día con las últimas novedades puede ser emocionante, también puede representar un desafío significativo en cuanto a mantenimiento y compatibilidad. Si estás trabajando con Genexus y quieres construir una Knowledge Base (KB) robusta y fácil de mantener, te hago algunas recomendaciones. <p></p>GeneXus garantiza la actualización tecnológica; sin embargo, es esencial estar preparados para abordar estos cambios. A pesar de que he presenciado numerosas charlas sobre el tema, noto una falta de énfasis en cómo prepararnos adecuadamente para las transiciones entre versiones. Por ello, he decidido elaborar una serie de publicaciones que se centrarán precisamente en este aspecto crucial.<h3 style="text-align: left;">El problema con las herramientas de terceros</h3><p>Si bien las herramientas y recursos de terceros, pueden acelerarte muchisimo el desarrollo y la puesta en produccion, traen como consecuencia, que cuando cambian, afectan el funcionamiento de tu sistema. </p><p>Por ejemplo, si desarrollo con un Pattern, con un cambio de versión de Genexus o un cambio de versión del Pattern, nos va a llegar todas las ventajas de dicha actualización así también como los objetos cambiados. <br />Si dependemos de un Theme, Design System o Menús u otros objetos que vienen como ejemplo en dichas herramientas, es importante tener en cuenta que cuando el mismo cambie en la próxima versión voy a tener que lidiar con dicho cambio.<br /></p><p></p><h3 style="text-align: left;">Hacer copia de los objetos que uso. </h3>En lugar de depender directamente de los artefactos de terceros, es mejor hacer una copia (con un SAVE AS y no un Rename) de los objetos. Y ponerle un nombre que se distinga del original. <br /><br />Ejemplo de estos objetos:<br /><ul style="text-align: left;"><li>MasterPage que vienen con Genexus o con Patterns. </li><li>GAMExample* que vienen con GAM</li><li>Design System que vienen con los Patterns. </li><li>Ejemplos de objetos generados al instalar un User Controls</li></ul><h3 style="text-align: left;">Ventajas</h3><p></p><p>1. Mayor control Al tener una copia, controlas todas las versiones, lo que significa que no te verás afectado por cambios imprevistos en la herramienta original.</p><p>2. Adaptabilidad: Una vez que tengas tu versión del artefacto, puedes adaptarlo y personalizarlo exactamente de la manera que quieras, sin restricciones.</p><p>3. Mantenimiento a largo plazo: Asegurarte de que tu KB sigue siendo funcional y relevante a lo largo del tiempo es fundamental. Con tu propia versión de los artefactos, no tendrás que preocuparte de que una actualización de una herramienta de terceros rompa algo en tu base de conocimientos.</p><h3 style="text-align: left;">Recomendaciones</h3><p></p><ol style="text-align: left;"><li><b>Documenta:</b> Asegúrate de mantener un registro de todos los artefactos de terceros que estás usando. Documenta de dónde provienen, su versión actual y cualquier cambio que hayas realizado.<br /><br /></li><li><b>Lee las Release Notes</b>: Es vital estar al tanto de los cambios que se presentan en las nuevas versiones. Las notas de lanzamiento te ofrecen un resumen de las actualizaciones, correcciones y cambios realizados. Esto te ayudará a saber si algo podría afectar tu KB.<br /><br /></li><li><b>Comparación de objetos</b>: Después de revisar las Release Notes, compara el objeto que salvaste con el correspondiente de la nueva versión. Esta comparación te permitirá ver las diferencias y decidir qué cambios, si los hay, deberías implementar en tu copia. Esta etapa es muy importante, pues es indispensable comparar la version salvada de mi objeto, con la nueva version que viene con la nueva version. <br /><br />Ejemplo:<br />Hago un SAVE AS del objeto GAMExampleLogin y lo nombro como Login en mi KB. Cuando instalo una nueva versión de GAM (generalmente pasa con nuevas versiones de GeneXus), tengo que comparar el nuevo GAMExampleLogin con el objeto Login, para poder adaptarlo a los cambios que aparecieron. <br /><br /></li><li><b>Prueba antes de implementar</b>: Antes de implementar cualquier actualización o cambio en tu KB, pruébalo en un entorno de desarrollo o de prueba para asegurarte de que todo funciona como se espera.</li></ol><p></p><h3 style="text-align: left;">Conclusión: </h3><p>Al final del día, la mejor manera de garantizar una KB Genexus mantenible y robusta es tener control total sobre los recursos y herramientas que estás utilizando. Adoptando este enfoque proactivo, te aseguras de que tu base de conocimientos sea siempre funcional, relevante y eficaz en el futuro. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-47217204142907674132023-09-07T09:35:00.006-03:002023-09-08T10:17:27.182-03:00Tercera prueba de GeneXus Next<p>Seguí trabajando con el mismo prompt que use ayer para hacer la prueba y ahora si generó correctamente la aplicación. No se bien que cabión tras bambalinas, pero ahora me funcionó bien. <br /><br />Me resulta mágico, que solo poniendo una descripción de lo que quiero pueda deducir un modelo de datos, crear la base de datos, cargarle datos de prueba y hacer un deploy en la nube para que lo pueda probar. <br />Adicionalmente, me publica una API para todos las tablas de datos básicos y hechos del sistema. <br /><br />Es indudable que ahorra una cantidad impresionante de trabajo manual y repetitivo que hasta el momento no había podido ser automatizado. </p><p>Genere el modelo con WorkWithPlus y ya tiene además la posibilidad de consultar con lenguaje natural , por ejemplo, si ponemos en el filtro de arriba a la derecha: "Tickets with Status Name = In Progress"<br />me lleva a la pantalla de trabajar con Tickets, con el filtro de Status filtrando por In Progress. <br /><br />Le agrega una nueva forma de navegar al sistema, que va a posibilitar que mas usuarios puedan aprovechar las funcionalidades ya existentes. </p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhU3Uf3kGNqNDfhfcbVaEwEBLiZ4uKWm1x3LolffNYrkIbmru2diXf6pRvEpa_YgVo6W8f_8HNxeEBsmpy0KokLYhEGeSogzgOkcQCR2E9GawzkI5RBqXMbtRo3sXZmtUPebnJ_jZ23mS2fXlGidP-C8imAGELYuUzIie-ryOs5ukSqld62ZHLOfg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="531" data-original-width="901" src="https://blogger.googleusercontent.com/img/a/AVvXsEhU3Uf3kGNqNDfhfcbVaEwEBLiZ4uKWm1x3LolffNYrkIbmru2diXf6pRvEpa_YgVo6W8f_8HNxeEBsmpy0KokLYhEGeSogzgOkcQCR2E9GawzkI5RBqXMbtRo3sXZmtUPebnJ_jZ23mS2fXlGidP-C8imAGELYuUzIie-ryOs5ukSqld62ZHLOfg=s16000" /></a></div><br />Me parece muy buen avance. <p></p><p>Intento calcular cuantas horas puede llevar el hacer este mismo sistema, diseñando la base de datos, haciendo los script para cargarle datos, programando todos los mantenimientos y su API y veo un aumento de productividad difícil de cuantificar. Si además le agrego que el diseño quede tan lindo como tiene este, el aumento de productividad es mucho mayor, porque para llegar a tener pantallas tan bien diseñadas, a mi personalmente me llevaría muchísimas horas (y no creo que lo lograria). </p><p><br /></p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com2tag:blogger.com,1999:blog-5980598.post-84629040094458254332023-09-06T19:17:00.005-03:002023-09-08T10:17:11.579-03:00Segunda Prueba de GeneXus Next<p> Hice una segunda prueba de GeneXus Next y lamentablemente el resultado no fue muy satisfactorio. <span> </span><span> </span></p><p><span></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiUGZuZ7kzyJOGKg9mBrCHmnJqG0EiLO8RP9Z_1JZAR7cmcFR4t363vlf-O6pR6IV5Hr5EfeQYOg6TO09uAd2kElDR1T0m87Op4fP_HsooJCX4T8Ruyir7RwpU-e8LdoipcX6ZfHCUHYaN_yagchCPAazgOB8O2jbOc5vOo3B9oOIgtjT1ALEz3pg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="463" data-original-width="826" height="179" src="https://blogger.googleusercontent.com/img/a/AVvXsEiUGZuZ7kzyJOGKg9mBrCHmnJqG0EiLO8RP9Z_1JZAR7cmcFR4t363vlf-O6pR6IV5Hr5EfeQYOg6TO09uAd2kElDR1T0m87Op4fP_HsooJCX4T8Ruyir7RwpU-e8LdoipcX6ZfHCUHYaN_yagchCPAazgOB8O2jbOc5vOo3B9oOIgtjT1ALEz3pg" width="320" /></a></div><br /><br /><p></p><p><span>Probe con el prompt<br /><br /></span><span style="color: #999999; font-family: RubikRegular; font-size: 16px; white-space-collapse: break-spaces;">Necesito hacer un sistema para el seguimiento de tickets de desarrollo para aplicaciones, donde se puedan registrar errores, oportunidades de mejoras, sugerencias. Se necesita hacer seguimiento del estado de los tickets, saber quien lo tiene asignado, poder poner comentarios y notificar a los involucrados. Los clientes deben poder ingresar los tickets online y tambien consultarlos. Considerar al menos las siguientes entidades Clientes, Tickets, Sistemas, Personas, Estado de Tickets, Comentarios de Tickets
</span>No me parecia algo muy complejo, pero da un error y no me muestra cual es por lo que no puedo saber que es lo que esta pasando. </p>Me recomienda empezar desde el principio de nuevo, cosa que hice, pero no tuve mucha suerte. Lo reporte hace un tiempo a la gente de GeneXus, pero ya paso un buen tiempo y sigue sin resolverse. Tal vez sea una bobada, pero no logro ver que debo cambiar. <br /><br />Estaría bueno poder ver el log de que es lo que funcionó mal para poder cambiarlo. <div><br /></div><div>Es normal que aparezcan este tipo de errores en productos nuevos. Me gusta mucho como va evolucionando este producto pues le va a facilitar mucho la tarea a los "Citizen Developers" y también nos va a servir a nosotros (Professional Developer) para hacer prototipos rápidos. </div><div><br /></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com2tag:blogger.com,1999:blog-5980598.post-6664818231114195542023-09-04T09:38:00.004-03:002023-09-04T09:58:28.238-03:00 Cómo encontrar objetos en una KB GeneXus que utilizan dos tablas<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjc1ApyGKaW8GjxpumfYIEfXDMZJVs0Fr8OHsYuxew9XtjSSLBBMqu2gsMBIlImf1059RtNgor4HS8AsPYeH1SX3R_hNKWWdP8914PhHI8qkLuAluogOUNmwp_gnjVhSurXmlKTADHEeNNX9xeY_CTBDKsOzsiq4AIfaB12PU22PcfKKPlL6cUJvQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="720" data-original-width="1280" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEjc1ApyGKaW8GjxpumfYIEfXDMZJVs0Fr8OHsYuxew9XtjSSLBBMqu2gsMBIlImf1059RtNgor4HS8AsPYeH1SX3R_hNKWWdP8914PhHI8qkLuAluogOUNmwp_gnjVhSurXmlKTADHEeNNX9xeY_CTBDKsOzsiq4AIfaB12PU22PcfKKPlL6cUJvQ" width="320" /></a></div><br />GeneXus es una herramienta poderosa que facilita la creación y mantenimiento de aplicaciones. Sin embargo, en ocasiones podemos encontrar la necesidad de identificar qué objetos hacen referencia a dos tablas específicas en nuestra Knowledge Base (KB). <p></p><p>Vamos a hacerlo paso a paso.</p><h4 style="text-align: left;">Paso 1: Listar objetos que usan la TABLA1</h4><p>1. En tu KB GeneXus, localiza la TABLA1.</p><p>2. Una vez que estés en la tabla, ve a las referencias de los objetos que la utilizan.</p><p>3. Selecciona todos los objetos que hacen referencia a esta tabla.</p><p>4. Accede al menú <b>LSIExtensions (*) </b>y selecciona <b>Edit</b>.</p><p>5. Luego, elige <b>Copy Info Objects as Table</b>.</p><p>6. Abre tu editor de texto preferido y pega el contenido del portapapeles. Yo uso Notepad++</p><h4 style="text-align: left;">Paso 2: Ordenar y guardar el archivo</h4><p>1. Ordena el contenido alfabéticamente. Lo ordeno en el Notepad++ con Edit / Line Operation / Sort Lines</p><p>2. Guarda el archivo con el nombre TABLA1.txt.</p><h4 style="text-align: left;">Paso 3: Listar objetos que usan la TABLA2</h4><p>1. Vuelve a tu KB GeneXus y repite el proceso del Paso 1 pero ahora con TABLA2.</p><p>2. Ordena alfabéticamente el contenido (como en el Paso 2).</p><p>3. Guarda el archivo como TABLA2.txt.</p><h4 style="text-align: left;">Paso 4: Comparar ambos archivos</h4><p>1. Utiliza un comparador de texto (herramientas como WinMerge, Diffchecker, Beyond Compare o Notepad++ o cualquier otro software de tu preferencia).</p><p>Yo uso el Notepad++ con el Plugin Comparer</p><p>2. Abre TABLA1.txt y TABLA2.txt en el comparador.</p><p>3. Comienza la comparación y presta atención a las líneas que son iguales en ambos archivos, ya que esto indica que el objeto hace referencia a ambas tablas.</p><p>4. Toma nota de estas líneas o, si prefieres, crea un nuevo archivo con esos objetos específicos.</p><p>Con esto, hago una lista de los nombres de los objetos separados por ; editando un archivo que tenga los objetos que usan ambas tablas. </p><p>5. La salida es por ejemplo objeto1;objeto2;objeto3 (es importante <b>no </b>poner el ; al final). Esa lista de objetos se puede poner el el selector de objetos del Work With Objects (Ctrl-J) o Open Object (Ctrl-o) </p><p>Con estos pasos, habrás identificado todos los objetos en tu KB GeneXus que hacen referencia tanto a TABLA1 como a TABLA2. Esta técnica puede ser especialmente útil cuando estás trabajando en refactorizaciones, modularizaciones o intentando comprender mejor las interdependencias en tu KB. </p><p>Puede ser usado para tablas o para otro tipo de objetos. En mi caso, tenia que ubicar objetos que hacían join entre dos tablas, que son muy usadas en una KB de mas de 10.000 objetos y no era una tarea fácil. <br />Posiblemente existan otras formas de hacerlo mas eficientes. Seria bueno que GeneXus brindara una forma nativa de hacer este tipo de operaciones. </p><p>(*) Tuve que compilar LSIExtensiones para GeneXus 18, porque es encuentran los fuentes, pero no los binarios. Como el GeneXus Platform SDK tuvo varios cambios en sus dll, hay que hacer varios cambios para lograr que compile. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-51710327946090609512023-08-29T09:47:00.000-03:002023-08-29T09:47:07.389-03:00Fortaleciendo la Comunidad GeneXus: Desafíos y Oportunidades<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi0KIYR60p7pJY4WvQwvr-ZGWzLcRSPvpbpmB_vb7LveE9jucvm8zqNpNqTaXj4uFMPxGk3fUBnYmBX7DvF3TzM8ZTPs6nok321RlCcjWmTUNb-iooiBR6Ex_sjDVzlvmidDovZ8iihJ9v_ratQE0a6CB9uiXkQZ5AnhQRDIB_3lXAGhvG1jKGebg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="300" data-original-width="332" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEi0KIYR60p7pJY4WvQwvr-ZGWzLcRSPvpbpmB_vb7LveE9jucvm8zqNpNqTaXj4uFMPxGk3fUBnYmBX7DvF3TzM8ZTPs6nok321RlCcjWmTUNb-iooiBR6Ex_sjDVzlvmidDovZ8iihJ9v_ratQE0a6CB9uiXkQZ5AnhQRDIB_3lXAGhvG1jKGebg" width="266" /></a></div><br /><p></p>En los últimos años, la cantidad de usuarios GeneXus ha experimentado un crecimiento. Esto es evidente con la llegada de nuevos desarrolladores y la continuidad de los que, como yo, llevamos años en este mundo. Las tendencias hacia el desarrollo Low Code, la integración de inteligencia artificial y la creciente demanda de sistemas por parte de empresas y personas sugieren un futuro prometedor con espacio para más desarrolladores.<br /><h4 style="text-align: left;">¿Por qué es tan crucial una comunidad sólida?</h4>Una comunidad fuerte permite mejorar las metodologías de trabajo, haciendo que los proyectos GeneXus sean más eficientes y productivos. Pero para que una comunidad prospere, hay factores esenciales a considerar:<br /><br /><ul style="text-align: left;"><li><b>Compromiso</b>: Una comunidad saludable se caracteriza por la activa participación de sus miembros, quienes deben sentirse impulsados a colaborar y aportar.</li><li><b>Comunicación Abierta</b>: Es vital facilitar canales de comunicación efectivos entre miembros y líderes. Y, por supuesto, todo debe basarse en el respeto mutuo.</li><li><b>Diversidad e Inclusión</b>: Una comunidad diversa ofrece riqueza en perspectivas y experiencias. Desde expertos hasta novatos, todos deben tener un lugar y sentir que pertenecen.</li><li><b>Soporte y Recursos</b>: Es fundamental proporcionar herramientas y recursos que fortalezcan el desarrollo y las capacidades de los miembros.</li><li><b>Flexibilidad</b>: Las comunidades deben adaptarse a cambios y evoluciones, y el consejo de un colega con experiencia similar puede ser invaluable.</li><li><b>Reconocimiento</b>: Valorar las contribuciones incrementa la participación y refuerza la sensación de pertenencia.</li><li><b>Seguridad</b>: Todos deben sentirse seguros al compartir ideas, sin temor a críticas destructivas o acoso.</li></ul>Hemos logrado importantes avances en nuestra comunidad, como la organización de webinars de muy buen contenido, los cursos en video, etc . <div><br /></div><div>Sin embargo, aún enfrentamos desafíos. Los foros, especialmente aquellos dirigidos a betatesters, no han cumplido las expectativas, pues los planteos la mayoría de las veces, quedan sin respuesta o la misma demora semanas. Da la sensación que ni siquiera son leídos. </div><div><br /></div><div>Otra oportunidad, es la creación de ambientes donde principiantes puedan plantear sus dudas. <br />El uso de StackOverflow y Slack no fueron demasiado exitosos, desde mi punto de vista, pues les faltó promoción y liderazgo para responder las dudas. <br /><br />No soy experto en gestión de comunidades, pero me parece claro que debemos mejorar. Necesitamos espacios para que los recién llegados aprendan y crezcan, a través de talleres, debates y mentorías.<br /><br />En conclusión, fortalecer nuestra comunidad es esencial para maximizar la productividad en proyectos GeneXus. Es una inversión a largo plazo que, sin duda, valdrá la pena. </div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-2279838833779774502023-07-28T11:53:00.002-03:002023-07-28T11:53:53.587-03:00Consejos de uso de Google Analytics para el desarrollador GeneXus. <p>En las <a href="https://wiki.genexus.com/commwiki/servlet/wiki?11847,Google+Analytics+Control">aplicaciones Genexus, es muy fácil habilitar</a> Google Analytics para que la misma informe sobre su uso.</p><p>Esta herramienta tiene muchisimos usos para entender como usan los usuarios la aplicación. En particular, queria mostrar algunas que son utiles para quienes desarrollan aplicaciones web, y pueden ayudar a desarrollar aplicaciones mas faciles de usar. </p><p><br /></p><h3 style="text-align: left;">Usuarios en Real Time</h3><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj5ni4fMQxx6gswL8r3J3Qwd_vqtq_TDilkt2VzSUjlFkROkqOjDWuSy0RFiq4h8HuMFGviBZNQwD2jta1wbrfBPj9cNCWOM0s7FFLc0QJONhKe1lrz47gGZoU7AOTdCfLVnPi11MkPYDh1YDFGsoEOkj75dHr0WD0MaycL8J5tSqnc8F5of59cMw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="362" data-original-width="1635" height="151" src="https://blogger.googleusercontent.com/img/a/AVvXsEj5ni4fMQxx6gswL8r3J3Qwd_vqtq_TDilkt2VzSUjlFkROkqOjDWuSy0RFiq4h8HuMFGviBZNQwD2jta1wbrfBPj9cNCWOM0s7FFLc0QJONhKe1lrz47gGZoU7AOTdCfLVnPi11MkPYDh1YDFGsoEOkj75dHr0WD0MaycL8J5tSqnc8F5of59cMw=w680-h151" width="680" /></a></div><br />Permite ver cuantos usuarios estan conectados en este momento al sitio y desde donde se están conectando. Es útil para ver como afectan alguna nueva instalación. <p></p><p>Muestra desde que dominio, pais se conectan y cuales son las paginas mas utilizadas en ese momento. </p><h3 style="text-align: left;">Ranking por paises </h3><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgdZ7Mtrmz6NEUUJ4NBlbgNH9QOAPED_BWY2hb-lQC0ZudkNy8t4O60chlsBFnlJz5Ltw4L9ffdtV2-x4t5_MAUcFsCs6k48xF5OH0uglNJE3JhzAtnxQuwCGUMkqcKrRUWIaiC2RY2gdkyXlkLbNPF8YEZueYok55Efnq56RbkSHUNbWbXHggoEw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="864" data-original-width="1017" height="543" src="https://blogger.googleusercontent.com/img/a/AVvXsEgdZ7Mtrmz6NEUUJ4NBlbgNH9QOAPED_BWY2hb-lQC0ZudkNy8t4O60chlsBFnlJz5Ltw4L9ffdtV2-x4t5_MAUcFsCs6k48xF5OH0uglNJE3JhzAtnxQuwCGUMkqcKrRUWIaiC2RY2gdkyXlkLbNPF8YEZueYok55Efnq56RbkSHUNbWbXHggoEw=w640-h543" width="640" /></a></div><br /><p></p><p>Para conocer un poco mejor la audiencia de mi aplicacion, es bueno ver desde que pais es mas usada la aplicación. Por ejemplo en este caso, la gran mayoria de la misma es accedida desde Uruguay. <br /><br /></p><h3 style="text-align: left;">Que navegador usan mis usuarios? </h3><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiyhYMdeuN1LxX94lyyiWMPKbXKrPNoliI9WCcmqMIL25YoA8wELZBjtFTS6pcYZjmjh7buRM0E5UeoUvVNbeBIm8Qwx0I6EsvZqIfpwy39KtIr6YSlifc0XNEFvhYzkngIH-nosuORDrXONaQaIw201HUbaKMWcyktsx3Tpx3FVi4ObluoMKtBog" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="369" data-original-width="1036" height="228" src="https://blogger.googleusercontent.com/img/a/AVvXsEiyhYMdeuN1LxX94lyyiWMPKbXKrPNoliI9WCcmqMIL25YoA8wELZBjtFTS6pcYZjmjh7buRM0E5UeoUvVNbeBIm8Qwx0I6EsvZqIfpwy39KtIr6YSlifc0XNEFvhYzkngIH-nosuORDrXONaQaIw201HUbaKMWcyktsx3Tpx3FVi4ObluoMKtBog=w640-h228" width="640" /></a></div><br />Ver esta consulta ayuda a definir con que navegadores debemos concentrar los esfuerzos de testing de la aplicación. <p></p><h3 style="text-align: left;">Con que sistema operativo se conectan? </h3><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg6EzMd0X6XVcUMY1oc-uhPOjqGFP0KfIxqTyVyTV3iAyRRN4XMFpCu9ffaXcsj0qLU_9o6o55EiKFlEEW84u2hnMjyfDK7mDB2FVF8mIpSB6pkDzOEQiK2ZbcBLzL0xPNav-TYpxM3pK7Zu1fza_uUCDn27lXQ_1iCv93Rw7zcizPa8ysAVpkQTA" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="409" data-original-width="1027" height="254" src="https://blogger.googleusercontent.com/img/a/AVvXsEg6EzMd0X6XVcUMY1oc-uhPOjqGFP0KfIxqTyVyTV3iAyRRN4XMFpCu9ffaXcsj0qLU_9o6o55EiKFlEEW84u2hnMjyfDK7mDB2FVF8mIpSB6pkDzOEQiK2ZbcBLzL0xPNav-TYpxM3pK7Zu1fza_uUCDn27lXQ_1iCv93Rw7zcizPa8ysAVpkQTA=w640-h254" width="640" /></a></div><br /><h3 style="text-align: left;">Qué proporción de usuarios se conectan con mobile? </h3><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhHFNpc7qlUY_rtYj0U8qro5VD8ol0EIjAMVoP75Y0WSr4Ej8UkUv_PsdxAXXx6hCk3D0YC6nFiJY6nyzrFiFED_pV8b6SERNGy9iAHmLsouQgE3AIySOAMHErvhT6wDG8EprswCK5SgsW7iwZ-Vlnk7uk0sCaKacgjtil22udhBS0P6H0J6RyurA" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="295" data-original-width="616" height="306" src="https://blogger.googleusercontent.com/img/a/AVvXsEhHFNpc7qlUY_rtYj0U8qro5VD8ol0EIjAMVoP75Y0WSr4Ej8UkUv_PsdxAXXx6hCk3D0YC6nFiJY6nyzrFiFED_pV8b6SERNGy9iAHmLsouQgE3AIySOAMHErvhT6wDG8EprswCK5SgsW7iwZ-Vlnk7uk0sCaKacgjtil22udhBS0P6H0J6RyurA=w640-h306" width="640" /></a></div><br />Esta consulta es la que conviene ver su evolución para ver cuantos usuarios se conectan a la aplicación WEB con dispositivos móviles y cuantos lo hacen desde equipos de escritorio. <p></p><h3 style="text-align: left;">Que resolución de pantalla usan mis usuarios?</h3><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi57S4Fzl3kEFxD1jYkxhbCqAGvq2JqTrolBBFhXIcRNpNLSpgtqiinxpXvpaUfhhJ7y5GkAKSZJfHmiOP_jE3zgxYxbfe8ughz-TjS2_mnycXl8sJAR3M_k8MM95kRHZnnlw4IMKryYDksmiOUTihHqr-MCq-0dUJD_r_RTSwLyI8OrbF3ftZ47A" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="606" data-original-width="663" height="584" src="https://blogger.googleusercontent.com/img/a/AVvXsEi57S4Fzl3kEFxD1jYkxhbCqAGvq2JqTrolBBFhXIcRNpNLSpgtqiinxpXvpaUfhhJ7y5GkAKSZJfHmiOP_jE3zgxYxbfe8ughz-TjS2_mnycXl8sJAR3M_k8MM95kRHZnnlw4IMKryYDksmiOUTihHqr-MCq-0dUJD_r_RTSwLyI8OrbF3ftZ47A=w640-h584" width="640" /></a></div><br />Esta consulta es importante para tomar decisiones de diseño de pantallas. Y también en como probar las aplicaciones. <p></p><h2 style="text-align: left;">Performance</h2><h3 style="text-align: left;">Cuanto demora en promedio cargar las páginas? </h3><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiHFn2zeSXxYFSrtv9AfVkix0dsk5MLdA2NMW_L1P0x2m0v6iOAp5_v9NQS7hd9glzZZZPMc7QmIsTzSFF7PlBT-gV2FwykF0vJxUV4fOMdJyV9ScJSs1zBS10Rh0jmfgc548xPEQJgZTChU34KeeExvA1ZYr9XeNWRR6Iytbumb3gRhM5EPfe_tg" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="584" data-original-width="1044" height="358" src="https://blogger.googleusercontent.com/img/a/AVvXsEiHFn2zeSXxYFSrtv9AfVkix0dsk5MLdA2NMW_L1P0x2m0v6iOAp5_v9NQS7hd9glzZZZPMc7QmIsTzSFF7PlBT-gV2FwykF0vJxUV4fOMdJyV9ScJSs1zBS10Rh0jmfgc548xPEQJgZTChU34KeeExvA1ZYr9XeNWRR6Iytbumb3gRhM5EPfe_tg=w640-h358" width="640" /></a></div><br />Se pueden ver como evoluciona el tiempo de carga de las paginas y si empeora o mejora con los cambios de versiones que se instala. </div><div><br /></div><h3 style="text-align: left;">Cuales son las páginas que se usan más y cuanto demoran ? </h3><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEisHOLMLfSypVNOjHJVyK9MSvYTHcLknQnoQYjbBZm2dOGpTgdTmKeMkKhNOo6mng9-LIQnJ97Dce7vMhyPjaVbklFjK3rzGwTmXO2bzSu6pimlxYon6E2PU6pcXcRvttEkeaCtM6_dwXvPQdUzmu_2Dx4yjmSmHFSv0qMHTpulnanCQQmp-AOMNg" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="576" data-original-width="678" height="543" src="https://blogger.googleusercontent.com/img/a/AVvXsEisHOLMLfSypVNOjHJVyK9MSvYTHcLknQnoQYjbBZm2dOGpTgdTmKeMkKhNOo6mng9-LIQnJ97Dce7vMhyPjaVbklFjK3rzGwTmXO2bzSu6pimlxYon6E2PU6pcXcRvttEkeaCtM6_dwXvPQdUzmu_2Dx4yjmSmHFSv0qMHTpulnanCQQmp-AOMNg=w640-h543" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;">En esta consulta se puede ver la cantidad de visitas y el tiempo promedio que demoran las consultas mas usadas. Hay una consulta que demora en promedio 10.20 segundos, y seria bueno poder optimizarla. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><h3 style="clear: both; text-align: left;">Conclusión</h3><div style="text-align: justify;">Incorporar Google Analytics es muy fácil en cualquier aplicación WEB o Mobile y nos da algo de visibilidad y permite hacer consultas útiles para focalizar el desarrollo y mantenimiento de nuestra aplicación en las áreas que mas se necesitan, para que los usuarios tengan una buena experiencia de usuario. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Como los recursos dedicados a mantenimiento de aplicaciones es siempre escaso, conviene focalizar en aquellos que mas se necesiten. Por ejemplo, puedo hacer que las consultas más usadas desde celulares con baja resolución, sean responsive y se muestren solo los datos indispensables cuando lo veo en pantallas chicas. </div></div></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com1tag:blogger.com,1999:blog-5980598.post-82422539886750297642023-07-20T19:39:00.005-03:002023-07-21T09:41:40.601-03:00KBDOCTOR para Genexus 18<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgYRw2o5_cR4fE6T13l89iP2AFEeObN9ZZR-iIUcDg-o3zffAb9NpWS2rFlaTT-6FTAl7f0npvwU4yjAiEDlSK2_dni1K3o3LTKDbc-4iVdCyHIzrZjw1KfPk7Ff05RVuyyIpxn7HTJ3hYGSDjgFX-onYC099lxdgXyLcUszBS9VjB3iGzEeWwuDQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="61" data-original-width="249" height="78" src="https://blogger.googleusercontent.com/img/a/AVvXsEgYRw2o5_cR4fE6T13l89iP2AFEeObN9ZZR-iIUcDg-o3zffAb9NpWS2rFlaTT-6FTAl7f0npvwU4yjAiEDlSK2_dni1K3o3LTKDbc-4iVdCyHIzrZjw1KfPk7Ff05RVuyyIpxn7HTJ3hYGSDjgFX-onYC099lxdgXyLcUszBS9VjB3iGzEeWwuDQ" width="320" /></a></div><br />Intenté subir una versión de KBDOCTOR para Gx18 al marketplace y no lo logré, pues da errores de validación que no logre superar.<p></p><p>Dejé <a href="https://wiki.genexus.com/commwiki/wiki?55396,File%3AKbdoctor+gx18.zip,">un zip en la wiki</a>, por si alguien lo quiere </p><p>Descomprimir en el directorio Packages y luego ejecutar</p><p>genexus /install </p><p>en el directorio de Genexus 18.</p><p>Tiene muy poco testeo y no tiene opciones nuevas. No está en condiciones optimas de ser liberado, pero como me lo pidieron varias veces, lo libero. </p><p><br /></p><p><br /></p><p><br /></p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com2tag:blogger.com,1999:blog-5980598.post-27022688019451165912023-07-03T09:41:00.005-03:002023-09-08T10:18:11.823-03:00Eventos en webpanels y transacciones GeneXus. <p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjmiz5A_H0CMj8hz4sHZ1R2toyXdK0zWpKVUJReTnwYSxuKtjh7dEOBIxY_F61lNqAU_R5nyvlvbPbOHSGKQsJjhJg8RzRviRarwoeWrHiWAR1oYkEKsJZspBbmrJ0oDugmPBvnl36MjpR9B5eTmhKGjc2TNAGJXhK1_ScgcM_iDck8AfYbb4BzAQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="400" data-original-width="600" height="213" src="https://blogger.googleusercontent.com/img/a/AVvXsEjmiz5A_H0CMj8hz4sHZ1R2toyXdK0zWpKVUJReTnwYSxuKtjh7dEOBIxY_F61lNqAU_R5nyvlvbPbOHSGKQsJjhJg8RzRviRarwoeWrHiWAR1oYkEKsJZspBbmrJ0oDugmPBvnl36MjpR9B5eTmhKGjc2TNAGJXhK1_ScgcM_iDck8AfYbb4BzAQ" width="320" /></a></div><br />Este post es parte de una serie de artículos sobre como hacer KB mas mantenibles y actualizables a nuevas versiones de GeneXus.<p></p><p>Los objetos que tiene interfaz de usuario, soportan eventos en su programación. Dichos eventos son necesarios para permitir al usuario hacer acciones sobre los datos. Los eventos pueden dispararse por diferentes motivos como ser apretar un botón, cambiar algún valor, salir de un control, paginar, cargar una grilla, etc. </p><p>Una practica que recomiendo fuertemente para hacer la KB mas fácil de mantener y sobre todo mas migrable a nuevas versiones, es la de solo incluir en el código de los eventos, aquellas cosas que interactúan con los elementos de las pantalla, y todo lo demás, resolverlo con otros objetos (procedures, data providers, etc). </p><p>Cosas que <b>SI</b> deben hacer los eventos:<br /></p><p></p><ul style="text-align: left;"><li>Mostrar mensajes al usuario</li><li>Ocultar/Mostrar controles (botones, grillas, tablas)</li><li>Actualizar datos en pantalla, dependiendo de lo ingresado por el usuario</li><li>Cambiar texto de controles (captions) </li><li>Mover controles</li><li>Cambiar colores</li><li>Agrandar/achicar textos</li><li>Interactuar con User Controls</li><li>Call a procedures / Usar Data Providers</li></ul><div>Cosas que <b>NO</b> deben hacer los eventos (**)</div><div><ul style="text-align: left;"><li>for each sobre tablas (aunque sea para cargar controles, tipo dynamic combobox)</li><li>Lógica de negocio</li><li>Usar SDT que no sean mostrados en pantalla </li><li>Usar código nativo (CSharp, Java) </li><li>Usar External Objects</li><li>Commits/Rollback</li></ul><div>Usando estas reglas, se obtiene codigo que es mas fácil de mantener y tambien de modularizar. </div></div><div>Cuando llega el momento de migrar a versiones mas nuevas, tambien es mucho mas fácil realizar el cambio de webpanel a panels o usarlos para Smart Devices o lo que se venga en el futuro. </div><div><br /></div><div>Alguien puede decir, que programando de esta forma, se van a tener mas objetos en la KB y es totalmente cierto. Se tienen mas objeto, mucho mas chicos y mas focalizados en una tarea especifica, lo cual hace mas facil luego su mantenimiento </div><div><br /></div><div>Haciéndolo corta:<br />En los eventos de WBP o TRN, solo interactuar con la UI y todo lo demas, resolverlo en procedures y data providers. </div><div><br /></div><div>No es difícil hacer una herramienta que haga estos chequeos, para facilitarle la vida a los desarrolladores futuros. </div><div><br /></div><div>(**) Los resultados pueden variar. Results may vary. </div><div>Puede haber casos en que es indispensable usarlos, use con moderación. </div><div><br /></div><p></p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com0tag:blogger.com,1999:blog-5980598.post-35717519952439526212023-06-15T10:22:00.005-03:002023-06-16T11:20:49.415-03:00No code, low code, high code = CODE<p>La evolución de la forma de interacción entre humanos y máquinas ha experimentado cambios significativos a lo largo del tiempo. Voy a tratar de mostrar con diagramas como ha evolucionado el proceso de desarrollo de software y la interacción entre los desarrolladores y las computadoras.</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh94hhcQPlfROXt1SyKzuG319HPTPgMtrkGbawiPj4R-v9WTNbBYEPE-jS0ozhv2Gm6NO-3ypv7NMhq_WBktSY9kzMIub1KNThKnQxTrudVnT_7Uwm8ySAy64OVgTgNUL8HuVEI4eMHrzO4OgUD-GkZvov3Dw_5krN9byUuOXIjJSmOWMBSfhw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="182" data-original-width="1367" height="65" src="https://blogger.googleusercontent.com/img/a/AVvXsEh94hhcQPlfROXt1SyKzuG319HPTPgMtrkGbawiPj4R-v9WTNbBYEPE-jS0ozhv2Gm6NO-3ypv7NMhq_WBktSY9kzMIub1KNThKnQxTrudVnT_7Uwm8ySAy64OVgTgNUL8HuVEI4eMHrzO4OgUD-GkZvov3Dw_5krN9byUuOXIjJSmOWMBSfhw=w485-h65" width="485" /></a></div></div><br /></div><p></p><p>En las primeras etapas, se muestra que los desarrolladores interactuaban directamente con las computadoras utilizando lenguaje máquina. En esta fase, el desarrollo de software requería un conocimiento profundo de la arquitectura y los códigos de bajo nivel de las máquinas. Era un enfoque muy técnico y laborioso.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiV0R6KcgzmlG4F5npsxZpzNwGkIOahEuaOmVIOjSkjSmrsPSQAKY539GiNt825vJf5QSfxOG87nDQcz_Ayw3uDqZ10x5jUTwv4crezLpSVvr_gQHoC7_d9KcRB0M_7f6DP36uOhsaaaqDdOUCVF13Ko4ee3O9andZZuW71MUtSl7VeHGymifg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="153" data-original-width="1363" height="55" src="https://blogger.googleusercontent.com/img/a/AVvXsEiV0R6KcgzmlG4F5npsxZpzNwGkIOahEuaOmVIOjSkjSmrsPSQAKY539GiNt825vJf5QSfxOG87nDQcz_Ayw3uDqZ10x5jUTwv4crezLpSVvr_gQHoC7_d9KcRB0M_7f6DP36uOhsaaaqDdOUCVF13Ko4ee3O9andZZuW71MUtSl7VeHGymifg=w490-h55" width="490" /></a></div><p></p><p>A medida que avanzamos en el tiempo se observa una progresión hacia niveles de abstracción más altos. La siguiente etapa muestra el uso de lenguaje ensamblador (assembler), que proporcionaba una capa de abstracción sobre el lenguaje máquina, facilitando un poco más la tarea de programación. En esta etapa, los programadores tenían que hacer manejo de memoria, acceso a disco y programar las operaciones mas básicas desde cero, para cada una de las maquinas que tenían que programar. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhPnEMKLYcSn0v76enQ203NgaD06bh8nog0yQFYoy4Pqi4BfMSPJJ2vkM_Rr2qYRvHLV6X_ab8HW4yxpNz9nWKFZaoo8frm8TW3nnKuBgs3ey8nscK80M15WnOm0ODHmdTb-p8GUuVRrww_xNOvW1him07xRgL5Y2SYYCmtQCDUVStTMWZ2tbw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="121" data-original-width="1383" height="63" src="https://blogger.googleusercontent.com/img/a/AVvXsEhPnEMKLYcSn0v76enQ203NgaD06bh8nog0yQFYoy4Pqi4BfMSPJJ2vkM_Rr2qYRvHLV6X_ab8HW4yxpNz9nWKFZaoo8frm8TW3nnKuBgs3ey8nscK80M15WnOm0ODHmdTb-p8GUuVRrww_xNOvW1him07xRgL5Y2SYYCmtQCDUVStTMWZ2tbw=w720-h63" width="720" /></a></div><br /><p></p><p>Luego, con la introducción de los lenguajes de alto nivel permitió a los desarrolladores escribir menos código y en un formato más cercano al lenguaje humano. En esta etapa, los programas escritos en lenguajes de alto nivel debían ser traducidos a lenguaje máquina para que la computadora pudiera entenderlos y ejecutarlos.</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhLkYx5V7b3KIlcy9zfbrmzZXW1hdTQNsYJBRmG8fep-wO2XbCqzMwS6oqxjdETMmbQ19DrL0vq6aDbW-myeE0K2mkFtcRLWscDkmnwQi2ZDHhK7fTjy9ketxsqZejbpKjP5xCy07c2Uqzy2223WCon2mQqJDJhhlMKvBCcFt0WhirmvH4DeZY" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="301" data-original-width="1370" height="108" src="https://blogger.googleusercontent.com/img/a/AVvXsEhLkYx5V7b3KIlcy9zfbrmzZXW1hdTQNsYJBRmG8fep-wO2XbCqzMwS6oqxjdETMmbQ19DrL0vq6aDbW-myeE0K2mkFtcRLWscDkmnwQi2ZDHhK7fTjy9ketxsqZejbpKjP5xCy07c2Uqzy2223WCon2mQqJDJhhlMKvBCcFt0WhirmvH4DeZY=w495-h108" width="495" /></a></div><br /><br /></div><br />La siguiente fase muestra la introducción del bytecode y la máquina virtual (como la de java o los framework de .NET). En este enfoque, el código fuente escrito en lenguajes de programación de alto nivel se compila en bytecode, que es un conjunto de instrucciones de nivel intermedio. La máquina virtual se encarga de interpretar y ejecutar el bytecode en la computadora. Esta abstracción permitió la portabilidad del software, ya que el mismo bytecode podría ejecutarse en diferentes plataformas.<p></p><p>Escribimos menos código y podemos hacer mas aplicaciones mas potentes. </p><p>El avance de esto no es tan lineal como para poder representarlo en diagramas sencillos, pues en el medio tuvimos lenguajes de cuarta generación, manejadores de reglas en runtime, y herramientas graficas para el diseño de flujos de trabajo. Todas estas son forma de código, que permiten explicarle a la computadora que es lo que tiene que hacer. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEglWHfR7jOkaX--9NpYoJt8lVNWMwlxZ_hTwPGEhVM-U7rUH6_Al4t6vbIgtBLHILcTMUdhzIiBHfDq_5SXcGa9aYHD1YIn6taFMTfxXp-om3cy0_BV-Krjp_z2z6i8ayb7R4Tx84yNEVNhdlXCdTj9vz1kLA56F_N0zeFUSZdSCVdKZYVXOSU" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="202" data-original-width="985" height="110" src="https://blogger.googleusercontent.com/img/a/AVvXsEglWHfR7jOkaX--9NpYoJt8lVNWMwlxZ_hTwPGEhVM-U7rUH6_Al4t6vbIgtBLHILcTMUdhzIiBHfDq_5SXcGa9aYHD1YIn6taFMTfxXp-om3cy0_BV-Krjp_z2z6i8ayb7R4Tx84yNEVNhdlXCdTj9vz1kLA56F_N0zeFUSZdSCVdKZYVXOSU=w595-h110" width="595" /></a></div><br />El enfoque de "low code" es una tendencia actual en el desarrollo de software. El "low code" se basa en el uso de plataformas y herramientas que permiten a los desarrolladores crear aplicaciones con un mínimo de codificación manual. Estas herramientas proporcionan interfaces visuales y configuraciones simplificadas para agilizar el proceso de desarrollo. Aunque todavía se requiere el lenguaje de máquina para que la computadora ejecute el software, el enfoque de "low code" reduce considerablemente la cantidad de código que los desarrolladores deben escribir manualmente.<p></p><p>En resumen, el diagrama representa la evolución de la interacción entre humanos y máquinas en el desarrollo de software. Ha habido un progreso desde el uso directo de lenguaje máquina hasta enfoques más abstractos y simplificados, como el uso de lenguajes de alto nivel, bytecode, máquinas virtuales, lenguajes de cuarta generación y el enfoque de "low code". Estos cambios reflejan la búsqueda constante de formas más eficientes y accesibles de desarrollar software, permitiendo a los desarrolladores enfocarse más en la lógica del negocio y menos en los detalles técnicos de implementación.</p><p>A lo largo de la corta historia de la computación, vemos una evolución grande en todo el ciclo. Tanto los desarrolladores y las computadoras han cambiado y avanzado mucho. <br />Han variado mucho la forma en que le damos las instrucciones a las computadoras sobre que es lo que tienen que hacer y hemos avanzado mucho en los tipos de problemas que podemos resolver, pero el código, sigue siendo codigo. La cantidad de instrucciones que tiene que tener una computadora para resolver problemas es mas o menos conocida. Si se puede declarar y definir esas instrucciones de forma mas concisa o mas rapida, hay que aprovecharlo y tener mayor productividad. Pero el código estará en forma de componentes reutilizables, en parámetros de modelos matemáticos o en códigos difíciles de entender como ADN o jeroglíficos, pero va a existir. <br /></p><p>En todas estas abstracciones es importante tener en claro que debemos hacer sistemas/aplicaciones en forma profesional y responsable para no pasar a futuras generaciones de programadores sistemas que sean difíciles de mantener o que necesiten reprogramarlos, pues eso siempre es un proceso bastante traumático. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com2tag:blogger.com,1999:blog-5980598.post-46501879407367521212023-06-02T18:54:00.004-03:002023-06-05T14:59:19.366-03:00GeneXus: Usar un workspace controlado - O como organizar el espacio de trabajo en GeneXus. <p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_pnqHHPJOshzaWQy21M40hydqHroEdHTgE8hxS7l7TxBTGeO2pDKXGnaQqgU74ANJJEh72e6McPjeDbpM8f2mWEFi83Gnx8_omD6OusPYYqdtKxRj9rrhiHNW5EOTKSXTr8uASsBLuoWajTcI9tYeO1rtUNDV4FvtLof4Qv-fgsyAr9vmXjk/s600/ventanas_desordenadas.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="600" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_pnqHHPJOshzaWQy21M40hydqHroEdHTgE8hxS7l7TxBTGeO2pDKXGnaQqgU74ANJJEh72e6McPjeDbpM8f2mWEFi83Gnx8_omD6OusPYYqdtKxRj9rrhiHNW5EOTKSXTr8uASsBLuoWajTcI9tYeO1rtUNDV4FvtLof4Qv-fgsyAr9vmXjk/s320/ventanas_desordenadas.jpg" width="320" /></a></div><br />GeneXus es altamente configurable en su espacio de trabajo. Permite que sus diferentes componentes, se agrupen en el IDE de diferente formas y los mismos pueden quedar flotantes, auto ocultarse, agrandarse, achicarse, verlos arria, abajo, etc. <p></p><p>Tambien es muy comun, que con el trabajo alguna de estas ventanas se oculten sin querer, o queden en lugares incomodos. </p><p>Por ejemplo, cuando trabajo en monitores que son Full HD o superiores, me gusta tener :</p><p></p><ul style="text-align: left;"><li>siempre visible a la derecha el KBExplorer / Preferences, </li><li>siempre visible y a la izquierda las Propiedades, Toolbox y los resultados de los Test. </li><li>siempre visible y abajo, la ventana de output. </li><li>el espacio central con el editor de texto </li><li>un tab para KBdoctor. </li></ul><div>GeneXus nos brinda la posibilidad de ejecutar con la opción /NoWorkSpace, con la cual se levanta con las opciones por defecto, donde las propiedades , el KB Explorer y el Output se ocultan cuando no tienen el foco. Acomodarlo a la forma que yo quiero, lleva un tiempito. </div><div><br /></div><div>Algo que encontré (aunque no lo vi documentado en ningun lado) es que GeneXus salva el estado del WorkSpace en el archivo GenexusWorkSpace.xml en el directorio <br /><br /><span style="font-family: courier;"><b>%APPDATA%</b>\Genexus\GeneXus\<b>%gxversion%</b>\GeneXusWorkspace.xml</span></div><div><br /></div><div>donde AppData es la variable de entorno cuyo contenido c:\users\ealmeida\AppData\Roaming<br />y gxversión es 17, 18, etc. <br /><br />Por lo tanto, para poder empezar siempre GeneXus con las ventanas colocadas en los lugares y con las tamaños que a mi me gustan es:<br /><ul style="text-align: left;"><li>Ejecuto GeneXus /NoWorkSpace (por ejemplo, GeneXus 17) en el directorio de GeneXus. </li><li>Configuro las ventanas como a mi me gustan</li><li>Cierro GeneXus (con esto se salva el archivo GeneXusWorkSpace.xml )</li><li>Renombro el archivo GeneXusWorkSpace.xml a GeneXusWorkSpace_OK.xml</li></ul><br />Luego hago un archivo GX17_workspace.CMD que hace:<br /></div><p></p><div><span style="font-family: courier;">set gxversion=17</span></div><div><div><span style="font-family: courier;">set gxprogamdir=c:\genexus\genexus%gxversion%</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">copy %APPDATA%\Genexus\GeneXus\%gxversion%\GeneXusWorkspace_ok.xml %APPDATA%\GeneXus\GeneXus\%gxversion%\GeneXusWorkspace.xml</span></div><div><span style="font-family: courier;">start %gxprogamdir%\genexus.exe</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: inherit;">Entonces, cada vez que quiero empezar GeneXus con la </span>configuración<span style="font-family: inherit;"> </span>deseada<span style="font-family: inherit;"> corro con ese script y recupero el estado del espacio de trabajo que a mi me gusta. </span></div><div><br /></div><div>Ya plantee en el foro de la BETA que estaría bueno poder salvar o recuperar un estado de workspace desde el IDE, pero por el momento esto no está soportado, por lo que paso esta forma de hacerlo pues puede servirle a alguien. </div></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com5tag:blogger.com,1999:blog-5980598.post-20627935070263340662023-05-01T22:02:00.004-03:002023-05-02T10:20:08.700-03:00Modelo de datos temporales (o bi-temporales). <div><span data-canva-clipboard="ewAiAGEAIgA6ADUALAAiAGQAIgA6ACIAQgAiACwAIgBoACIAOgAiAHcAdwB3AC4AYwBhAG4AdgBhAC4AYwBvAG0AIgAsACIAYwAiADoAIgBEAEEARgBoAHUATQBKAHMAXwAtAG8AIgAsACIAaQAiADoAIgA3ADcAMQBtAHQAaABhAGEANwBGAFIASwB5AEcAVgBaAG4ASwBqAGoAOQBnACIALAAiAGIAIgA6ADEANgA4ADIAOQA4ADYAMQA0ADYANwA1ADMALAAiAGoAIgA6AFsAewAiAEEAIgA6AHsAIgBCACIAOgB7AH0ALAAiAEsAIgA6AHsAfQAsACIAQwAiADoAewB9ACwAIgBNACIAOgB7AH0ALAAiAEQAIgA6AHsAfQAsACIATAAiADoAWwB7ACIAQQAiADoAewB9ACwAIgBCACIAOgAiAEMAIgB9ACwAewAiAEEAIgA6AHsAfQAsACIAQgAiADoAIgBCACIAfQBdACwAIgBFACIAOgB7AH0ALAAiAEYAIgA6AHsAIgBBACIAOgAiAEkAZABlAG4AdABpAHQAeQAuAHAAbgBnACIALAAiAEIAIgA6ADEAfQAsACIARwAiADoAewB9ACwAIgBIACIAOgB7ACIAQgAiADoAIgBuAG8AbgBlACIALAAiAEMAIgA6ACIAIwAwADAAMAAwADAAMAAiACwAIgBEACIAOgAiACMAZgBmAGYAZgBmAGYAIgB9ACwAIgBKACIAOgB7ACIARgAiADoAIgAjADAAMAAwADAAMAAwACIAfQB9AH0AXQAsACIAQQA/ACIAOgAiAEIAIgAsACIAQQAiADoAWwB7ACIAQgAiADoAMQAyAC4AMAA3ADcAMwA5ADMAMgA2ADEAMgAzADUANwA4ADQALAAiAEQAIgA6ADEAMAA2ADcALgA5ADIAMgA2ADAANgA3ADMAOAA3ADYANAAyACwAIgBDACIAOgAxADAAOAAwAC4AMAAwADAAMAAwADAAMAAwADAAMAAwADAAMgAsACIAQQA/ACIAOgAiAEkAIgAsACIAYQAiADoAewAiAEIAIgA6AHsAIgBBACIAOgB7ACIAQQAiADoAIgBNAEEARgBoAHUARgAwAE4AVAB3AE0AIgAsACIAQgAiADoAMQB9ACwAIgBCACIAOgB7ACIAQQAiADoALQAyADcALgA4ADEAMAA3ADMANgAwADEAMQA5ADEAMgAwADEAMwAsACIAQgAiADoALQA2ADcALgA2ADkAOAA4ADYANQAyADgANQAwADYAMAAyADYALAAiAEQAIgA6ADEAMQAzADUALgA2ADIAMQA0ADcAMgAwADIAMwA4ADIANAAzACwAIgBDACIAOgAxADEAMwA1AC4ANgAyADEANAA3ADIAMAAyADMAOAAyADQAMwB9AH0AfQB9AF0ALAAiAEIAIgA6ADEAMAA4ADAALAAiAEMAIgA6ADEAMAA4ADAAfQA="></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiXcUm02razwREc3HGhBNs8U0HfNUE8iEbBBPJ9aSrYeFAgm5sJUGG-iapgGW3zW_xxbKmqh_eRxxM3tpaDKVlsLXDJmoHjHZy5OdVKhgOjxcxNHGO41PJ37epIV42cIe1oHjGnqunl1wObX2tLan_lwyJedrfo1HZD4UVMy2qHK8bBzLMZBXU" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="581" data-original-width="567" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEiXcUm02razwREc3HGhBNs8U0HfNUE8iEbBBPJ9aSrYeFAgm5sJUGG-iapgGW3zW_xxbKmqh_eRxxM3tpaDKVlsLXDJmoHjHZy5OdVKhgOjxcxNHGO41PJ37epIV42cIe1oHjGnqunl1wObX2tLan_lwyJedrfo1HZD4UVMy2qHK8bBzLMZBXU" width="234" /></a></div><br />Imaginemos una aplicación de gestión de ventas de una tienda en línea que utiliza una base de datos relacional para almacenar su información. Esta aplicación tiene una tabla "Ventas" que almacena información sobre las ventas realizadas en la tienda. La tabla tiene las siguientes columnas:<div><br /></div><div><span style="font-family: courier;"><b>VENTAS</b><br />* VentasID Ventas ID Numeric (8) <br /> VentasFecha Ventas Fecha Date <br /> ClienteID Cliente ID Character (10) <br /> VentasImporte Importe de la venta Numeric (10.2)<br /><br /><b>CLIENTE</b><br />* ClienteID Cliente ID Character (10) <br /> ClienteNombre Cliente Nombre VarChar (100) <br /> CiudadID Ciudad ID Character (10) </span><div><p>La aplicación tiene la capacidad de registrar las ventas que se realizan, incluyendo la fecha en que se llevan a cabo, y también puede realizar consultas sobre las ventas registradas en la base de datos. Sin embargo, la aplicación no refleja el tiempo en el modelo de datos para las entidades relacionadas con la venta, como los clientes. </p><p>Por ejemplo, si un cliente se muda de cuidad después de realizada una compra, la aplicación no registra esta información histórica en la base de datos. La información del cliente se actualiza en la base de datos en tiempo real, y se sobrescribe la información anterior. </p><p>Para seguir con el ejemplo sencillo, supongamos que tenemos </p><p>Si tenemos los clientes, ciudades y ventas<br /><br /></p><div style="background-color: white; font-family: Consolas, "Courier New", monospace; font-size: 12px; line-height: 16px; white-space: pre;"><div><b>VENTAS</b></div><div>2023-01-01 -EL_ECO - 1.000</div><div>2023-02-01 -TELEGRAFO - 5.000</div><div>2023-03-01 -TELEGRAFO - 2.000</div><div><br /></div><div><b>CLIENTES</b></div><div>EL_ECO - PALMIRA - EL ECO DE PALMIRA</div><div>TELEGRAFO - PAYSANDU - EL TELEGRAFO</div><div><br /></div><div>y podemos hacer un reporte de </div><div><br /></div><div><b>TOTAL POR CIUDAD</b></div><div>PALMIRA : 1.000</div><div>PAYSANDU : 7.000</div><div>RIVERA : 0</div><div><br /></div><div>En un momento el cliente TELEGRAFO <b>se muda a RIVERA.</b> </div><div><br /></div><div>CLIENTES</div><div>EL_ECO - PALMIRA - EL ECO DE PALMIRA</div><div>TELEGRAFO - RIVERA - EL TELEGRAFO</div><div><br /></div><div>el reporte de totales por ciudad, va a ser de la siguiente forma:</div><div><br /></div><div><b>TOTAL POR CIUDAD</b></div><div>PALMIRA : 1.000</div><div><span style="color: red;"><b>PAYSANDU : 0</b></span></div><div><span style="color: red;"><b>RIVERA : 7.000</b></span></div></div><p>En resumen, aunque la aplicación puede manejar el tiempo para los hechos relacionados con las ventas (como la fecha de la venta), no refleja el tiempo en el modelo de datos para las entidades relacionadas con la venta (como los clientes y los productos). Como resultado, la aplicación no puede realizar un seguimiento histórico completo de la información relacionada con las ventas y sus entidades relacionadas.</p><p>Este funcionamiento, puede ser aceptable o no en la aplicación. Antes era casi la única forma de hacerlo, pero cada vez mas los clientes tienen más requerimientos para que los reportes de ventas pasadas, no se modifiquen por cambios presentes en las entidades relacionadas con la venta. </p><p>Existen varias soluciones posibles (o las mas usadas, al menos)</p><h3 style="text-align: left;">1) Data warehouse</h3><p>La opción mas sencilla, es tener una data warehouse, donde se carguen las ventas en forma periódica, manteniendo redundancia en la DW. La aplicación y la base de datos operacional es una foto actual de los datos y guardamos la historia en la DW. Para esto, hay muchos estudios sobre dimensiones que cambian (<a href="https://en.wikipedia.org/wiki/Slowly_changing_dimension">Slowly Changing Dimensions</a>) </p><p><b>Ventajas: </b><br />Es una forma conocida y probada de resolverlo. </p><p><b>Desventajas:</b><br />Hay que hacer programas de carga de la DW. Hay que duplicar el modelo de datos y mantener la infraestructura de la misma. Los reportes históricos deben hacerse en la DW y los operacionales en otra base de datos, lo cual puede ser molesto y confuso para los usuarios.</p><p>También es común que los reportes de la DW tengan algún retraso en la carga de los datos, que pueden dificultar la toma de decisiones. </p><h3>2) Gestión de datos históricos</h3><div>Usar herramientas de las base de datos, para guardar datos históricos, que sirve para la auditoria. La mayoría de las base de datos, soportan en forma parcial el standard <a href="https://en.wikipedia.org/wiki/SQL:2011">SQL:2011</a> que incluyen soporte temporales en SQL y poder consultar el estado de tablas en el pasado (no soporta el futuro). </div><div><br /></div>Tengo esperanza que Genexus permita definir tablas como SYSTEM_VERSIONING en el futuro, y esto facilitaría un poco este tipo de escenarios. <h3 style="text-align: left;">3) Incorporar manejo temporal al modelo de datos temporales (o bi-temporales).</h3><p> Una forma que recomiendan en la bibliografia, es la utilización de un rango de vigencia de los datos, por ejemplo, para la tabla de CLIENTES tendríamos</p><p><b style="font-family: courier;">CLIENTE</b><br style="font-family: courier;" /><span style="font-family: courier;">* ClienteID Cliente ID Character (10)<br />* Cliente_FechaInicial Date<br /> Cliente_FechaFinal Date<br /></span><span style="font-family: courier;"> ClienteNombre Cliente Nombre VarChar (100)<br /></span><span style="font-family: courier;"> CiudadID Ciudad ID Character (10)</span></p><p>Modificando la clave de clientes y con eso podemos guardar en una única tabla todos los datos históricos de clientes. <br /></p><p>Para poder consultar dicha tabla, siempre hay que ir con una fecha (con hoy, veo el registro actual). <br />Tiene como contra, que no se pueden utilizar funcionalidades de la base de datos, como integridad referencial y también se complica bastante la realización de joins. </p><p>Otro de los problemas, es que hay que controlar que los rangos de fechas de vigencia, sean coherentes. Siempre la FechaInicial debe ser menor igual que la FechaFinal. <br />Además los intervalos de tiempos entre diferentes registros no se deberían superponer.</p><p>Dar de alta un cliente, es agregar un registro a la tabla de clientes. </p><p>Actualizar un cliente, es cerrar la vigencia de la versión anterior del cliente y dar de alta un nuevo registro de cliente con una nueva vigencia. </p><p>Dar de baja un cliente, alcanza con poner la fecha de finalización la vigencia, a la fecha que se haga </p><p>Para poder utilizarlo correctamente es necesario manejar patrones de desarrollo para no ocasionar problemas. </p><h3 style="text-align: left;">4) Modelo Mixto (Dimensiones con Revisiones)</h3><p>Uno modelo que me ha servido en algunas oportunidades es tener un modelo mixto. La entidad de clientes seria modelada con dos tablas. </p><p><b style="font-family: courier;">CLIENTE</b><br style="font-family: courier;" /><span style="font-family: courier;">* ClienteID Cliente ID Character (10)<br /></span><span style="font-family: courier;"> ClienteNombre Cliente Nombre VarChar (100)</span></p><p><span style="font-family: courier;"> <b>CLIENTE_REVISION</b><br /></span><span style="font-family: courier;"> * Cliente_RevisionID Number (8)<br /> Cliente_FechaInicial Date<br /> </span><span style="font-family: courier;"> Cliente_FechaFinal Date<br /></span><span style="font-family: courier;"> CiudadID Ciudad ID Character (10)</span></p><p>El nombre del cliente, puede ir en la tabla de arriba o en la revision, dependiendo si considera que el nombre del cliente es significativo. Para algunas entidades puedes ser bueno dejarlo junto a la clave (o sea no llevar historia de ese campo) y para otras se va a necesitar llevar la revisiones de ese atributo tambien. </p><p>Las ventajas de este modelo, es que se tiene integridad referencial en la base de datos, en los casos que se deseen. </p><p>Cuando se realiza una venta, se va a buscar cual es la revisión correspondiente a dicha venta (con una condicion Cliente_FechaInicial <= FechaVenta y FechaVenta < Cliente_FechaFinal. </p><p>Una vez encontrada la revision, se guarda dicha revisión en la tabla de ventas y a partir de ahi, fiunciona correctamente el join entre Ventas y Cliente_revision y tambien se puede delegar a la base de datos la integridad referencial. </p><p>La tabla de Ventas (con manejo de tiempo en las dimensiones quedaría)</p><p><b>VENTAS</b></p><p><span style="font-family: courier;">* VentasID<span style="white-space: pre;"> </span>Numeric (8)<span style="white-space: pre;"> </span><br /></span><span style="font-family: courier;"> VentasFecha</span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;"> </span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;">Date</span><span style="font-family: courier; white-space: pre;"> </span><br /><b> <span style="font-family: courier;">ClienteID</span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;">Character (10)<br /></span><span style="font-family: courier;"> Cliente_RevisionId</span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;">Numeric (8)</span></b><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;"> <br /></span><span style="font-family: courier;"> VentaImporte<span style="white-space: pre;"> </span>Numeric (10.2)</span><span style="white-space: pre;"> </span></p><p>Por cada dimensión que necesite manejo temporal, debo agregar un numero de revision, que debe calcularse en el momento de generar el hecho (en este caso, la venta). </p><p>La alternativa que manejan en los libros, es el utilizar rangos de fechas y siempre manejar la fecha de la venta, para ir a buscar cual es la revisión correspondiente, pero eso es mucho mas costoso desde el punto de vista computacional, para sistemas que graban una vez y luego son leidos muchas veces. </p><p>Por ejemplo, en este caso, se realiza la venta y se grabaría el registro y luego dicho registro va a ser consultado muchas veces para consultas, impresiones, etc. </p><p><b>Ventajas:</b></p><p>Utilización de la base de datos relacional para manejo de integridad referencial y joins. </p><p>Manejo relativamente sencillo con Genexus para el manejo de datos temporales en dimensiones. </p><p>El impacto en el rendimiento y en el almacenamiento no es muy grande. </p><p><b>Desventajas</b></p><p>Existen tablas adicionales, que al ser accedida deberán ser filtradas por una fecha (ej. ClienteRevision)</p><p>Hay que validar en el mantenimiento de datos básicos, que los periodos de validez de las revisiones sean coherentes. </p><p>Las modificaciones de datos en el pasado, pueden necesitar ajustes (cambios en la revisión en los hechos). Por ejemplo, si detecto que una revisión anterior, ya fue usada en una venta, pero tenia algun dato equivocado, puedo necesitar crear nuevas revisiones y cambiar la revisión en la tabla de Ventas. </p><p>El borrado de dimensiones (en este caso CLIENTES) no puede ser físico, sino que hay que agregar una flag o una fecha de borrado, pues siempre tendrá referencias. </p><p>La tablas de hechos van a quedar con tantos campos de revisión, como dimensiones temporales haga referencia la tabla, lo cual puede hacer un poco mas incomodo el hacer consultas manuales sobre las tablas. </p><p>En el caso de la ejecución anterior</p><div style="background-color: white; font-family: Consolas, "Courier New", monospace; font-size: 12px; line-height: 16px; white-space: pre;"><div>VENTAS</div><div>2023-04-21 -ELECO - 1000.00</div><div>2023-03-22 -TELEGRAFO - 5000.00</div><div>2023-05-01 -TELEGRAFO - 2000.00</div><div><br /></div><div>CLIENTES <b>usando fecha 2023-05-01</b></div><div>ELECO - PALMIRA - EL ECO DE PALMIRA</div><div>TELEGRAFO - RIVERA - EL TELEGRAFO</div><div>--</div><div>TOTAL POR CIUDAD</div><div>PALMIRA : 1000</div><div>PAYSANDU : 7000</div><div>RIVERA : 0</div></div><p>A pesar que el cliente TELEGRAFO esta ahora en RIVERA, las ventas siguen reflejando que se hicieron en PAYSANDU, que era lo que queriamos, que no cambiara de ciudad las ventas realizadas en el pasado. </p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjm5-7d6xY6wlbTt8_Y13eLQ78AY1ReObMu8oiAvD5IcaU3g6SE1KueqUMNnKxXwMi5go1bfibQY02O8fN6LBfHmhhTqG5HPSNUvFT8UKsvdEBsZs9yKwWEGJdyN2Qp8Kp65UhoTPOye8T3k62iUeaOkVnxJLgMZUepJKRO1dr2thyW0RRzF9o" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="457" data-original-width="1040" src="https://blogger.googleusercontent.com/img/a/AVvXsEjm5-7d6xY6wlbTt8_Y13eLQ78AY1ReObMu8oiAvD5IcaU3g6SE1KueqUMNnKxXwMi5go1bfibQY02O8fN6LBfHmhhTqG5HPSNUvFT8UKsvdEBsZs9yKwWEGJdyN2Qp8Kp65UhoTPOye8T3k62iUeaOkVnxJLgMZUepJKRO1dr2thyW0RRzF9o=s16000" /></a></div><br /><br /></div>Lo unico que hay que agregar es lo que esta marcado en rojo. <p></p><p><br />Estoy buscando contraejemplos, donde este modelo tenga problemas, pero por ahora no los estoy encontrando. </p><p>Existen otras soluciones (por ejemplo guardar redundante en los hechos las dimensiones que se quieran o usar dos rangos de fechas (uno para la fecha en que se realiza la operación y otro rango de fechas para la validez de dicha información). Queda bastante mas complejo el modelo, aunque permite corrección de datos en el pasado. </p><p><br /></p><h3 style="text-align: left;">Conclusión</h3><p>A medida que los sistemas se hacen mas críticos y abarcan cada vez mas actividades de la vida cotidiana, vamos a tener que poder modelar mejor como evolucionan los mismos. Los modelos de datos actuales, no reflejan bien los cambios que suceden y seria bueno que los proveedores de herramientas (base de datos, herramientas de desarrollo, frameworks, etc) provean las componentes basicos para poder hacer mas fácil estos desarrollos. <br />Por ejemplo, seria bueno poder contar con tipos de datos básicos como PERIODOS (del tipo fecha inicial y fecha final) y sus operaciones como chequear que una fecha este en un periodo o que dos periodos se superponen o se contienen, etc. Las bases de datos están incorporando a un ritmo lento estas funcionalidades. Espero que en el futuro serán mas comunes. </p><p>En particular, con GeneXus, me gustaría contar con un Pattern de diseño, que permita mantener este tipo de dimensiones con soporte temporal, validando las operaciones de alta/baja y modificaciones y que brinde las funciones necesarias para buscar las revisiones por fechas. </p><p>Si contáramos con la posibilidad de manejo de periodos como un tipo basico, tambien seria un poco mas sencilla de entender la programación, el desplegar en pantalla, usar un UC para el ingreso de rangos de fechas, etc.</p><p>También se puede agregar validaciones a la KB, que avise si existe un programa que acceda a la tabla de ClienteRevision, y no filtra por la clave primaria o no toma en cuenta el rango de fecha. Puede ser valido, en caso que quiera listar todos las revisiones, pero serian las excepciones. </p><p><b>Nota:</b> En los ejemplos, use Fecha para elegir algo sencillo, pero los periodos o rangos dependen de la precisión que necesite la aplicación. Pueden ser años, meses, días, días/horas, milisegundos, etc</p><p>Links útiles</p><p></p><ul style="text-align: left;"><li><a href="https://en.wikipedia.org/wiki/Bitemporal_modeling">Bitemporal Data Model</a> (wikipedia)</li><li><a href="https://www.amazon.com/-/es/Tom-Johnston/dp/0124080677">Bitemporal Data </a> (Tom Johnston)</li><li><a href="https://www.amazon.com/-/es/Tom-Johnston/dp/0123750415/ref=sr_1_2?__mk_es_US=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=1MPZVOPTK8L1K&keywords=temporal+database+relational&qid=1682988760&s=books&sprefix=temporal+database+relatio%2Cstripbooks%2C357&sr=1-2">Managing Time in Relational Databases: How to Design, Update and Query Temporal Data</a> (Tom Johnston)</li><li><a href="https://martinfowler.com/eaaDev/timeNarrative.html">Temporal Patterns</a> (Martin Fowler)</li><li><a href="https://link.springer.com/referenceworkentry/10.1007/978-0-387-39940-9_439">TSQL2 </a>(<a data-author-popup="auth-Richard_T_-Snodgrass" data-test="author-name" data-track-action="open author" data-track-label="link" data-track="click" href="https://link.springer.com/referenceworkentry/10.1007/978-0-387-39940-9_439#auth-Richard_T_-Snodgrass" style="background-color: #fcfcfc; box-sizing: inherit; color: #004b83; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 16px; margin-block: 0px; margin: 0px; overflow-wrap: break-word; text-decoration-skip-ink: auto; text-decoration-thickness: 0.0625rem; text-underline-offset: 0.08em; word-break: break-word;">Snodgrass</a><span face="-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif" style="background-color: #fcfcfc; color: #333333; font-size: 16px;"> )<br /><br /></span></li></ul><div><p>UPDATE </p><p>Como dice Pablo en los comentarios, también se pueden usar <a href="https://wiki.genexus.com/commwiki/servlet/wiki?45622,Temporal+Data+using+Dynamic+Transactions">Dynamic Transactions</a>. Con mis pruebas, no me fue muy bien, pero tal vez estaba haciendo algo mal. Voy a revisar y hago otro post comparando las soluciones. </p></div><p></p></div></div><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com3tag:blogger.com,1999:blog-5980598.post-23580053065389689132023-03-21T08:39:00.003-03:002023-03-21T08:41:24.324-03:00Usabilizando GeneXus: Poder salvar el estado del Workspace (y dejarlo por defecto)<p>GeneXus es muy configurable, en la forma de posicionar las diferentes ventanas de trabajo (workspace). <br />Es habitual mover y/o agrandar las ventanas de:<br /></p><ul style="text-align: left;"><li> Output</li><li> Properties</li><li> KB Explorer</li><li> Toolbox</li><li> Search</li></ul><p></p><p>y un montón de etcéteras. </p><p>Genexus por defecto, recuerda el estado del espacio de trabajo y la próxima vez que entro, me muestra las ventanas tal cual las dejé la ultima vez.</p><p>Esto trae como problema, que cuando uno trabaja un rato largo, puede mover alguna ventana por error y queda mal configurada. Volver a la situación anterior deseada, no es difícil, pero es engorroso. </p><p>Una opción que hoy nos brinda Genexus es la de correr GeneXus con la opción /NoWorkSpace que abre la configuración default de GeneXus. </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj6yA_A-DGGvsIEyOoDiinHJNx0jOWpObFZOD0Q2lPIkhbPCNm2chm6U7JwAuo2t0fkalHftrGXOU2HRSPGGmetWzGxwdg4-LRn5UWPUWtVhpaFiycYiIMmKqXqOfoMY_nryALZcHJnNCed1YiRcCwmwSqkhh6viDCMsQZwGTZG9VBAD1rgLBo" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="605" data-original-width="1127" src="https://blogger.googleusercontent.com/img/a/AVvXsEj6yA_A-DGGvsIEyOoDiinHJNx0jOWpObFZOD0Q2lPIkhbPCNm2chm6U7JwAuo2t0fkalHftrGXOU2HRSPGGmetWzGxwdg4-LRn5UWPUWtVhpaFiycYiIMmKqXqOfoMY_nryALZcHJnNCed1YiRcCwmwSqkhh6viDCMsQZwGTZG9VBAD1rgLBo=s16000" /></a></div><br /><p></p><p>En monitores grandes, a mi me gusta trabajar con la opción por defecto de GeneXus, pero con el KB Explorer y Properties fijadas/ancladas (no se como se traduce pinned) y la ventana de Output siempre visible abajo. </p><p>Muestro un ejemplo, en baja resolución, en la realidad el área de trabajo es mucho mayor. <br /><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjBWytyGQJWy7E5nEWQsCbOvANGeELjrVAF6gcjnh1Ro0ogLZ3KFgs0tDfP266G_aBJiT2pupXZnQ3vbdpgqZG-XGkKZayz8PYde1bZy6KcuRnUzprImXDl-r5DATGbUPnWwkQd0kFBY3yCCRNhW6WZWnYA5H0yBfA6fFIoPAC_T9mtLBAsjTw" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="600" data-original-width="1128" src="https://blogger.googleusercontent.com/img/a/AVvXsEjBWytyGQJWy7E5nEWQsCbOvANGeELjrVAF6gcjnh1Ro0ogLZ3KFgs0tDfP266G_aBJiT2pupXZnQ3vbdpgqZG-XGkKZayz8PYde1bZy6KcuRnUzprImXDl-r5DATGbUPnWwkQd0kFBY3yCCRNhW6WZWnYA5H0yBfA6fFIoPAC_T9mtLBAsjTw=s16000" /></a></div><br /><br />Cosas que me gustaría poder hacer:<br /><ul style="text-align: left;"><li>Cambiar la configuración por defecto del workspace, de forma que cuando abra GeneXus con /NoWorkspace, me traiga mi configuración. </li><li>Poder Salvar Configuraciones con diferentes configuraciones (Monitor Grande, Monitor Chico, Dos Monitores, etc).</li><li>Poder Elegir una configuración y recargarla, sin salir de Genexus. </li></ul><div>Tal vez estas cosas ya se puedan hacer y yo aun no encontré como se hacen. </div><div><br /></div><div>PD: He visto que diferentes desarrolladores, eligen diferentes configuraciones, dependiendo de:</div><div><ul style="text-align: left;"><li>Cantidad de Objetos de la KB (en KB chicas, los objetos se encuentran mas facil)</li><li>Resolucion de monitores (la experiencia es muy diferente en monitores chicos que grandes)</li><li>Mas de un Monitor (Repartir pantallas en mas de un monitor, da una experiencia diferente)</li><li>Tipo de Aplicacion (No usan la misma configuracion para mobile que para web, por ejemplo)</li><li>Tipo de trabajo (Es diferente programar API y Procedures, que Paneles) </li></ul></div><p></p><p><br /></p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com1tag:blogger.com,1999:blog-5980598.post-10491690421240173872023-03-06T11:39:00.001-03:002023-09-08T10:17:45.100-03:00Primera prueba de GeneXus Next<p> </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjbRM13AonjD92aMRaxcoJD-Ur3qgbgDN8NVxA3If6MW1wj6uzY5JF_HSGslOHeOB_bTqNkFokocNM9YEWSpf8E2DSNr0d3yVTbuXoH1XzYvtvr3MryxloKsG7P_ykN4n6CDosJV-5VKl0CrYK1LjKb4bCqKtgZYtkEvAcxjYiMdL-_8mN-NGQ" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="432" data-original-width="990" height="175" src="https://blogger.googleusercontent.com/img/a/AVvXsEjbRM13AonjD92aMRaxcoJD-Ur3qgbgDN8NVxA3If6MW1wj6uzY5JF_HSGslOHeOB_bTqNkFokocNM9YEWSpf8E2DSNr0d3yVTbuXoH1XzYvtvr3MryxloKsG7P_ykN4n6CDosJV-5VKl0CrYK1LjKb4bCqKtgZYtkEvAcxjYiMdL-_8mN-NGQ=w400-h175" width="400" /></a></div><br /><p></p><p>La primera prueba de GeneXus Next me gustó mucho, para ser una primerísima versión. Tiene mucho potencial que deberá verse en futuras versiones. <br /><br />Cómo otras herramientas orientadas a interfaz por un chat, nos presenta un prompt donde podemos escribir unas pocas palabras. La idea ahí es describir que es el sistema que quiero realizar, y de ahí infiere cuales serán las principales entidades que va a tener el backend para dicho sistema. </p><p>Lo probe en español y en inglés y no noté diferencias sustanciales, aunque lo que genera siempre está en ingles. </p><p>Por ejemplo, si escribo en el prompt:<br /><br /><span style="background-color: white;"><span face="Poppins, sans-serif" style="color: #8c8d8e;"><span style="font-size: 18px;"><i>"Manejo de Seguridad, con usuarios, roles y permisos. Autenticar y Autorizar los diferentes Objetos de la aplicación"<br /><br /></i></span></span></span>Me plantea las siguientes entidades: <span style="background-color: white;"><span face="Poppins, sans-serif" style="color: #8c8d8e;"><span style="font-size: 18px;"><i><br /><br /></i></span></span></span></p><p><span face="Poppins, sans-serif" style="background-color: white; box-sizing: border-box; color: #8c8d8e; font-size: 14px;">Based on your business description, the following 4 entities were identified:</span><br style="background-color: white; box-sizing: border-box; color: #8c8d8e; font-family: Poppins, sans-serif; font-size: 14px;" /><br style="background-color: white; box-sizing: border-box; color: #8c8d8e; font-family: Poppins, sans-serif; font-size: 14px;" /></p><ol style="background-color: white; box-sizing: border-box; color: #8c8d8e; font-family: Poppins, sans-serif; font-size: 14px; margin-bottom: 10px; margin-top: 0px;"><li style="box-sizing: border-box;"><span style="box-sizing: border-box;">Object:</span> Resources that users can access</li><li style="box-sizing: border-box;"><span style="box-sizing: border-box;">Permission:</span> Actions that users can perform</li><li style="box-sizing: border-box;"><span style="box-sizing: border-box;">Role:</span> Permissions assigned to each user</li><li style="box-sizing: border-box;"><span style="box-sizing: border-box;">User:</span> People who use the application</li></ol><p>y luego de unos 5 minutos<br /><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgBKuv8hHTu5KAOXPBqw4KVZPF7Y-ah22RXzPn_RIDip3tYkJkdsAWMXB2g9TgVbTcW-p-rKkkyZDPjbH-6sBSn-aQjT-dJKO-8Mx5RCaE1MnR7EEIl6mhwBOVD6AgwMVPV6oQlHbncE2mFK_ryizH8ALiKwuLVA5rhzJKzYKBEH3UcRrpQLCo" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="539" data-original-width="778" height="222" src="https://blogger.googleusercontent.com/img/a/AVvXsEgBKuv8hHTu5KAOXPBqw4KVZPF7Y-ah22RXzPn_RIDip3tYkJkdsAWMXB2g9TgVbTcW-p-rKkkyZDPjbH-6sBSn-aQjT-dJKO-8Mx5RCaE1MnR7EEIl6mhwBOVD6AgwMVPV6oQlHbncE2mFK_ryizH8ALiKwuLVA5rhzJKzYKBEH3UcRrpQLCo" width="320" /></a></div><br /><p></p><p>Genera las tablas en una base de datos, le carga datos de prueba , y publica una API para acceso a dichas tablas (altas bajas y modificaciones). <br /><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjtNKhj57aiYxwo-Hgq0dnLEgX7LhhwSnDCdrS_aBJKpCza0lx7CA1WR55gAnSS2Un9NWp2jDJtC2cHYnO7Ps7OuallDzt2F4Bdv0x9-w9kBCZag_77QqpdFcmiqwiQJt52ksZEgivvruxyBpeyJlHSCNwZ2ihcS__oSg3tui8jWqTWTiBhImw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="830" data-original-width="1032" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjtNKhj57aiYxwo-Hgq0dnLEgX7LhhwSnDCdrS_aBJKpCza0lx7CA1WR55gAnSS2Un9NWp2jDJtC2cHYnO7Ps7OuallDzt2F4Bdv0x9-w9kBCZag_77QqpdFcmiqwiQJt52ksZEgivvruxyBpeyJlHSCNwZ2ihcS__oSg3tui8jWqTWTiBhImw" width="298" /></a></div><br />También genera programas con el Pattern WW+ sobre todas las tablas que necesita, donde se pueden hacer altas / bajas / modificaciones y consultas sobre las tablas definidas y queda una aplicación para probar en un ambiente en la nube. <p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhwcLqDspU9eh3lUJNL_Sx8CCPJt0299FbAIKS5-Lht8tavzy6THEhDTdXxptw1FGhsjU1c9dWAPJtxiAwSH6MHrNwgFNrWeKqhE6HuhO5gEDETFd2bseT4frzJ1nnyKig2YRKIWQmL2ugCIB6uEQHIY6rlXMNa0Y37PY2XCpvGSJchO7xisrQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="543" data-original-width="1057" height="164" src="https://blogger.googleusercontent.com/img/a/AVvXsEhwcLqDspU9eh3lUJNL_Sx8CCPJt0299FbAIKS5-Lht8tavzy6THEhDTdXxptw1FGhsjU1c9dWAPJtxiAwSH6MHrNwgFNrWeKqhE6HuhO5gEDETFd2bseT4frzJ1nnyKig2YRKIWQmL2ugCIB6uEQHIY6rlXMNa0Y37PY2XCpvGSJchO7xisrQ" width="320" /></a></div><br /><br /><p></p><p>Haber podido generar todo esto, solo con una descripción de lo que quiero es maravilloso. </p><p>Automatiza una cantidad de tareas (diseñar las entidades, crear la base de datos, cargar datos de prueba, aplicar patrones, generar la API, hacer el deploy al ambiente de test y varias mas) bajando muchísimo la fricción que existe para hacer prototipos para mostrar aplicaciones. Si además pienso que no se ingreso ni una linea de codigo para todo esto, es mejor aun. </p><p>Aun no es útil mas que para mostrar su potencial, pero el ritmo de avance en los temas es impresionante y no dudo que en poco tiempo tengamos algo que pueda usarse. </p><p>El desafío de traducir desde el ambiente de los usuarios, donde nada necesita gran precisión al ambiente de los sistemas,donde se necesita que todo este precisamente definido este tipo de herramientas pueden ser de mucha ayuda. El trabajo de los programadores será el de validar si lo que los usuarios están tratando de explicar, es un modelo útil de la realidad. </p><p>Por ejemplo, en el ejemplo de la seguridad, si bien las entidades son correctas, la relación entre las mismas no son las que a mi me hubiese gustado:<br /></p><ul style="text-align: left;"><li>Cada Object, tiene un solo User. </li><li>Cadar Permission tien un solo Role</li><li>No hay relación entre User y Role.</li></ul>En próximas iteraciones de GeneXus Next se van a poder modificar estas cosas (estructura de las entidades, relaciones entre entidades, etc). Además el resultado de esto va a poder ser modificado con Genexus directamente por un programador. <p></p><p>Como todo sistema que aprende, va a poder dar soluciones tan buena como con los datos que fue entrenado, por lo que es importante que sea alimentado con un buen repositorio de dominios y entidades que estén bien definidas, de forma que pueda replicar buenos ejemplos. </p><p>La inteligencia artificial tiene mucho que aportar para mejorar la productividad de los programadores GeneXus. </p><div class="blogger-post-footer">Publicado en http://ealmeida.blogspot.com</div>Enrique Almeidahttp://www.blogger.com/profile/14840952830880488550noreply@blogger.com11