Este artículo describe un problema común en el desarrollo de software backend, específicamente en el manejo de transacciones de bases de datos, y cómo el autor lo resolvió creando un linter personalizado. El problema surge cuando, al envolver código existente en una transacción, se olvida de usar el objeto de repositorio transaccional (tx) en lugar del repositorio global (s.repo), lo que provoca que algunas operaciones se ejecuten fuera de la transacción, generando corrupción de datos y condiciones de carrera difíciles de detectar. Estas operaciones 'fugas' pueden pasar por compilación, pruebas unitarias (que se ejecutan aisladas) e incluso revisiones de código, manifestándose solo bajo carga.
El autor, frustrado por la dificultad de depurar estos errores, decidió construir una herramienta de análisis estático, un linter, para detectarlos en tiempo de compilación. El linter se basa en el framework go/analysis de Go, que simplifica la creación de analizadores estáticos al encargarse de la complejidad del parsing y el type-checking. El linter funciona recorriendo el Abstract Syntax Tree (AST) del código, identificando llamadas a funciones de transacción y luego verificando que todas las operaciones dentro de la transacción utilicen el objeto de repositorio transaccional (tx) y no el repositorio global.
La implementación clave implica identificar llamadas a transacciones (basándose en el nombre de la función Transaction y el tipo del repositorio), extraer el parámetro de la transacción (tx), y luego rastrear su uso a través del AST del callback de la transacción. Para rastrear el parámetro tx, el linter captura tanto su nombre como su objeto de tipo, permitiendo comparaciones precisas incluso si el nombre de la variable se 'shadows' (redefine) dentro del callback. El linter evita analizar transacciones anidadas, asumiendo que tienen su propio alcance. El resultado es una herramienta que puede detectar errores sutiles y potencialmente costosos antes de que lleguen a producción, mejorando la calidad y la fiabilidad del código.
