jueves, febrero 13, 2025

Continuando la transición: De Flask a GoFiber

Una ventaja de ser expulsado de tu zona de confort —TurboGears, Genshi, SQLAlchemy— es que te obliga a estudiar y analizar bien cómo quieres que funcionen tus futuros desarrollos. ¿Quieres seguir usando Apache-WSGI? ¿Ya te cansaste de estar pendiente de las actualizaciones de los servidores? ¿Lidiar con dependencias descontinuadas?

Flask parecía la opción más obvia para sustituir a TurboGears, así que comenzamos a migrar algunos desarrollos. La curva de aprendizaje no parecía muy pronunciada. También aprovechamos la oportunidad para irnos hacia una arquitectura serverless, hospedando las aplicaciones en contenedores usando Docker. Ya teníamos experiencia con contenedores al desplegar los proyectos anteriores en TurboGears.

Los contenedores para Flask incluían Nginx, WSGI y el código fuente del proyecto. ~370MB parecían razonables y casi mágicos en ese entonces. Una de las muchas ventajas de Python es que puedes modificar el código mientras está corriendo en producción 🤓. Un error ortográfico, un hotfix, etc., se podían corregir en minutos: abrir una sesión de sh o bash dentro del contenedor, instalar vim, modificar el archivo en cuestión y listo. Después, la corrección se aplicaba al código base y el contenedor quedaba limpio en la siguiente actualización.

Durante la cuarentena de 2020, comencé a utilizar Go para desarrollar servicios. La sintaxis es muy simple, aunque a veces repetitiva. También me costó un poco al principio adaptarme a la falta de un mecanismo tradicional de manejo de excepciones. En Python, Java, JavaScript y otros lenguajes puedes envolver un segmento de código dentro de un try-catch. Siguiendo el principio "It is easier to ask for forgiveness than permission", puedes manejar la excepción cuando lo que crees que va a pasar no sucede.

En Go, tienes que pensarlo de una forma diferente.


Manejo de errores: Python vs. Go

Try-Catch en Python

En Python, el manejo de errores es sencillo con try-except:

def dividir(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        print("Error: No se puede dividir entre cero.")
        return None

resultado = dividir(10, 0)  # Esto imprimirá un mensaje de error

Manejo de errores en Go

Go no tiene un try-catch convencional. En su lugar, el manejo de errores se realiza mediante valores de retorno:

package main

import (
    "errors"
    "fmt"
)

func dividir(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("no se puede dividir entre cero")
    }
    return a / b, nil
}

func main() {
    resultado, err := dividir(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Resultado:", resultado)
    }
}
A medida que avanzábamos en la adopción de Go, nos dimos cuenta de que la simplicidad y el rendimiento que ofrecía valían el esfuerzo de adaptación. Aunque al principio resultaba extraño no contar con un sistema de excepciones tradicional, el manejo explícito de errores nos obligó a escribir código más robusto y predecible. Con el tiempo, terminamos prefiriendo esta aproximación, ya que facilitaba la depuración y nos ayudó a construir servicios más eficientes y escalables. Así, lo que comenzó como una migración obligada, terminó transformándose en una mejora significativa en nuestra forma de desarrollar aplicaciones. 🚀

lunes, febrero 03, 2025

Agregando timestamps a fotos

Usando mogrify, parte de las herramientas de imagemagick, podemos agregar el timestamps a fotos que tiene la fecha de captura en su EXIF.

$ mogrify  -pointsize 28 -gravity SouthEast -annotate +5+5 '%[EXIF:DateTime]'  *.jpg

Mas información de configuración en: http://www.imagemagick.org/Usage/basics/#mogrify

Cuando tu plataforma favorita es descontinuada

Hace varios años, cuando llegó el momento de elegir una plataforma para sustituir al tremendo Java, con sus JSF, Spring y demás, dimos el salto a Python. La razón principal era su rapidez para desarrollar prototipos, lo que permitía que los clientes pudieran visualizar y aprobar sus proyectos con mayor agilidad.

En ese entonces, había dos propuestas destacadas: Django y TurboGears. Django era la opción obvia, pero no me convencía que todo estuviera integrado dentro del mismo ecosistema: el ORM, el renderizado de plantillas y el enrutamiento. TurboGears, por otro lado, ofrecía herramientas de código abierto para cada una de estas tareas.

Para mí, la mejor opción era TurboGears, y durante muchos años nos funcionó de maravilla. Se desarrollaron numerosos proyectos con esta tecnología: era rápido y fácil de adaptar.

Sin embargo, con la llegada de Python 3.0, las actualizaciones comenzaron a retrasarse. Luego vino Python 3.4 y la situación empeoró; con Python 3.8, simplemente dejaron de existir. TurboGears había quedado abandonado.

Aun así, logramos adaptar nuestros desarrollos para funcionar en contenedores con Python 3.8, la última versión en la que TurboGears aún operaba sin demasiados problemas.

Esperamos en vano una actualización, mientras Django seguía evolucionando.

Durante la cuarentena de 2020 aprovechamos para explorar nuevas opciones. Flask parecía una buena alternativa... pero, en medio del enorme esfuerzo de refactorización, apareció una opción aún mejor: GoFiber y GORM.

viernes, abril 29, 2016

Timestamps con SQLAlchemy

Es común tener campos que guarden la fecha de la creación de registro y la fecha de modificación de ése registro.

Mucho tiempo usé la siguiente declaración:

1
2
    ts = Column(u'ts', TIMESTAMP(timezone=False),
                server_onupdate=text('CURRENT_TIMESTAMP'), primary_key=False, nullable=False)

Aprovechando que 'CURRENT_TIMESTAMP' es soportado en MySQL, cada vez que se inserta un registro MySQL pone la fecha del servidor de manera automática.

Creo que ahora hay una mejor manera de manejarlo, siempre y cuando el RDBMS soporte 'on update':


1
2
    created = Column(DateTime, nullable=False, default=func.now())
    updated = Column(DateTime, nullable=False, default=func.now(), onupdate=func.now())

Es mas simple y fácil de leer

domingo, abril 24, 2016

Como quitar atributos extendidos en OSX (com.apple.quarantine)

Recientemente al bajar una nueva plantilla y descomprimirla en un nuevo directorio, aparece que con un '@' a un lado de sus permisos de archivo.
jupabeans at TankerMini in ~/workspace/theme
$ ls -ls

total 0

0 drwxr-xr-x     4 jupabeans  staff   136 Apr 24 22:07 .

0 drwxr-xr-x     7 jupabeans  staff   238 Apr 24 21:56 ..

0 drwxrwxrwx@    6 jupabeans  staff   204 May 28  2015 README

0 drwxrwxrwx@  121 jupabeans  staff  4114 May 28  2015 theme
jupabeans at TankerMini in ~/workspace/theme
$ ls -@ls

total 0

0 drwxr-xr-x     4 jupabeans  staff   136 Apr 24 22:07 .

0 drwxr-xr-x     7 jupabeans  staff   238 Apr 24 21:56 ..

0 drwxrwxrwx@    6 jupabeans  staff   204 May 28  2015 README

     com.apple.quarantine 26
0 drwxrwxrwx@  121 jupabeans  staff  4114 May 28  2015 theme
     com.apple.quarantine 26
Eso indica que el archivo tiene atributos extendidos (extended attributes) en OSX.  En éste caso 'com.apple.quarantine', una bandera que OSX usa desde Leopard (10.5) para marcar archivos descargados de fuentes no confiables.  Cuando ejecutas por primera vez ese archivo, una pantalla de confirmación aparecerá en la pantalla.

Pero ¿qué pasa cuando sólo son archivos de texto? pues nada, pero siempre quedarán marcados y a mi me distraen.  Así que los voy a quitar.

Hay varios métodos para quitarlos, el inteligente sería, buscar los archivos marcados en un directorio y quitarlos uno por uno.  El brutal sería quitarlos con 'recursive' activado.
$ xattr -dr com.apple.quarantine theme
xattr es el comando para manejar los atributos extendidos, -d es la opción para borrarlo -r activa recursividad, luego el nombre del atributo y al final el directorio o archivo.

Hay varias plantillas que tienen los archivos marcados como ejecutables, para quitarlos simplemente:

$ chmod 755 $(find theme -type d)
$ chmod 644 $(find theme -type f)
En ocasiones los espacios en los nombres de archivos pueden confundir los argumentos de chmod. Se puede usar las siguientes alternativas.
$ find theme -type d -exec echo -n '"{}" ' \; | xargs chmod 755
$ find theme -type f -exec echo -n '"{}" ' \; | xargs chmod 644
*actualizado 22 noviembre 2016
Otro método para remover los atributos extendidos
$ xattr -rc .

miércoles, febrero 24, 2016

Mercurial y control de versiones

En cada proyecto de desarrollo debemos contar con una herramienta para el control de versiones. Mercurial es actualmente mi favorito, hace años fue cvs y luego svn.

Haremos un simple ejercicio para mostrar funciones básicas de uso frecuente con ésta herramienta.  No he probado como funcionarían éstos ejemplos en Windows, pero si funcionan en sistemas POSIX.  Unix, Linux y OS X.

martes, febrero 23, 2016

Creando un ambiente de desarrollo en OS X

OS X es una buena plataforma de desarrollo.  Para todos los propósitos es una tiene un API POSIX, que la hace similar a al ambiente de desarrollo que antes usaba en Linux.

Sin embargo, el shell es muy elemental y ya me acostumbré a los beneficios de herramientas que en Linux están activadas por default.  Te muestro algunas de ellas.