Weblogs Código

Picando Código

¡Feliz día del Programador!

septiembre 13, 2019 10:00

¡Feliz día del programador colegas! El día del programador se celebra en el día número 256 (28) del año por ser la cantidad de valores representables en un byte de datos (13/9 en los años comunes y 12/9 años bisiestos). Como es tradición, aprovecho la excusa para hacer un repaso de en qué ando desde el último día del programador.

Feliz día del programador

Hablemos de programación: Ruby sigue siendo mi lenguaje principal. Recientemente he estado muy atento a Crystal: un lenguaje con tipos estáticos inspirado en Ruby. En este post, escribí sobre cómo crear un bot de Telegram con un cliente en Crystal, y también desarrollé un shard para validar cédulas de identidad uruguayas (¿suena conocido?). El código fue prácticamente copiar y pegar de la versión de Ruby, con algunas mínimas modificaciones. Pero quedó funcionando con tests, build en Travis y todo. Pueden ver el código fuente en GitHub. También por acá escribí sobre Gleam, lenguaje nuevo sobre BEAM. Por suerte le he venido escapando a Go. 

Me mantengo interesado en Elixir, este año asistí a Code Elixir London y estuvo genial. Vi muchas buenas charlas y cosas interesantes que está haciendo la gente con Elixir. Phoenix LiveView es un despelote y tengo muchas ganas de probarlo. Ojalá para el próximo día del programador les pueda contar de algún proyecto nuevo que programé en Elixir.

He trabajado en varios proyectos propios. Últimamente le estoy metiendo a gamesdb, una gema Ruby para la API de TheGamesDB. El primer commit fue en 2014, y no había escrito nada al respecto en el blog. Espero publicar el proyecto que la inspiró para poder compartirlo por acá algún día. La aplicación está empezada, y tiene la funcionalidad básica, pero desarrollada en formato “MVP” en muy poco tiempo. Ya teniendo la idea y el prototipo (y la gema que permite importar los datos de TheGamesDB), algún día me sentaré a programarla en serio. Tengo al menos dos proyectos más en mente que están a medio empezar pero que me motiva mucho terminarlos para poder usar y compartirlos.

Cada tanto actualizo mi plugin de WordPress: List Category Posts. Tengo ideas de más cosas para WordPress, pero sinceramente me desmotiva un poco programar PHP. No es que sea tan malo, pero al estar en contacto con el lenguaje y su ambiente sólo a través del desarrollo de un plugin de WordPress, es difícil mantenerme interesado (además que el lenguaje no me resulta particularmente atractivo en comparación a otros). Pero seguiré manteniendo éste plugin y List Categories por ahora, y si en algún momento me inspiro publicaré los demás que tengo en mente.

Spacemacs es todavía mi editor de texto. Me hace la vida más fácil y cada vez me gusta más. Me soluciona muchísimo la vida Org-Mode para gestionar trabajo, notas y demás. Escribí un post al respecto en Spacemacs: entorno integrado eficiente y sofisticado para Emacs. Espero que lo vean y descubran lo geniales que son Emacs y Spacemacs.

En conclusión me he mantenido bastante ocupado en cuanto a programación, por más que de repente me resulte más difícil que antes compartir todo eso por el blog. Pero también sigo leyendo muchos cómics, jugando mucho Nintendo, tomando cerveza y escuchando punk rock. Hay cosas que no cambian tanto 🙂

Ya llevo más de 2 años viviendo en Escocia, a pesar de la amenaza del Brexit y quién sabe qué va a pasar. Pero estoy contento acá, me gusta mucho, he hecho muchos amigos nuevos y recibido visitas de gente de Uruguay y sigo volviendo a visitar el paisito. No estoy trabajando más en Cultivate, o sí. Cultivate fue adquirido por Deliveroo, una de éstas empresas grandes en el espacio conocido como “gig economy”, donde básicamente las empresas se ahorran pagar impuestos (Uber, AirBnb, etc). Es la segunda vez que trabajo en una empresa que es adquirida por otra empresa. Veremos qué tal va ésta vez.

Me estoy empezando a sentir viejo en internet. No entiendo muchos comportamientos en redes sociales y mucha cosa me da vergüenza ajena. Estamos interactuando de maneras nuevas y distintas, y no me convence que sean mejores. No estoy hablando de no entender a la gente más joven, muchas veces se trata de gente de mi edad o mayor, y al verles entrar en esa rosca de obtener likes, clics, manipular información, buscar desesperadamente aprobación virtual, pienso “qué pelotudos”. Pero ignórenme, no es más que el abuelo Simpson gritándole a una nube (ya que estamos, recuerden que “la nube” es la computadora de alguien más). Si les pasa lo mismo, les recomiendo desconectarse más. Los libros son un excelente escape a ese bizarro mundo online.

Escribo bastante irregularmente en el blog. La lista de borradores sin publicar crece cada vez más. Por eso a veces termino publicando posts que de repente no son tan extensos, pero por lo menos me fuerzo a terminar de escribir algo “publicable”. Me gusta escribir, y me encanta interactuar con gente que lee lo que escribo. Pero esto se está haciendo cada vez más raro en internet. Las páginas web personales y blogs van muriendo en esta competición por monetizar toda actividad que uno haga, ya sea con streaming, podcasts, y blogs que van quedando inundándonos con anuncios, pop-ups, subscripción a newsletters…

Pero a su vez me deja contento saber que éste es un rincón en internet donde escribo cosas que quiero escribir, sin seguir tendencias o intentar lograr que hagas clic en un enlace para generar una micro ganancia. Y la poca gente que sigue leyendo es porque tiene algún interés en común o le interesa lo que escribo, así que bienvenidos sean. Me vengo proponiendo escribir y publicar más. Aunque no sea sobre programación, software libre o tecnología, voy a postear sobre temas que me interese y divierta. Espero recibir sus comentarios al respecto.

¿En qué andan quienes quedan del otro lado?

El día del programador otros años: 20072008200920102011201220132014201520172018

» Leer más, comentarios, etc...

Fixed Buffer

¡¡FixedBuffer ha cumplido un año!!

septiembre 11, 2019 08:00

La imagen muestra una tarta de cumpleaños

Ya ha pasado el verano, toca volver a la rutina y al trabajo, y volvemos a la carga con el blog. Esta es una publicación especial, porque hoy hace un año, empezamos esta andadura en FixedBuffer.

Este ultimo año ha sido una experiencia muy gratificante, que además me ha dado la posibilidad de colaborar con gente y aprender de ello. De unos cosas más técnicas, de otros cosas más de estilo… Pero en cualquiera de los casos, conocer a compañeros con los que poder ir a comer y hablar de cualquier cosa.

En este último año, he recibido el MVP por parte de Microsoft en tecnologías de desarrollo. También he tenido la posibilidad de dar alguna charla en comunidades técnicas. La verdad es que creo que ha sido un buen año 🙂

Muchas gracias a todos los que durante este año habéis estado al pie del cañón (que se que sois unos cuantos).

Para este año, tenemos más ideas interesantes que seguir contando, como por ejemplo como montar un Identity Server, o colaboraciones que nos hablaran sobre como montar un proxy inverso con Nginx. 🙂 🙂

Por último, vamos a ver cuáles son el Top 5 de las entradas del año:

  1. Haciendo fácil el acceso a datos con Entity Framework Core (Parte 2)
  2. Haciendo fácil el acceso a datos con Entity Framework Core
  3. Generación de ficheros «Excel» (xlsx) con ClosedXML
  4. ClosedXML, una manera fácil de dar formato a nuestros .xlsx
  5. Cómo crear un servicio Net Core multiplataforma

¡¡Muchas gracias a todos los seguidores de FixedBuffer, que sois los que hacéis que esto valga la pena!!

**La entrada ¡¡FixedBuffer ha cumplido un año!! se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Picando Código

Datos y Cogollos: Edición especial Datacamp 2019

septiembre 09, 2019 02:30

El próximo jueves 12 de setiembre a partir de las 19:00, sumate a la comunidad de Datos Abiertos uruguaya en DATOS Y COGOLLOS. Se trata de un evento organizado por la comunidad de Datos Abiertos local, así que no le pertenece a ninguna organización en particular, y está más que abierto a su sigan sumando nuevas personas y organizaciones:

Llega la tercera edición de este evento para conocer y dar a conocer lo que se está haciendo con datos abiertos, esta vez como evento paralelo del Datacamp 2019 de AGESIC y con la presencia de invitados internacionales 😎🔝.

Datos y Cogollos: Especial Datacamp 2019

¿Qué es esto?

Es un evento para juntar a toda la comunidad trabajando alrededor (o cerca, o con interés) del tema Datos Abiertos, conocer los proyectos que hay en la vuelta, pero sobretodo conocer a las personas que estamos en eso y compartir una charla acompañada por alguna bebida para hacerlo más informal.

Es un formato que empezó en México en 2013, impulsado por SocialTIC bajo el nombre de “Datos y Mezcales” y que hace bastante rato que teníamos ganas de traer a Uruguay.
Está organizado por la comunidad de Datos Abiertos local, así que no le pertenece a ninguna organización en particular y está más que abierto a que se sigan sumando nuevas personas y organizaciones.

¿Qué va a pasar?

Ésta es la agenda que vamos a intentar seguir:
– Bienvenida y presentación de la iniciativa
– Presentaciones relámpago ⚡ (máx. 5 min.) de proyectos y organizaciones
– Brindis y convivencia (asado, chelas, cogollos, helado de dulce de leche, etc.)

¿Cómo me anoto para presentar mi proyecto?

Comentá en ese Meetup y decinos el nombre de persona que presentaría, un correo de contacto y el nombre del proyecto/organización/presentación que quieren compartir. Vamos a ir anotando la lista de oradores/as acá, donde también podés anotarte directamente si así lo preferís.

Las presentaciones pueden ser con diapositivas/video/apoyo audiovisual y solicitamos que cada persona que presente la suba a la web (ej. Google Slides) y pegue el enlace a su presentación en el documento anterior. Buscamos presentaciones y presentadores/as lo más diversas posibles, empezando por apuntar a la paridad de género, así que por favor no se ofendan si preguntamos si es posible que presenten otras personas llegado el caso. ☺
Acá podés encontrar sobre las presentaciones del Primer Datos y Cogollos.

¿Por qué “cogollos”?

Básicamente porque podemos… El evento adapta su nombre a alguna bebida típica del país y así pasó por México (Datos y Mezcales), El Salvador (Datos y Cervezas), Bolivia (Datos y Singanis), Ecuador (Datos y Bielas), Colombia (Datos y Guaros), Costa Rica (Datos y Chiliguaros), Guatemala (Datos y Tragos) y España (Datos y Cañas).
Cuando le toca a Uruguay, optamos por algo que ninguna de las organizaciones amigas de todos esos países podría poner legalmente (o sea, es un poco un chiste interno).

¿Es obligatorio presentar/saber de datos abiertos/tomar/fumar porro?

No, para nada. Cada uno viene y hace lo que quiere.

Más información e inscripciones

» Leer más, comentarios, etc...

Blog Bitix

La aplicación cliente de Steam en GNU/Linux

septiembre 06, 2019 04:00

Durante unos años he estado sin jugar a juegos porque al haberme pasado a GNU/Linux creía que no se podía al menos a los juegos comerciales actuales, en GNU/Linux hay algunos juegos que funcionan perfectamente como juegos retro con RetroArch, SuperTux, OpenTTD o Battle for Wesnoth en entre algunos de diversos géneros. Pero la realidad es que con Wine y el cliente de Steam son dos posibilidades para jugar a algunos perfectamente y tener un catálogo que no llega a la altura de Windows pero bastante amplio.

Steam
Linux

La plataforma de juegos Steam es una de las más populares. Con su cliente de juegos es posible comprar, descargar e instalar juegos para tanto para Windows, macOS y también para GNU/Linux. Steam y Valve han posibilitado que se puedan jugar a varios juegos triple A en GNU/Linux, Valve se está esforzando para que muchos juegos sean jugables en la plataforma del pingüino.

Steam ofrece un cliente nativo para GNU/Linux que en Arch Linux se ofrece en los repositorios oficiales. Requiere además habilitar el repositorio multilib para paquetes de 32 bits e instalar el controlador gráfico de la tarjeta gráfica de 32 bits.

1
$ sudo pacman -S steam

Para habilitar el repositorio multilib en Arch Linux hay que editar el archivo de configuración /etc/pacman.conf y descomentar varias líneas quitando el caracter # que las precede.

1
2
3
4
...
[multilib]
Include = /etc/pacman.d/mirrorlist
...

En el caso de un gráfica Intel hay que instalar el paquete lib32-mesa.

1
$ sudo pacman -S lib32-mesa

Hecho esto se puede iniciar el cliente, en el menú de aplicaciones del sistema aparecen su acceso directo de aplicación, se necesita una cuenta por que lo que hay que registrarse antes desde su plataforma web. Los juegos de la biblioteca aparecen en el cliente para instalar. En este caso tengo el juego Company of Heroes 2.

Cliente de Steam en GNU/Linux

Instalado el juego se puede iniciar desde el cliente de Steam. Aún con una gráfica integrada Intel de un Intel NUC8i5BEK (Bean Canyon) se pueden jugar a muchos juegos bajando algo los detalles y resolución.

Company of Heroes 2

Los juegos ofrecen diferente nivel de soporte para GNU/Linux, para Windows, macOS y Steam+Linux, los que deben funcionar sin problema son los de la última categoría. Los de Windows pueden funcionar a través de una capa de emulación desarrollada por Steam, para activarla hay que ir a Steam > Parámetros > Steam Play y activar las opciones Enable Steam Play for Supported title y Activar Steam para todos los demás títulos. Sin embargo, no hay garantía que los juegos con solo soporte de Windows funcionen correctamente, he probado con World of Warships y no se iniciaba correctamente mostrando únicamente una pequeña ventana negra.

Steam Play Settings

De vez en cuando Steam ofrece juegos gratuitos que se pueden añadir libremente a la biblioteca y en ocasiones ofrece grandes descuentos. También a través de su propio cliente es posible jugar a los juegos de Blizzard como Diablo 3, aunque en este caso es necesario utilizar Wine.

» Leer más, comentarios, etc...

Blog Bitix

Como instalar el cliente de Steam en GNU/Linux

septiembre 06, 2019 04:00

Durante unos años he estado sin jugar a juegos porque al haberme pasado a GNU/Linux creía que no se podía al menos a los juegos comerciales actuales, en GNU/Linux hay algunos juegos que funcionan perfectamente como juegos retro con RetroArch, SuperTux, OpenTTD o Battle for Wesnoth en entre algunos de diversos géneros. Pero la realidad es que con Wine y el cliente de Steam son dos posibilidades para jugar a algunos perfectamente y tener un catálogo que no llega a la altura de Windows pero bastante amplio.

Steam
Linux

La plataforma de juegos Steam es una de las más populares. Con su cliente de juegos es posible comprar, descargar e instalar juegos para tanto para Windows, macOS y también para GNU/Linux. Steam y Valve han posibilitado que se puedan jugar a varios juegos triple A en GNU/Linux, Valve se está esforzando para que muchos juegos sean jugables en la plataforma del pingüino.

Steam ofrece un cliente nativo para GNU/Linux que en Arch Linux se ofrece en los repositorios oficiales. Requiere además habilitar el repositorio multilib para paquetes de 32 bits e instalar el controlador gráfico de la tarjeta gráfica de 32 bits.

1
$ sudo pacman -S steam

Para habilitar el repositorio multilib en Arch Linux hay que editar el archivo de configuración /etc/pacman.conf y descomentar varias líneas quitando el caracter # que las precede.

1
2
3
4
...
[multilib]
Include = /etc/pacman.d/mirrorlist
...

En el caso de un gráfica Intel hay que instalar el paquete lib32-mesa.

1
$ sudo pacman -S lib32-mesa

Hecho esto se puede iniciar el cliente, en el menú de aplicaciones del sistema aparecen su acceso directo de aplicación, se necesita una cuenta por que lo que hay que registrarse antes desde su plataforma web. Los juegos de la biblioteca aparecen en el cliente para instalar. En este caso tengo el juego Company of Heroes 2.

Cliente de Steam en GNU/Linux

Instalado el juego se puede iniciar desde el cliente de Steam. Aún con una gráfica integrada Intel de un Intel NUC8i5BEK (Bean Canyon) se pueden jugar a muchos juegos bajando algo los detalles y resolución.

Company of Heroes 2

Los juegos ofrecen diferente nivel de soporte para GNU/Linux, para Windows, macOS y Steam+Linux, los que deben funcionar sin problema son los de la última categoría. Los de Windows pueden funcionar a través de una capa de emulación desarrollada por Steam, para activarla hay que ir a Steam > Parámetros > Steam Play y activar las opciones Enable Steam Play for Supported title y Activar Steam para todos los demás títulos. Sin embargo, no hay garantía que los juegos con solo soporte de Windows funcionen correctamente, he probado con World of Warships y no se iniciaba correctamente mostrando únicamente una pequeña ventana negra.

Steam Play Settings

De vez en cuando Steam ofrece juegos gratuitos que se pueden añadir libremente a la biblioteca y en ocasiones ofrece grandes descuentos. También a través de su propio cliente es posible jugar a los juegos de Blizzard como Diablo 3, aunque en este caso es necesario utilizar Wine.

» Leer más, comentarios, etc...

Picando Código

Pronunciamiento de la Red de Gobierno Abierto en el marco del ciclo electoral en Uruguay 2019-2020

septiembre 04, 2019 03:00

Desde DATA Uruguay, como miembros de la Red de Gobierno Abierto, difunden el siguiente pronunciamiento y nos invitan a leer y adherir al mismo:

Red de Gobierno Abierto

Uruguay vive en este 2019 un nuevo ciclo electoral que renovará la integración del Poder Ejecutivo y el Poder Legislativo. En medio de una intensa campaña electoral y ante un cambio de gobierno, las organizaciones integrantes de la Red de Gobierno Abierto nos pronunciamos frente a los candidatos a la presidencia representantes de todos los partidos políticos en competencia, en virtud de defender la implementación del paradigma de gobierno abierto como un eje transversal en el diseño, monitoreo e implementación de políticas públicas.

El gobierno abierto no es algo novedoso para nuestro país. Se instala en una experiencia de más de diez años, con la aprobación de la Ley de Acceso a la Información Pública en 2008 y, posteriormente, la incorporación de Uruguay a la Alianza por el Gobierno Abierto (AGA) en el año 2012.

Además de estos y otros hitos, se enmarca en una larga tradición democrática y de participación ciudadana, que hace de Uruguay un país con más de 968 ámbitos de participación identificados (1), en los más variados ámbitos y niveles de gobierno.

El proceso, comenzado en 2012 a partir de la incorporación de nuestro país a la AGA, implica principalmente la generación de Planes de Acción de Gobierno Abierto cada dos años, co-creados entre actores públicos, de sociedad civil, academia y sector privado. En los cuatro planes publicados hasta hoy, se ha logrado no sólo asumir compromisos significativos y lograr un buen nivel de cumplimiento, sino también madurar e institucionalizar el proceso de creación, a través de herramientas como el Grupo de Trabajo de Gobierno Abierto (donde la Red de Gobierno Abierto participa desde la sociedad civil), la inclusión presupuestal de estos procesos y un significativo esfuerzo por transformar las prácticas de trabajo en el Estado para incluir los principios de transparencia, participación, colaboración y co-creación. Testimonio de este avance es que el plan vigente para Uruguay es el único que fue evaluado como 100% co-creado, entre los 79 países de la alianza.

El éxito y el reconocimiento internacional que nuestro país ha obtenido en virtud de este proceso es un mérito compartido por un amplio grupo de organizaciones, provenientes de los más diversos ámbitos, cuya participación ha fortalecido notoriamente el proceso de gobierno abierto en Uruguay. Esta multiplicidad de actores también evidencia el valor de instancias colaborativas al servicio del diseño, monitoreo e implementación de políticas públicas en todas las temáticas.

A quienes a partir del año próximo tendrán la responsabilidad de gobernar el país, les invitamos a expresar su compromiso a mantener y profundizar en un futuro gobierno el camino recorrido en este sentido, a través de la continuidad del trabajo en el marco de la AGA, y la institucionalidad generada en el país alrededor del Grupo de Trabajo de Gobierno Abierto.

Pero sobre todo, exhortamos al más profundo compromiso ético con lo que representa un gobierno abierto y sus valores más básicos: transparencia, participación y disposición al trabajar en colaboración con la más grande pluralidad de actores.

Podes sumarte a este pronunciamiento acá

» Leer más, comentarios, etc...

Picando Código

DataCamp – Comprendiendo los datos abiertos: infografías, historias e interactivos

septiembre 03, 2019 11:11

AGESIC organiza el evento “Datos 360° Una visión integral para la gestión de los datos en el Estado”, un evento que incluye dos días de jornadas y un DataCamp:

Desde hace algunos años Agesic trabaja a partir de una “visión de datos 360°”, es decir, un enfoque holístico del uso de los datos en el Estado que incorpora distintas perspectivas, como la Protección de Datos Personales, la gestión e integración de datos y la Seguridad de la Información. El objetivo de esta iniciativa es alcanzar una concepción sistémica de la temática, optimizar la gestión de datos en la Administración Pública y buscar eficiencia al momento de generar, compartir y gestionar los datos por parte de los organismos públicos.

Análisis, Visualizaciones, Mapas, Storytelling y más de la mano de expertos nacionales e internacionales en el DataCamp:

DataCamp - Comprendiendo los datos abiertos: infografías, historias e interactivos

Datacamp: Es un espacio de experimentación y aprendizaje. Los participantes aprenden cómo encontrar, extraer y analizar datos públicos usando herramientas forenses para contar mejores historias periodísticas. Brinda a los periodistas, activistas cívicos y desarrolladores, un curso acerca de las técnicas más importantes y las herramientas necesarias para analizar datos públicos. Los participantes también trabajan en equipos para construir nuevas aplicaciones de noticias y sitios de participación cívica que ayuden a mejorar el valor de los reportajes tradicionales.

La actividad está dirigida a estudiantes y técnicos vinculados con áreas de comunicación, diseño, informática e investigación que necesiten aprender sobre el manejo de herramientas para la depuración de grandes cantidades de datos y su tratamiento para la generación de contenidos, investigaciones periodísticas y visualizaciones.

Inscripciones

Más información

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Take Command 25

septiembre 03, 2019 03:01

Desde hace décadas que me encanta, y que uso diariamente Take Command de Rex Conn and JP Software Inc.. Os hablé recientemente de Cosas interesantes con Take Command, y también de Resaltado de sintaxis en Take Command. En esta nueva versión 25, los cambios visibles para el usuario son pocos, si bien Rex nos dice …

Take Command 25 Leer más »

Artículo publicado originalmente en Bitácora de Javier Gutiérrez Chamorro (Guti)

La entrada Take Command 25 aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

» Leer más, comentarios, etc...

Picando Código

Horizon Chase Turbo – Nintendo Switch

septiembre 03, 2019 01:30

Horizon Chase Turbo es un juego de carreras inspirado en los grandes hits de los 80’s y 90’s: Out Run, Lotus Turbo Challenge, Top Gear (SNES), Rush, entre otros. Cada curva y cada vuelta en Horizon Chase Turbo recrea el clásico gameplay de arcade y ofrece diversión sin límites de velocidad. Es desarrollado por el estudio brasilero Aquiris Game Studio, de Porto Alegre 🇧🇷

Horizon Chase Turbo

Desde que me enteré que Horizon Chase Turbo se iba a publicar en Nintendo Switch, lo quise jugar. Pero algo no me termina de convencer al considerar comprar los juegos en formato digital. ¿Y si mañana el proveedor cierra la tienda online y por alguna razón los juegos se pierden? Esto ya ha pasado en algunas plataformas, con el cartucho o disco no se pierden los datos. En fin, en un AMA de Reddit con los desarrolladores del juego me enteré que habría una versión física en Switch. Así que me aguanté, pero lo esperé con mucha anticipación y expectativa. Recientemente llegó a mis manos y mis expectativas se vieron totalmente colmadas.

Cuando era un pequeñejo fanboy de Nintendo (ahora soy un fanboy de Nintendo viejo y peludo), jugaba mucho Top Gear el Super Nintendo en la casa de un amigo. Jugábamos de todo, pero el Top Gear era genial. Se podía jugar de a dos a pantalla dividida, tenía un estilo muy particular, y pasábamos las horas memorizando las pistas, esquivando oponentes, y compitiendo por salir primeros. La saga tuvo un par de títulos más en el Super Nintendo con Top Gear 2 y Top Gear 3000. Pero a pesar de haber sido desarrollados por el mismo equipo, no tenían (al menos para mí) el mismo atractivo del original.

Top Gear fue desarrollado por el mismo estudio responsable de la saga de carreras Lotus para Amiga, que después llegaría a otras plataformas como Amstrad, Atari, Commodore 64 y Spectrum. Con buscar y ver algunos videos de esos títulos, nos damos cuenta que siguen el mismo estilo y reutilizan gráficos entre uno y otro. Escribiendo esto me acordé que ¡Top Gear también tuvo su port para Game Boy Color! No recuerdo cómo ni cuándo, pero llegué a jugarlo… Con las limitaciones de hardware se imaginarán que no fue un título tan memorable, aunque lo recuerdo con cariño.

Una parte importantísima del Top Gear de SNES, es la banda sonora. La música fue compuesta por el compositor escocés Barry Leitch. Las canciones quedaron grabadas en mi memoria, y cada tanto me acordaba de Top Gear y escuchaba el OST online. Desde la pantalla de inicio del juego, las melodías son espectaculares, con un estilo muy particular y pegadizo. De repente ésto era parte de lo que le faltaba al Top Gear 2 y 3000, porque Leitch no volvió a la saga hasta Top Gear Rally para Nintendo 64 en 1997.

También jugué Top Gear Rally en su momento, pero era otra cosa. Al comprar mi Nintendo 64, Top Gear Rally 2 fue uno de los primeros juegos que compré. Si bien eran disfrutables, repito que nunca se recuperó esa magia del primero que jugué. Pero todo esto cambió con Horizon Chase Turbo.

No sólo se inspira en los títulos mencionados, es un homenaje y sucesor espiritual de éstas sagas hecho por personas que obviamente las disfrutaron y las respetan mucho. Este juego trae Top Gear a 2019 con un montón de cosas nuevas:

  • Gráficos e interfaz modernos
  • Pantalla dividida estilo vieja escuela para hasta 4 jugadores (necesito gente con quién jugar…)
  • Música por Barry Leitch 🙌 🙇‍♂️, Diseñador de Sonido de clásicos de los 90s como Top Gear y Lotus Turbo Challenge, entre otros
  • Muchísimo contenido: 12 copas, 48 ciudades, 109 pistas, 31 coches desbloqueables y 12 mejoras para los autos
  • Modo en línea competitivo
  • Leaderboards globales y entre amigos

El campeonato arranca en California, que nos puede traer memorias del San Francisco Rush de los arcades y Nintendo 64. Pero el siguiente circuito de pistas se va a Chile. Y ahí cuando arranqué la carrera en “La Capital”, me emocioné. La canción que se escucha es una reinterpretación del tema de la introducción de Top Gear para Super Nintendo:

¡Gracias Barry Leitch por volver y componer la música para el juego! Pueden seguir a Barry Leitch en Twitter, y ver algunas entrevistas durante el desarrollo de Horizon Chase desde su twitter o desde el de Horizon Chase. Además de compartir algunas cosas de la composición, podemos ver joyitas como el tema “Baw’s tae the wa'” (del escocés: “balls to the wall”), y detalles que no se pueden percibir en la mezcla final.

“Fernando, ¡dejá de abrir la boca y emocionarte con la canción y prestá atención que te estás yendo para afuera de la pista!” gritaba mi subconciente. Pero por suerte podemos reiniciar la carrera si nos está yendo demasiado mal.

El estilo de juego es básicamente el mismo que en los 16 bits. Elegimos nuestro auto basado en la aceleración, velocidad máxima, capacidad de combustible, maniobrabilidad, y le damos a las carreras. Hay que ir esquivando a los contrincantes que nos hacen chocar e ir más lento. También tenemos gasolina y nitro sueltos por la pista para recuperarnos, y unas fichas que nos dan más puntaje.

Tiene varios detalles como los globitos de cómic saliendo del chofer en distintas situaciones a lo Top Gear. En uno de los globitos, el personaje hace un comentario que podría interpretarse como que rompe la cuarta pared, dándonos a creer que es el mismo conductor de siempre…

Las pistas son entretenidas y dan para jugarlas más de una vez. Ya sea porque no salimos primeros, porque nos faltó recolectar todos los ítemos para ganar un Súper trofeo o simplemente porque la disfrutamos mucho y queremos volver a correr.

Tiene el modo de juego World Tour, que es el clásico ir corriendo carreras y desbloqueando circuitos nuevos. Los demás hay que desbloquearlos ganando carreras en World Tour. Playground, con distintos retos y limitaciones, y carreras en las que se puede competir online. Tournament es una competición de a 4 carreras a la vez, y el último modo es Endurance Mode en el que elegimos un auto y hay que correr ciertas carreras sin actualizacionesa los autos. Las actualizaciones se obtienen desbloqueando circuitos “de actualización” y ganándolos. Esto nos permite elegir entre 3 distintas actualizaciones cada vez.

Horizon Chase Turbo está disponible también en Steam para Linux, Mac OS y Windows, XBox One y PlayStation 4. ¡Gracias Aquiris por desarrollar este juego! Ya es uno de mis títulos preferidos de Nintendo Switch.

YouTube Video

» Leer más, comentarios, etc...

Picando Código

Gamesdb – Gema Ruby para la API de TheGamesDB

septiembre 02, 2019 03:00

El sábado pasado pensaba irme de aventuras por algún castillo de Escocia. Pero me desperté con un dolor de garganta tremendo que se transformó en resfrío y no me dejó salir todo el fin de semana. Qué mejor que ponerme a programar y actualizar una de mis gemas Ruby…

GamesDB

TheGamesDB es una base de datos online de videojuegos. El sitio sirve como servicio frontend que se enlaza a una base de datos de metadata de videojuegos y arte de alta calidad. La base de datos puede ser usada en varias aplicaciones a través de su API (PC’s como centro multimedia, emuladores, etc.). Se pueden buscar juegos, plataformas, arte, y más.

En 2014 empecé un proyecto personal en el que quería usar datos de TheGamesDB. En ese entonces existía una gema para interactuar con la API, pero ya no se actualizaba hacía casi 2 años en el momento. Tampoco me gustaba cómo manejaba la respuesta de la API, así que decidí implementar una gema de cero: gamesdb. Recientemente, la API migró a un diseño completamente nuevo. La API anterior había pasado a modo legacy. El año pasado ya la había actualizado a los nuevos endpoints pero tenía pendiente migrar a la versión actual. Finalmente la API legacy se descontinuó, así que no me quedó opción que actualizar el código sino la gema era completamente inútil.

Una de las cosas buenas de la API actualizada es que la respuesta viene en formato JSON en vez de XML. Así que entre otras cosas, la gema tiene una dependencia menos (además de ser más fácil de parsear la información que recupera). También decidí publicar la versión 1.0, esa versión que tanto me cuesta etiquetar porque no considero nada “lo suficientemente estable”. Pero al haber cambiado la API, todo lo escrito en las versiones anteriores ya no funcionaba, así que qué más da. De todas formas la seguiré actualizando. Todavía hay varios endpoints por implementar, en principio sólo implementé los que necesitaba para mi proyecto. Pero eventualmente voy a escribir todos los casos que provee la API.

Como siempre, es interesante volver a código que escribí hace años, y ver cómo escribiría un montón de cosas distintas hoy. Y seguro las escribiría de otra forma dentro de uno o dos años.

El fin de semana me concentré en reimplementar las cosas para que funcionen con la actualización, corregir los tests y que los builds pasen. Pero me anoté varias cosas para hacer refactoring a futuro.

Espero algún día terminar el proyecto que me hizo escribir esta gema, y si es así, ¡lo compartiré por acá también!

El código fuente de la gema: https://github.com/picandocodigo/gamesdb

» Leer más, comentarios, etc...

Blog Bitix

Ejemplo sencillo de como crear un documento PDF con Java y PDFBox

agosto 30, 2019 10:15

Leer un CSV, escribir un CSV, archivos excel, generar gráficas para visualizar datos junto con generar documentos PDF son tareas comunes de las aplicaciones como forma de exportar los datos de la base de datos de una aplicación. Generar un archivo PDF con PDFBox requiere unas pocas lineas de código para documentos con cierta complejidad quizá sea más adecuado usar la librería JasperReports.

Java

Generar documentos e informes de salida en una una tarea básica de cualquier aplicación y una forma de exportar los datos a otros formatos. Con Apache POI se pueden generar hojas de cálculo excel para su procesamiento con LibreOffice o Microsoft Office Excel. En ocasiones también es necesario generar gráficas para visualizar un conjunto grande de datos para ser más fáciles de interpretar, descubrir tendencias, comparar, sacar conclusiones en base a las cuales tomar alguna acción. Los archivos PDF también son muy utilizados para imprimirlos en formato en papel o enviarlos adjuntos en correos electrónicos.

Uno de estos casos podría ser la generación de una factura en base a una plantilla e incluir el el importe y consumo realizado por un cliente y que este pueda obtenerla en formato electrónico o le sea enviada por correo electrónico como un documento adjunto o enviar un correo electrónico para indicar que tiene la factura disponible en su área de cliente lista para su descarga. Este es el caso de muchas empresas que ofrecen servicios como compañías eléctricas, de telecomunicaciones, servicios municipales de agua y basura, bancos para su justificantes y comprobantes, comercios, etc…

Para generar documentos en PDF en Java está disponible la librería Apache PDFBox. Un ejemplo sencillo de como generar un archivo PDF con algunos estilos de texto, fuentes, un tamaño específico de página y una imagen es el siguiente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package io.github.picodotdev.blogbitix.javapdf;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
public class Main {
public static void main(String[] args) throws Exception {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A6);
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// Text
 contentStream.beginText();
contentStream.setFont(PDType1Font.TIMES_BOLD, 32);
contentStream.newLineAtOffset( 20, page.getMediaBox().getHeight() - 52);
contentStream.showText("Hello World!");
contentStream.endText();
// Image
 PDImageXObject image = PDImageXObject.createFromByteArray(document, Main.class.getResourceAsStream("/java.png").readAllBytes(), "Java Logo");
contentStream.drawImage(image, 20, 20, image.getWidth() / 3, image.getHeight() / 3);
contentStream.close();
document.save("document.pdf");
}
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
plugins {
id 'java'
id 'application'
}
application {
mainClassName = 'io.github.picodotdev.blogbitix.javapdf.Main'
}
repositories {
jcenter()
}
dependencies {
compile 'org.apache.pdfbox:pdfbox:2.0.16'
}

El resultado es el siguiente Documento PDF.

Documento generado con PDFBox

Una alternativa a PDFBox es iText, la primera tiene una licencia Apache e iText una licencia AGPL o comercial lo que puede ser determinante para un proyecto. La licencia AGPL obliga a que una aplicación web haga público su código fuente lo que probablemente en usos comerciales no sea lo deseado y usar la versión de la licencia comercial obliga a adquirir el derecho de uso al que obliga la licencia que posee un coste tal vez indeseado o que directamente hace que quede descartada.

PDFBox no posee una forma de escribir párrafos y tener saltos de línea automáticos según el ancho de la página, en el ejemplo el texto se posiciona de forma absoluta en la página estando la coordenada (0,0) en la parte inferior izquierda. Para añadir esta funcionalidad a PDFBox hay que usar el complemento pdfbox-layout.

Pero en vez de crear un documento PDF desde cero desde Java si se trata de una factura es más sencillo partir de un documento PDF a modo de plantilla con el diseño deseado en el que solo haya que incluir la información que varía en la ubicación del documento apropiada. Este sería en caso de una factura o justificante. Y si el documento es un informe con muchos datos o el diseño se desea cambia independientemente de la información que incluye o es complejo en vez de insertar cada campo de texto e imágenes individualmente con código está la opción de utilizar el generador de documentos JasperReports.

En el siguiente tutorial de PDFBox se incluyen más ejemplos de tareas básicas al procesar documentos PDF con esta librería.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

» Leer más, comentarios, etc...

Blog Bitix

Ejemplo sencillo de como crear un documento PDF con PDFBox

agosto 30, 2019 04:00

Leer un CSV, escribir un CSV, archivos excel, generar gráficas para visualizar datos junto con generar documentos PDF son tareas comunes de las aplicaciones como forma de exportar los datos de la base de datos de una aplicación. Generar un archivo PDF con PDFBox requiere unas pocas lineas de código para documentos con cierta complejidad quizá sea más adecuado usar la librería JasperReports.

Java

Generar documentos e informes de salida en una una tarea básica de cualquier aplicación y una forma de exportar los datos a otros formatos. Con Apache POI se pueden generar hojas de cálculo excel para su procesamiento con LibreOffice o Microsoft Office Excel. En ocasiones también es necesario generar gráficas para visualizar un conjunto grande de datos para ser más fáciles de interpretar, descubrir tendencias, comparar, sacar conclusiones en base a las cuales tomar alguna acción. Los archivos PDF también son muy utilizados para imprimirlos en formato en papel o enviarlos adjuntos en correos electrónicos.

Uno de estos casos podría ser la generación de una factura en base a una plantilla e incluir el el importe y consumo realizado por un cliente y que este pueda obtenerla en formato electrónico o le sea enviada por correo electrónico como un documento adjunto o enviar un correo electrónico para indicar que tiene la factura disponible en su área de cliente lista para su descarga. Este es el caso de muchas empresas que ofrecen servicios como compañías eléctricas, de telecomunicaciones, servicios municipales de agua y basura, bancos para su justificantes y comprobantes, comercios, etc…

Para generar documentos en PDF en Java está disponible la librería Apache PDFBox. Un ejemplo sencillo de como generar un archivo PDF con algunos estilos de texto, fuentes, un tamaño específico de página y una imagen es el siguiente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package io.github.picodotdev.blogbitix.javapdf;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
public class Main {
public static void main(String[] args) throws Exception {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A6);
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// Text
 contentStream.beginText();
contentStream.setFont(PDType1Font.TIMES_BOLD, 32);
contentStream.newLineAtOffset( 20, page.getMediaBox().getHeight() - 52);
contentStream.showText("Hello World!");
contentStream.endText();
// Image
 PDImageXObject image = PDImageXObject.createFromByteArray(document, Main.class.getResourceAsStream("/java.png").readAllBytes(), "Java Logo");
contentStream.drawImage(image, 20, 20, image.getWidth() / 3, image.getHeight() / 3);
contentStream.close();
document.save("document.pdf");
}
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
plugins {
id 'java'
id 'application'
}
application {
mainClassName = 'io.github.picodotdev.blogbitix.javapdf.Main'
}
repositories {
jcenter()
}
dependencies {
compile 'org.apache.pdfbox:pdfbox:2.0.16'
}

El resultado es el siguiente Documento PDF.

Documento generado con PDFBox

Pero en vez de crear un documento PDF desde cero desde Java si se trata de una factura es más sencillo partir de un documento PDF a modo de plantilla con el diseño deseado en el que solo haya que incluir la información que varía en la ubicación del documento apropiada. Este sería en caso de una factura o justificante. Y si el documento es un informe con muchos datos o el diseño se desea cambia independientemente de la información que incluye o es complejo en vez de insertar cada campo de texto e imágenes individualmente con código está la opción de utilizar el generador de documentos JasperReports.

En el siguiente tutorial de PDFBox se incluyen más ejemplos de tareas básicas al procesar documentos PDF con esta librería.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

» Leer más, comentarios, etc...

Blog Bitix

Utilizar credenciales de conexión a la base de datos generadas por Vault en una aplicación de Spring

agosto 23, 2019 07:00

Spring Cloud Vault facilita la integración con Vault, una de sus usos es utilizarlo para obtener unas credenciales de conexión a la base de datos generadas bajo demanda y con un tiempo de vida limitado en vez de embeberlas en la configuración de la aplicación y con u tiempo de vida indefinido.

Spring
Vault

La herramienta Vault de HashiCorp permite almacenar secretos, otra de sus funcionalidad es ser capaz de generar credenciales de forma dinámica. Habitualmente una aplicación para conectarse a una base de datos incluye en su configuración las credenciales, usuario y contraseña, para autenticarse y crear las conexiones, estas credenciales tiene un tiempo de vida indefinido y comprometidas proporcionan acceso a la base de datos.

Vault permite centralizar la seguridad, otorgar a cada aplicación los permisos para conectarse a una base de datos a través de la obtención de credenciales (usuario y contraseña), auditar su uso y limitar el tiempo de validez de las credenciales a unas horas en vez de forma indefinida.

Spring Cloud Vault permite a una aplicación Spring simplificar la integración con Vault para obtener unas credenciales generadas dinámicamente.

En el archivo de contrucción de la aplicación hay que incluir las dependencias de Spring para la integración con Vault.

1
2
3
4
5
...
implementation('org.springframework.cloud:spring-cloud-starter-config', excludeSpringBootStarterLogging)
implementation('org.springframework.cloud:spring-cloud-starter-vault-config', excludeSpringBootStarterLogging)
implementation('org.springframework.cloud:spring-cloud-vault-config-databases', excludeSpringBootStarterLogging)
...

Obtener la credenciales de conexión a la base de datos es transparente para el código de la aplicación, lo único que se necesita es el usuario y contraseña además de la URL de conexión.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package io.github.picodotdev.blogbitix.springcloudvault;
...
@SpringBootApplication
public class Main implements CommandLineRunner {
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Override
public void run(String... args) {
System.out.printf("Username: %s%n", username);
System.out.printf("Password: %s%n", password);
try (Connection connection = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/app", username, password)) {
if (connection != null) {
System.out.println("Connected to the database!");
} else {
System.out.println("Failed to make connection!");
}
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Main.class, args);
}
}
1
2
3
4
5
6
...
10:37:47.013 [main] INFO io.github.picodotdev.blogbitix.springcloudvault.Main - Started Main in 1.368 seconds (JVM running for 1.784)
Username: v-approle-app-gRlHQlNyPF8qJ3DCUz9U-1566549466
Passowrd: A1a-MPPFfvMD3OQUC00H
Connected to the database!
...

La parte más relevante está en la configuración necesaria de la aplicación. Hay que añadir como configuración la ubicación del servidor Vault, es necesario configurar un método de autenticación para Vault, para el caso de aplicaciones el recomendado es AppRole. Con AppRole cada aplicación necesita de un role-id y un secret-id que hay que generar previamente. Y el rol del que obtener las credenciales, app.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
spring.application.name: app
spring.cloud.vault:
 uri: http://127.0.0.1:8200
 authentication: APPROLE
 app-role:
 role-id: a248529d-882c-ef5f-f7e6-6a9d349afa57
 secret-id: 1ce82723-0f98-f885-9784-3d65d910350b
 database:
 enabled: true
 role: app
 backend: database
 username-property: spring.datasource.username
 password-property: spring.datasource.password

Para probarlo hay que iniciar en este caso el servidor Consul ya que en el ejemplo se utiliza como el lugar donde se guardan los secretos. También hay que iniciar Vault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ consul agent -dev
==> Starting Consul agent...
==> Consul agent running!
Version: 'v1.5.0'
Node ID: '2f523068-b196-e3bb-0b09-dc34e20989d2'
Node name: 'archlinux'
Datacenter: 'dc1' (Segment: '<all>')
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)
Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ vault server -dev -config vault.hcl
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: true, enabled: false
Storage: consul (HA available)
Version: Vault v1.1.1
Version Sha: a3dcd63451cf6da1d04928b601bbe9748d53842e
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variable:
$ export VAULT_ADDR='http://127.0.0.1:8200'
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: jsBAedtA88Lm7uU1pCSYOBK1980Ervf9GSky4usmEdQ=
Root Token: s.8wwm4fRuRRVFm1cbBUMgdNtE
Development mode should NOT be used in production installations!
1
2
3
4
5
6
ui = true
storage "consul" {
address = "127.0.0.1:8500"
path = "vault"
}

La base de datos postgres se inicia como un contenedor de Docker.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ docker run --rm -it -p "5432:5432" -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres postgres:alpine
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8fedf0ef1342 postgres:alpine "docker-entrypoint.s…" 22 seconds ago Up 20 seconds 0.0.0.0:5432->5432/tcp serene_leavitt
$ docker exec -it 8fedf0ef1342 bash
bash-5.0# psql -U postgres
psql (11.4)
Type "help" for help.
postgres=# CREATE DATABASE app;
CREATE DATABASE
postgres=#

Para realizar la configuración de Vault primero hay que iniciar sesión, en el modo desarrollo del ejemplo utilizando el token root que es generado y emitido en la salida al iniciarlo.

1
2
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ vault login s.8wwm4fRuRRVFm1cbBUMgdNtE

Como en el artículo Generar credenciales de conexión a base de datos bajo demanda con Vault hay que activar el backend de database para generar credenciales de bases de datos, en las que básicamente se especifica la cadena de conexión a la base de datos de postgres con un usuario y contraseña con permisos suficientes para crear usuarios y la sentencia SQL que los crea. Se habilita y configura el backend database del que obtener las credenciales.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ vault secrets enable database
$ vault write database/config/app \
 plugin_name=postgresql-database-plugin \
 allowed_roles="app" \
 connection_url="postgresql://{{username}}:{{password}}@localhost:5432/?sslmode=disable" \
 username="postgres" \
 password="postgres"
$ vault write database/roles/app \
 db_name=app \
 creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
 default_ttl="1h" \
 max_ttl="24h"

Para que la aplicación de Spring Boot obtenga las credenciales ha de autenticarse en Vault en este caso utilizando el método recomendado para las aplicaciones que es utilizando en mecanismo de autenticación AppRole que básicamente es un usuario y contraseña para las aplicaciones.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ vault auth enable approle
$ vault write auth/approle/role/app \
 secret_id_ttl=10m \
 token_num_uses=10 \
 token_ttl=20m \
 token_max_ttl=30m \
 secret_id_num_uses=40 \
 policies=database-app
$ vault read auth/approle/role/app/role-id
Key Value
--- -----
role_id a248529d-882c-ef5f-f7e6-6a9d349afa57
$ vault write -f auth/approle/role/app/secret-id
Key Value
--- -----
secret_id 13b6c224-dc18-0404-7bc1-7c258c4c5a48
secret_id_accessor fd9a0915-af6e-b0a8-4e6c-dbb6ee587903

En Vault los permisos se otorgan con las policy, los secretos se organiza en una estructura jerárquica de directorios y a cada una de los contextos se le otorga los permisos deseados. Spring obtiene las credenciales para la base de datos del contexto database/creds/app por lo que al rol utilizando para obtener las credenciales hay que asocialer un policy con permisos de lectura para este contexto.

1
$ vault policy write database-app database-app.hcl
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
path "secret/application" {
capabilities = ["read"]
}
path "secret/app" {
capabilities = ["read"]
}
path "database/creds/app" {
capabilities = ["read"]
}

Obtenido un role-id y un secret-id so observa los policies asociados además de otras propiedades.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ vault write auth/approle/login role_id=a248529d-882c-ef5f-f7e6-6a9d349afa57 secret_id=13b6c224-dc18-0404-7bc1-7c258c4c5a48
Key Value
--- -----
token s.yAKbv8Qz5tfXpc8n7C8oND01
token_accessor GPHO70D2NFRHFFdsiNiftmzO
token_duration 20m
token_renewable true
token_policies ["database-app" "default"]
identity_policies []
policies ["database-app" "default"]
token_meta_role_name app

En este caso la aplicación de Spring incluye en su configuración las credenciales del AppRole, también se puede proporcionar como variables de entorno y propiedades del sistema.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub.

» Leer más, comentarios, etc...

Metodologías ágiles. De lo racional a la inspiración.

Marco Scrum

agosto 19, 2019 04:53

Marco de Scrum Curso de Scrum: Contactanos si estás interesado. ¡Aquí puedes ver el último video sobre Scrum en 9 minutos que hemos publicado!

» Leer más, comentarios, etc...

Blog Bitix

Generar credenciales de conexión a base de datos bajo demanda con Vault

agosto 15, 2019 07:00

Una de las funcionalidades proporcionada por Vault es generar credenciales dinámicas para la conexión a bases de datos. Generar las credenciales de forma dinámica proporciona varios beneficios: no hay unas credenciales que usen las aplicaciones que tengan un tiempo de vida indefinido, las aplicaciones no necesitan guardar en su configuración las credenciales, las credenciales se rotan de forma automática y los permisos para obtenerlas se pueden revocar de forma centralizada con Vault para cuales quiera bases de datos que se utilicen. Soporta las bases de datos más populares entre ellas postgres.

Vault
PostgreSQL

Las base de datos para proteger los datos realizan autenticación del usuario que se conecta. Normalmente utilizando un usuario y contraseña, una vez autenticado el usuario mediante permisos se realiza la autorización de las operaciones que puede realizar, a que bases de datos se puede conectar, que tablas puede acceder y que operaciones puede realizar.

Este modelo de autenticación tiene algunos inconvenientes. Uno de los inconvenientes es que los usuarios y contraseñas para mayor seguridad han de cambiarse con cierta frecuencia para evitar que si las credenciales quedan comprometidas no puedan utilizarse indefinidamente. Otro problema es que cada aplicación ha de conocer las credenciales de la base de datos, esto hace que haya múltiples posibilidades de que las credenciales queden comprometidas. Por otro lado el uso de las credenciales no queda registrado de forma centralizada que es necesario para saber ante una brecha de seguridad qué datos han sido accedidos y por quien.

La herramienta Vault de HashiCorp da solución a estos problemas generando credenciales de acceso a las bases de datos de forma dinámica, bajo demanda y con un tiempo de concesión limitado. Las credenciales tiene un tiempo de vida limitado si no se renueva su concesión y la generación de las credenciales queda registrado. La forma que tiene Vault de generar credenciales de forma dinámica en una base de datos relacional como postgres es conectarse a la base de datos con un usuario con permisos para generarlas y ejecutar una sentencia SQL que crea las credenciales.

Para permitir a Vault generar credenciales de conexión hay que activar el backend de bases de datos, configurarlo con la sentencia SQL que se utilizará para generar las credenciales y crear el rol de Vault que genera las credenciales cuando se le solicite. En este ejemplo se muestra para la base de datos postgres pero Vault también soporta otras bases de datos como MySQL. En el ejemplo la base de datos postgres se ejecuta en un contenedor de Docker en el que se asignan el usuario y contraseña del usuario root que utiliza Vault para generar las credenciales de forma dinámica.

Con las siguientes comandos se inicia Consul y Vault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ consul agent -dev
==> Starting Consul agent...
==> Consul agent running!
Version: 'v1.5.0'
Node ID: '38d4f541-0958-6d7d-d49e-a31a15987286'
Node name: 'archlinux'
Datacenter: 'dc1' (Segment: '<all>')
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)
Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ vault server -dev -config vault.hcl
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: true, enabled: false
Storage: consul (HA available)
Version: Vault v1.1.1
Version Sha: a3dcd63451cf6da1d04928b601bbe9748d53842e
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variable:
$ export VAULT_ADDR='http://127.0.0.1:8200'
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: jeW10eak6TxJzH2qFnwk7bWk7HcpDXd3KQOobi1rZTQ=
Root Token: s.0YRcRzojVcPG8LbbzyUd1MEA
Development mode should NOT be used in production installations!
1
2
3
4
5
6
ui = true
storage "consul" {
address = "127.0.0.1:8500"
path = "vault"
}

La base de datos se inicia en un contenedor de Docker, se crea una base de datos y una tabla.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ docker run -it -p "5432:5432" -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres postgres:alpine
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2792b13c36c1 postgres:alpine "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:5432->5432/tcp distracted_keldysh
$ docker exec -it 2792b13c36c1 bash
bash-5.0# psql -U postgres
psql (11.4)
Type "help" for help.
postgres=# CREATE DATABASE app;
postgres=# \connect app
You are now connected to database "app" as user "postgres".
app=# CREATE TABLE product (
id bigint PRIMARY KEY,
name varchar(256) NOT NULL
);
app=# \dt
List of relations
Schema | Name | Type | Owner
--------+---------+-------+----------
public | product | table | postgres
(1 row)
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 2792b13c36c1
172.17.0.2

En Vault hay que crear la configuración para conectarse a la base de datos y un rol que contiene la configuración para generar las credenciales y permitir obtenerlas, básicamente es un sentencia SQL con el nombre del usuario y contraseña, los permisos que se le asignan y el tiempo de concesión.

1
2
3
$ export VAULT_ADDR=http://127.0.0.1:8200
$ vault login s.0YRcRzojVcPG8LbbzyUd1MEA
$ vault secrets enable database
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ vault write database/config/app \
 plugin_name=postgresql-database-plugin \
 allowed_roles="app" \
 connection_url="postgresql://{{username}}:{{password}}@localhost:5432/?sslmode=disable" \
 username="postgres" \
 password="postgres"
$ vault write database/roles/app \
 db_name=app \
 creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
 default_ttl="1h" \
 max_ttl="24h"

Las credenciales se generan en el momento de leer una propiedad de Vault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ vault read database/roles/app
Key Value
--- -----
creation_statements [CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";]
db_name app
default_ttl 1h
max_ttl 24h
renew_statements []
revocation_statements []
rollback_statements []
$ vault read database/creds/app
Key Value
--- -----
lease_id database/creds/app/rFFlNmpNoxezccTVh3WufZOT
lease_duration 1h
lease_renewable true
password A1a-6hRTGNaShFIEGLvp
username v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370

En postgres la conexión desde la máquina local se permiten sin necesidad de credenciales, para simular realizar la conexión desde otra máquina hay que iniciar otro contenedor. En la conexión se utilizan las credenciales que ha proporcionado Vault. Dado que se realiza una operación de red hay que desactivar el firewall del sistema o permitir la conexión al puerto de la base de datos que en postgres es el 5432 si fuera necesario. Listando los usuarios de la base de datos con el comando \du se muestra el creado por Vault y si tiempo de validez.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ docker run -it postgres:alpine bash
bash-5.0# PGPASSWORD=A1a-6hRTGNaShFIEGLvp psql -U v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370 -h 172.17.0.2 -d app
psql (11.4)
Type "help" for help.
app=> \dt
List of relations
Schema | Name | Type | Owner
--------+---------+-------+----------
public | product | table | postgres
(1 row)
app=# \du
List of roles
Role name | Attributes | Member of
--------------------------------------------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370 | Password valid until 2019-08-15 09:22:55+00 | {}
app=> quit

Si el usuario y contraseña no es correcto no se permite la conexión a la base de datos.

1
2
bash-5.0# PGPASSWORD=tampered psql -U v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370 -h 172.17.0.2 -d app
psql: FATAL: password authentication failed for user "v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370"

En las aplicaciones Java que utilizan Spring el proyecto Spring Cloud Vault proporciona las utilidades para simplificar en gran medida la obtención de las credenciales a la base de datos utilizando Vault.

Esto permite que únicamente Vault conozca la cuenta root de la base de datos o una con suficientes permisos para crear credenciales, las aplicaciones no almacenan en su configuración las credenciales para conectarse la base de datos solo las de Vault que le permiten obtener unas credenciales para la base de datos con un tiempo de vida limitado y que pueden revocarse desde Vault en caso de un problema de seguridad para cuales quiera bases de datos que se utilicen.

» Leer más, comentarios, etc...

Coding Potions

Cómo gestionar una página web. Claves para el éxito

agosto 08, 2019 12:00

Introducción

Hoy en día es muy común que cualquier empresa tenga su propia web corporativa, con la que incluso llegan a dar servicios, pero lo cierto es que no todas triunfan debido a una mala gestión de la web. En el artículo de hoy te voy a enseñar algunas claves para una correcta gestión de tus páginas web.

Lo más recomendable es que todo lo gestiones tu mismo para un mayor control sobre tu producto, pero, para una óptima gestión de insfraestructuras tecnológicas es indispensable una buena administración de sistemas IT lo que te ahorrará tiempo y esfuerzo.

Lo que voy a contar a continuación son una serie de consejos, ideas y cosas a tener en cuenta para que no tengas ningún problema a la hora de gestionar una página web.

Bases de datos y backups

Administración de bases de datos

Una de las partes cruciales de tu página web son los datos. Los datos pueden ir desde los usuarios registrados en tu web, tus productos disponibles si se trata de un e-commerce, posts, etc.

Imagina que por un fallo inexperado se vacía la base de datos. Si esto ocurre lo más probable es que lo pierdas todo y te quedes sin nada. Dependiendo de tu sector, lo más normal es que tengas automatizada la creación de backups cada cierto tiempo (dependiendo del sector de tu negocio puede ser más tiempo o menos tiempo pero mínimo un backup al día).

Los backups no son más que copias en disco de tu base de datos para que en caso de error la puedas recuperar con facilidad. Hay sectores con datos muy delicado que hacen backups en distintos servidores y discos para asegurar que no se pierde, incluso algunos hacen copias en cintas físicas para evitar errores.

En gitlab, por ejemplo, un día tuvieron muchos problemas porque uno de sus trabajadores borró bases de datos con código y recursos de producción. Mucho lo lograron recuperar pero hubo parte que perdieron: https://about.gitlab.com/2017/02/01/gitlab-dot-com-database-incident/

Seguridad

Administración de la seguridad de una web

Otro factor clave para la gestión de páginas web es la seguridad. Dependiendo del sistema que tengas montado tienes que testear posibles bugs y fallos que se puedan producir en tu página web. Un fallo de seguridad sería fatal para tu página web.

Los fallos pueden ir desde usuarios que pueden acceder a partes de tu web que no deberían (al panel de control por ejemplo), accesos directamente al servidor y su sistema de carpetas, ataques DDoS, etc.

Toda medida de seguridad es poca, y dependerá del sistema y cómo tengas montada tu infraestructura, aunque hay ciertas pruebas que se pueden hacer a todas las páginas web.

Lo que es indispensable es que conozcas a la perfección tu infraestructura. Si tienes un hosting contratado, debes ponerte en contacto con la empresa para saber con exactitud cómo tienen montados los sistemas y qué medidas de seguridad tienen. Si tu mismo controlas la infraestructura tienes que mirar cada punto de acceso y posibles fallos en el sistema.

Lo más normal en empresas grandes es que la propia empresa tenga un departamento de sistemas y seguridad. Si no cuentas con uno, lo que se suele hacer es contratar servicios de auditoría de sistemas y páginas web.

Backend y APIS

Administración de servidores y backend

Si has montado un sistema propio, lo que tienes que comprobar y monitorear es posibles caídas del servicio. Si un página web es dependiente del backend o servidor y éste falla tu aplicación o página web no va a funcionar.

Un aspecto a tener en cuenta es la protección de la API. Si la API se va a encargar de servir datos a páginas solo visibles para ciertos usuarios, tenemos que encargarnos de asegurar que esas llamadas están protegidas mediante autorización. Si la API es abierta tenemos que tener cuidado por si alguien decide explotarla y saturarla.

Otro apartado clave son los logs. Deberías tener montado un sistema de logs para tenerlos todos controlados y accesibles en un solo lugar. Tu backend debería ser capaz de almacenar en esos logs los errores producidos cuando se usa la web.

Una forma efectiva de evitar fallos es tener una buena suite de tests en el código para que cada vez que se suba a producción una nueva versión se pasen todos los tests en busca de fallos en el código.

Lo que se suele hacer con las APIS es un versionado adecuado para que los endpoints no fallen debido a la subida de nuevas versiones. Por ejemplo si el frontend está usando una versión 2 de la API, no debería cambiar de versión hasta que no se a adaptado a las nuevas funcionalidades de la versión 3.

Frontend

Administración de proyectos frontend

Como no podía ser de otra forma, en el frontend también se pueden producir errores que pueden resultar desagradables a tus usuarios. Desde pequeños errores en estilos, pasando por páginas que no se ven bien, hasta páginas que si siquiera funcionan como debería.

Al frontend se añade otros problemas, los problemas causados por los estilos responsive. Ésto hay que tenerlo en cuenta y estar pendiente de cuando se suben cosas nuevas a producción para revisarlo y evitar problemas relacionados con esto,

Como pasa en el lado del servidor, también es importante cada cierto tiempo mirar y actualizar las posibles versiones de las librerías que se estén usando en ese momento para mitigar posibles errores. Recomiendo el uso de un gestor de librerías javascript como npm o yarn.

Otro punto importante son las llamadas HTTP, tanto en backend como en front se tienen que controlar bien para gestionar posibles fallos. Una práctica recomendada consiste en proteger todas las llamadas a servidor con token o autorización. También es importante limitar las APIS para que un usuario no pueda desarrollar un bot o script que explote la API.

Contenidos

Administración de contenidos online

Si tu modelo de negocio es una aplicación web este apartado no te será de mucha ayuda, pero si tienes montado una web tipo blog o una web más enfocada a los contenidos, vas a necesitar una forma de gestionarlos sin tener que andar tocando código.

Hoy en día existen muchos CMS que te facilitan la vida a la hora de gestionar el código para las páginas web, e incluso se encargan de gestionar la base de datos como por ejemplo, Wordpress del que hablaremos más adelante.

Si tu web es muy grande y tienes un backend propio lo mejor es que te montes tu propio sistema de gestión de contenidos, es decir, páginas internas en las que la gente pueda añadir, editar y borrar contenido para tu página web.

Para Google y los usuarios lo mejor es que cada poco tiempo actualices los contenidos ta creados, los amplíes si hace falta y arregles sus posibles errores.

Wordpress, todo en uno. No todo es perfecto.

Administración de contenidos online

Muchas veces se recomienda Wordpress para administrar páginas web y contenidos ya que ofrece un “todo en uno” y en eso estoy de acuerdo. Con wordpress te vas a evitar muchos dolores de cabeza y no vas a tener que mirar tantas cosas por eso es ideal para páginas no muy grandes.

Para páginas más grandes la cosa -se queda algo corta. Aunque es cierto que todavía hay grandes medios que lo utilizan, a la hora de la verdad lo mejor, como he dicho antes es montar tu propio sistema a tu gusto, aunque te cueste esfuerzo y tiempo.

Por experiencia se que con Wordpress, va a haber ocasiones en las que se te quede algo corto o que necesites funcionalidad especifica para crear ciertas cosas. Aunque es cierto que puedes desarrollar plugins y puedes meter código, lo cierto es que vas acabas perdiendo también mucho tiempo.

Otro problema de Wordpress es que lleva mucho tiempo y es muy popular. Que sea tan popular está bien porque hace que haya mucha comunidad y si tienes un problema alguien te lo sepa resolver, pero, al usarse mucho, hace que algunos quieran hackearlo.

Y es que para evitar hackeos otra cosa que tienes que gestionar es los plugins y los temas de Wodpress, porque está visto que con temas y plugins antiguos te expones a mucho riesgo de ser hackeado.

Conclusiones

No se ha comentado, pero también hay que tener en cuenta el escalado de la web. No es lo mismo una web para 10 usuarios que para 10.000 usuarios concurrentemente.

Las empresas grandes tienen sistemas de autoescalado automático para que en caso de afluencia de gente, se repliquen las bases de datos y los servidores para ser capaces de gestionar tanto volumen de gente.

La gestión de las páginas web ya creadas es una tarea que no se puede subestimar, es casi tan importante o más que la creación de la página web.

» Leer más, comentarios, etc...

Fixed Buffer

Descanso (Mode: ON)

agosto 06, 2019 08:00

La imagen muestra un terreno en mi pueblo y se ve una casita de paja que estoy haciendo.

Después de casi un año, ya tocan unas merecidas vacaciones, así que he pensado en dedicar la entrada de esta semana para avisaros de que me voy a tomar unas pequeñas vacaciones para descansar, estar con la familia, (y terminar la casita de paja de la foto xD).

Después de cojer fuerzas, volveremos en septiembre con varias cosillas interesantes que estoy preparando.

¡Os deseo unas buenas vacaciones a todos, y nos vemos en unas semanas!

**La entrada Descanso (Mode: ON) se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Navegapolis

Los mejores productos se obtienen cuestionando las ideas, no las personas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la agilidad no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden generar trabajo, pero no talento, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos en los que se cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación con la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Navegapolis

El talento se da mejor si no se confrontan los egos, sino las ideas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la creatividad ágil no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden producir trabajo, pero no innovación, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos en los que se cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación y la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Navegapolis

El talento se da mejor si no se confrontan los personas, sino las ideas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la creatividad ágil no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden producir trabajo, pero no innovación, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos en los que se cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación y la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Navegapolis

El talento se da mejor en las empresas en las que no se confrontan egos, sino ideas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la creatividad ágil no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden producir trabajo, pero no innovación, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos que cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación y la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Arragonán

Sobre el rediseño

julio 26, 2019 12:00

Hace un par de meses publiqué el rediseño de la home de mi web personal y de paso de este blog.

Versión 2013

El anterior diseño, de José Luis Lizano y maquetado por Guillermo Latorre, databa de inicios de 2013 y estaba enfocado a ser un portfolio de algunos de mis trabajos como desarrollador freelance hasta ese momento. Tenía el objetivo de dar a conocer el tipo de trabajos para el que se me podía contratar, objetivo que había perdido sentido hacía tiempo.

A su vez el blog lo maqueté yo basándome en el trabajo que hicieron ellos en la home, aún siendo un resultado medianamente digno, se evidenciaban mis limitaciones.

Pantallazo el diseño previo del blog

Originalmente, tanto la web como el blog estaban sobre Wordpress en un hosting compartido, así que tocaba ir haciendo actualizaciones y mantenimiento de vez en cuando… Normalmente tarde y mal. Así que a mediados de 2017 lo migré a Jekyll en Github Pages, integrando Disqus para los comentarios y así poder olvidarme de eso. En ese momento me tocó andar revisando la parte responsive para que no se viera el diseño totalmente roto accediendo desde móviles, algo que hasta entonces no le había dedicado atención.

Versión 2019

Tras mucho tiempo con ello en la cabeza, finalmente nos pusimos a darle una vuelta con Vanessa Rubio al rediseño. Sin tener objetivos en sí mismos, las ideas principales eran:

  • Cambio en el enfoque de comunicación, quería que la home fuera algo más parecido a una carta de presentación. Romper con el enfoque de portfolio para pasar a contar qué cosas hago, qué he hecho, mis intereses, etc.
  • Ganar en legibilidad, ya que el anterior diseño de la home estaba planteado para textos cortos y la adaptación que hice para el blog arrastraba por ello algunos problemas. Quería volver a darle protagonismo a este blog escribiendo más en él y dejando de publicar en Medium.
  • Tener un diseño pensado para consumir contenido desde dispositivos móviles, por razones evidentes.

Boceto inicial del diseño del blog tanto versión escritorio como móvil

Para ponerlo en común trabajamos sobre bocetos en papel iterando rápido hasta llegar a la imagen de este post, que usó Vanessa como base para diseñar ya la parte visual entrando a detalle junto a contenido que fui evolucionando.

Una vez diseñada la parte visual, empezó a trabajar en la maquetación responsive sobre un fork del repositorio de git. Incorporando los cambios directamente en el Jekyll existente, con el contenido real y sincronizando alguno de mis cambios en cuanto a copys. Además, aprovechando que Jekyll lo soporta de serie, en el camino migró los estilos de Less a Sass.

Para finalizar, estas son algunas explicaciones de decisiones sobre el rediseño de Vanessa:

La idea era rediseñar sin perder la identidad actual. Para eso mantuve los principales elementos identificativos, como el logo, los colores y la tipografía.

Como queríamos facilitar la lectura de textos largos, le di más peso al blanco (sustituyéndolo como color de fondo) y dejé el negro principalmente para las zonas de navegación y la intro de la home. Para hacerla también más cómoda, especialmente en dispositivos móviles, aumenté el tamaño de fuente y del interlineado; añadiendo además espacios entre apartados para facilitar la lectura en diagonal.

Quería que fuera un espacio limpio, sin elementos que pudieran distraer la lectura. Para eso eliminé la barra derecha del blog ampliando así el espacio del cuerpo del post y dejé bastante aire alrededor para relajar la vista y centrar la atención en el contenido.

Por último, también quería destacar los CTAs más importantes del blog (como el de enviar comentarios o navegar entre páginas) convirtiéndolos en botones y unificando al mismo tiempo esos mismos estilos con los de la home para mantener la coherencia entre elementos similares.

Personalmente estoy muy contento con el resultado :)

» Leer más, comentarios, etc...

Fixed Buffer

La potencia de la Reflexión en C# (Parte 4: Métodos)

julio 23, 2019 08:00

Imagen con el logo de C# para la entrada de reflexión para métodos

Aquí estamos una semana más hablando de la reflexión, y hoy les toca el turno a los métodos. Echando la vista atrás, hemos hablado sobre la reflexión en general y las propiedades, sobre como trabajar con ensamblados, y en la última semana hablamos sobre cómo utilizar los constructores mediante reflexión.

Hoy es el turno de trabajar con reflexión en métodos. A estas alturas, seguramente puedas imaginar cómo los vamos a obtener, puesto que es muy parecido a obtener los constructores. Salvo que esta vez, en vez de obtener un ConstructorInfo, vamos a tener un MethodInfo. (Aunque las dos clases en profundidad tienen sus diferencias, ambas heredan de MemberInfo). Además, lo hemos utilizado para probar el código en las entradas anteriores.

Obteniendo un método por reflexión

Como en todos los casos anteriores, lo que vamos a partir es del tipo (Type), pero esta vez vamos a llamar al método GetMethod() indicándole el nombre del método que queremos buscar. Adicionalmente, le podemos indicar también los modificadores y los parámetros, en caso de que tengamos varios métodos que se llaman igual, pero cambia la firma. Por ejemplo:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos un método público
var publicMethod = type.GetMethod("Multiplicar");
//Obtenemos un método privado
var privateMethod = type.GetMethod("ResetValor", BindingFlags.Instance | BindingFlags.NonPublic);
//Obtenemos un método estático
var staticMethod = type.GetMethod("Sumar", BindingFlags.Static | BindingFlags.NonPublic);


public class ClaseEjemplo
{
    private int _valor;
    public ClaseEjemplo(int valor)
    {
        _valor = valor;
    }

    public int Multiplicar(int por)
    {
        return _valor * por;
    }

    private void ResetValor()
    {
        _valor = 0;
    }

    static int Sumar(int a, int b)
    {
        return a + b;
    }
}

Invocando nuestro método

Una vez que tenemos nuestro MethodInfo, al igual que veíamos con los constructores, basta que llamemos a Invoke pasándole los parámetros, y ya hemos conseguido ejecutar nuestro código:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos los constructores
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); //Contructor con parametro int
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes); //Constructor genérico

//Creamos el objeto de manera dinámica
var objetoConParametros = constructorConParametros.Invoke(new object[] { 2 });

// Creamos una referencia al método   
var m = assembly.GetType(className).GetMethod("Multiplicar");

//Llamamos al método pasandole el objeto creado dinámicamente y los argumentos dentro de un object[]
var retConstructorParamatrizado = m.Invoke(objetoConParametros, new object[] { 3 });

Con esto tan sencillo, ya hemos conseguido ejecutar métodos por reflexión en C#. ¡Y esto es todo! ¿O no…?

El coste de la reflexión

Estamos ya por la cuarta entrada, y siempre diciendo que la reflexión es cara, pero…. ¿Cuánto más cuesta procesar nuestro código por reflexión?,¿es mucho…? ¿poco…? La respuesta es: muchísimo, vamos a poner unos números:

La imagen muestra un benchmark comparando la llamada normal al método y la llamada por reflexión, viendo que esta última es más de 3500 veces más lenta

Vaya… con estos números, parece que la reflexión no sirve, es demasiado lenta, no podemos meter reflexión en nuestro código más allá de para facilitarnos las pruebas unitarias.

La reflexión es muy útil para testing, hoy sin ir más lejos la he utilizado para poder testear cierta parte del código de un proyecto que es privada porque así debe serlo, y he podido saltarme las restricciones de acceso y he podido añadir tests para ese código que prueba solo lo que tiene que probar.

Muy acertadamente en los comentarios de una entrada anterior, planteaban una alternativa para mejorar el rendimiento, que consiste crear el objeto mediante el constructor por reflexión, y a partir de ahí utilizar dynamic. Para quién no lo conozca, dynamic es un tipo especial de objeto que evita la comprobación de tipos en compilación utilizando Dynamic Language Runtime, delegando al runtime ese trabajo, lo que nos permite hacer algo como esto:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos el constructor
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 

//Creamos el objeto de manera dinámica y de tipo "dynamic"
dynamic objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });

//Llamamos al método como si fuese un objeto tipado
var retConstructorParamatrizado = objetoDinamicoConParametros.Multiplicar(3);

Con este pequeño cambio, hemos conseguido mejorar los tiempos:

La imagen muestra como utilizar "dynamic" es cerca de 23 veces más rápido que utilizar reflexión, aunque sigue siendo 150 veces más lento que una llamada normal

Los dos principales problemas de esto, son que hemos perdido la flexibilidad que teníamos para buscar los métodos, ya que ahora el nombre tiene que coincidir, no tenemos ese margen para buscar (además de que volvemos a regirnos por los modificadores de acceso), y sobre todo, sigue siendo 150 más lento que hacer una llamada convencional (aunque hemos mejorado mucho respecto a la llamada por reflexión). De todos modos, si queremos utilizar la reflexión para cargar código que puede cambiar, sigue siendo demasiado lento. Llegados a este punto, ¿tenemos que tirar la toalla con la reflexión?

Creando delegados de métodos obtenido por reflexión

Un delegado, no es más que la referencia a un método desde la cual vamos a poder llamar a ese método sin necesidad de tener acceso al objeto que lo contiene, ya que este va implícito en la referencia a donde apunta el delegado:

// Declaramos la firma del delegado
delegate void MyDelegado(string str);

// Declaramos un método con la misma firma del delegado
static void Notify(string message)
{
    Console.WriteLine(message);
}

// Creamos una instancia del delegado.
MyDelegado del1 = new MyDelegado(Notify);

// Llamamos al método a través del delegado.
del1("Llamada desde un delegado");

Ahora, si unimos esto con la reflexión, lo que podemos hacer es crear un delegado que apunte hacia nuestro método por reflexión. Para ello, siguiendo con nuestro ejemplo, vamos a utilizar el delegado «Func<int,int>» (recordemos que nuestro método recibía un entero como parámetro y devolvía otro entero), pero si fuese necesario, podemos definir el delegado que nos haga falta.

Para construirlo, vamos a aprovecharnos de Delegate.CreateDelegate, y le vamos a indicar el tipo, el objeto al que hacemos referencia, y el nombre del método al que queremos hacer el delegado:

Func<int, int> delegateMethod = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), target, "Multiplicar");

Delegate.CreateDelegate tiene diferentes parámetros en función de lo que queramos hacer, por ejemplo, si queremos crear un delegado a un método estático, tendríamos que utilizar el objeto MethodInfo directamente, te recomiendo que le eches un ojo a sus posibilidades.

Además, como conocemos el tipo del delegado a la perfección (sabemos que esperar, o podemos consultarlo sobre el MethodInfo para saber que delegado aplicarle), podemos hacer un cast al tipo de delegado concreto, por ejemplo, el código completo sería algo así:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos el constructor
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 

//Creamos el objeto de manera dinámica            
object objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });
            
//Creamos el delegado pasandole el tipo, una referencia al objeto sobre el que va a trabajar, y el nombre del metodo
//Delegate.CreateDelegate tiene diferentes parámetros en función de lo que queramos hacer
Func<int, int> delegateMethod = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), objetoDinamicoConParametros, "Multiplicar");

//Llamamos al método 
var retDelegado = delegateMethod(3);

Si ejecutas este código, veras que funciona perfectamente (Como siempre, he dejado actualizado el repositorio en GitHub para poder descargárselo y tocarlo). Además, este modo si nos permite saltarnos los limitadores de acceso, en caso de que estemos haciendo pruebas al código.

Vale, es todo muy bonito, pero a simple vista, solo supone más trabajo porque tenemos que gestionar un delegado también, ¿esto aporta algo?, vamos a ver los números:

La imagen muestra el resultado del benchmark de los 4 métodos, viendose: Llamada convencional 0.02 ns, llamada por reflexión 213.90 ns, llamada con dynamic 9.89 ns y llamada con delegado 1.74 ns

Como se puede comprobar, después de hacer una llamada convencional, utilizar delegados es lo siguiente más rápido, siendo 5,7 veces más rápido que utilizar «dynamic».

Los tiempos son solo orientativos (de hecho, han ido variando ligeramente durante los diferentes benchmark)

Conclusiones

Si bien es cierto que no podemos conseguir los tiempos que conseguiríamos con una llamada convencional. Cuando se recurre a la reflexión es precisamente cuando las llamadas convencionales no están disponibles por una razón u otra. Como se puede comprobar de los números, la reflexión es cara, pero existen maneras de hacerla más liviana.

Como decíamos en la entrada de los constructores, un gran poder conlleva una gran responsabilidad. La reflexión es algo que debemos utilizar con cabeza y criterio, pero no es algo prohibido que no hay que tocar. Como he dicho varias veces, es una herramienta especialmente útil para hacer testing por ejemplo, cuando hay cosas donde necesitamos acceder y no podemos.

**La entrada La potencia de la Reflexión en C# (Parte 4: Métodos) se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Mascando Bits

Aprende a programar en Python – Introducción – 0

julio 19, 2019 06:05

Llevaba tiempo mascando esta serie de entradas para aprender a programar en Python, para las cuales no quise quedarme en algo del tipo mira, aprende y copia. El curso tiene un enfoque práctico con su parte de teoría y ejercicios donde corresponda. Atendiendo a las actuales necesidades formativas he decidido que el curso y su material podrá ser trabajado de manera online utilizando únicamente un navegador web.

Para ello he creado un repositorio en GitHub con dos herramientas que podréis elegir usar de manera online:

Ambos proyectos usan como base el intérprete de Brython, un proyecto que intenta emular el interprete de Python que puedes instalarte en tu equipo. Este proyecto permite saltarse el problema de no poder instalar el interprete de Python debido a restricciones en el equipo que uses, por ejemplo si dependes del departamento de Sistemas para instalarlo, o simplemente si quieres retomar el curso en cualquier instante sin necesidad de instalar nada.

El proyecto de la Consola Python Online es una consola que se comporta de manera similar a la que puedes tener cuando lanzas Python desde una consola de comandos. El proyecto IDE Python Online es un entorno de desarrollo integrado donde podrás en su parte izquierda realizar la programación con realce de sintaxis y ayuda de autocompletado predictivo de código; y en su parte derecha podrás ver el resultado del código escrito a la izquierda tras darle al botón «▶ Run» de la parte superior. Con estas dos herramientas tendrás lo que te hace falta para seguir el curso.

Este proyecto es de carácter Open Source, siendo posible contribuir en el propio repositorio a la mejora de los fragmentos de código, ejercicios y herramientas.

Antes de empezar quisiera explicarte qué es Python y ofrecerte una pequeña aproximación de su historia. Python es un lenguaje de programación interpretado, lo que significa que no necesita compilarse y generar un binario para funcionar, se interpreta el código y el encargado de hacerlo (el intérprete), lo traducen a lenguaje máquina. Esto quiere decir también que con vuestro código en Python sólo necesitáis que un intérprete de Python esté instalado en la máquina para ejecutar el código, o usar las herramientas que anteriormente presentaba 😉 .

Python es un excelente lenguaje de programación si quieres aprender una herramienta que potencie o complemente tu trabajo, como es el caso del clásico Excel. O simplemente como tu primer lenguaje de programación, debido a que su curva de aprendizaje es mucho más baja a diferencia de otros lenguajes, haciendo hincapié en una sintaxis que favorece la legibilidad del código. Además Python es multiparadigma, lo que significa que puede acomodarse a distintos enfoques y necesidades de programación, incluyendo el buen diseño por defecto en la propia sintaxis y evolución del lenguaje.

Actualmente Python se encuentra en un proceso de migración de Python 2 a Python 3, debido a que el soporte de Python 2 acaba el 1 de enero de 2020, terminando con un estado de segmentación del lenguaje que llevaba varios años produciéndose. El salto de Python 2 a Python 3 supone el cambio del diseño de cierta parte de la sintaxis que rompe la compatibilidad y evitaba a Python avanzar hacia el Python que hoy conocemos y que tanta penetración tiene en los sectores técnicos y no tan técnicos. No obstante existen herramientas como 2to3 que realizan la adaptación automática de la sintaxis de Python 2 a Python3. Obviamente no es perfecto y queda en manos del programador el terminar de pulir la migración. La versión del lenguaje que aprenderás aquí, por supuesto es Python 3 😉 .

Para ir abriendo boca voy a mostrarte el clásico programa de inicio «Hello World!» o «Hola Mundo!» en español:

Si le das al botón «▶ Run» leerás en la derecha «Hello World» seguido del tiempo que ha tardado en ejecutarse nuestro programa (lo que hay en el panel izquierdo).

Ahora te propongo un simple ejercicio hasta la próxima entrada. Partiendo del siguiente código:

Intenta que imprima en el lado derecho «Hello World«. Es fácil y seguro que lo consigues 😉 .

Con esto cerramos el capítulo de introducción donde hemos conocido las herramientas que vamos a usar para el curso, hemos presentado Python y hemos ejecutado nuestro primer programa.

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin