10 puntos por GN⁺ 2024-12-16 | 5 comentarios | Compartir por WhatsApp
  • Un artículo en el que el autor explica las limitaciones y problemas que percibió en Go tras usar el lenguaje durante años y luego cambiarse a Java
  • Plantea la idea de que la característica de Go de ser un lenguaje simple y "aburrido" (boring) puede ser una desventaja, no una ventaja
  • Filosofía de Go: el equipo de diseño de Go en Google enfatizó la simplicidad y las limitaciones, pero eso provoca trabajo repetitivo que el usuario tiene que resolver por su cuenta

1. Que Go sea "divertido" no es precisamente una ventaja

  • La postura de Russ Cox:
    • Enfatiza que el hecho de que Go sea "aburrido" (boring) es una ventaja
    • Solo existe el bucle for, y no se incluyen por defecto funciones como filter, map o reduce
    • La ausencia de muchas funciones avanzadas presentes en la mayoría de los demás lenguajes se considera parte de su simplicidad
  • Opinión de un usuario de Reddit:
    • La frontera entre "aburrido" y "potente" es ambigua
    • Sostiene que es muy probable que las funciones básicas que le faltan a Go terminen agregándose al lenguaje en algún momento
  • Dependencia de paquetes de terceros:
    • Para compensar funciones faltantes, se usa con frecuencia el paquete samber/lo:
      • Incluye funciones esenciales como filter, map y búsqueda
      • Tiene 18.1k estrellas en GitHub y se usa en más de 12.6k proyectos
    • Algunas funciones se añadieron con el paquete slices, pero siguen siendo insuficientes desde el punto de vista funcional
  • Molestias del autor:
    • Obliga a escribir bucles repetitivos
    • Es difícil resolver de forma concisa tareas como filter y map
    • Se puede extraer a métodos de receptor separados, pero eso perjudica la limpieza del código
  • La simplicidad de Go suele ser una ventaja, pero la falta de utilidades básicas integradas puede convertirse en una desventaja que reduce la productividad y la legibilidad del código

2. Dificulta los principios de Clean Code

  • Problemas con el manejo de errores:
    • La mayoría de las funciones incluyen error como valor de retorno:
      • Hay que repetir constantemente el patrón if err != nil
      • Al intentar ordenar el código, este termina volviéndose todavía más complejo
    • Incluso en proyectos simples, el código de un handler HTTP puede crecer a más de 20 líneas
      • Cuando el objetivo original era mantenerlo en unas 4 líneas
    • El autor llegó a frustrarse al punto de considerar panic() y middleware de recuperación para manejar errores
  • Recomendación de nombres cortos:
    • Se promueve usar nombres breves para variables, métodos y funciones:
      • Nombres como c o a no dejan claro qué significan
      • Por ejemplo, c podría ser Command, Controller, Argument o Amendment
      • Usar nombres más largos podría dar más claridad, pero la filosofía de Go prefiere los nombres cortos
    • Esto provoca discusiones interminables en revisiones de código del equipo, por ejemplo sobre nombres de métodos de prueba
  • La filosofía de Go enfatiza la concisión y la simplicidad del código, pero en la práctica puede generar complejidad e ineficiencia que van en contra de los principios de código limpio

3. La filosofía de lenguaje intencionalmente pequeño y la cultura DIY

  • Falta de funciones básicas:
    • Implementar un handler HTTP simple es fácil, pero si se necesita middleware básico (por ejemplo, backoff exponencial o configuración de cross-site) hay que salir a buscar varios paquetes
    • Es difícil tener certeza de si esos paquetes (1) siguen recibiendo mantenimiento y (2) realmente funcionan como se espera
  • Aumento del trabajo repetitivo:
    • La filosofía de diseño de Go de mantener la simplicidad termina empujando al desarrollador a "reinventar la rueda"
    • Ejemplo: incluso una función simple de filter puede tener que implementarse manualmente
  • Ecosistema de paquetes inmaduro:
    • Muchos proyectos en GitHub están abandonados o solo tienen unas cuantas versiones publicadas
    • Puede ser injusto compararlo con .NET/Java por ser un lenguaje relativamente joven, pero en la práctica la estabilidad y madurez de los paquetes de Go siguen siendo limitadas
  • Limitaciones de los ORM:
    • El principal paquete ORM de Go, Gorm, está por detrás de Hibernate o Entity Framework en funcionalidades
    • Presenta comportamientos extraños y falta de documentación
    • Reacción de la comunidad de Go: "En Go no necesitas ORM, ¡hazlo tú mismo!"
  • La simplicidad de Go puede ser una ventaja según el proyecto y el equipo, pero la falta de funciones incluidas por defecto puede afectar negativamente la productividad y la experiencia de desarrollo

4. En Go no existe realmente una sola forma de hacer las cosas

  • Malentendido sobre consistencia y uniformidad:
    • Table tests
      • Uso de suites de pruebas como stretchr/testify (utilizado en 557k proyectos)
      • Escritura de subpruebas personalizadas dentro de table tests
    • Esto revela una brecha entre la filosofía de Go de una "forma unificada" y la realidad
  • Genera conflictos dentro del equipo:
    • Aumentan las discusiones entre equipos sobre estilos de prueba y formas de implementación
    • La filosofía de Go y el propio equipo de diseño tampoco son plenamente consistentes:
      • Ejemplo: desacuerdos sobre el naming de métodos getter
  • Rechazo de funciones y dependencia de paquetes:
    • Se critica al equipo de Go por rechazar agregar funciones de assertion y por culpar a las limitaciones del programador
    • Como resultado, para usar lo que se necesita hay que instalar otro paquete más con go get
  • Aunque Go apunta a la simplicidad y la uniformidad, en la práctica existen múltiples formas de implementación y las discusiones derivadas de ello, mientras la ambigüedad de la filosofía de diseño del lenguaje agrava el problema

5. Depurar en Go no es divertido

  • No se pueden evaluar expresiones durante la depuración:
    • En una sesión de depuración no se pueden evaluar expresiones ni revisar la representación de cadena personalizada de un objeto
    • Eso dificulta entender con claridad el estado de los objetos en tiempo de ejecución
  • Stack traces y logs poco intuitivos:
    • Cuando fallan pruebas grandes (por ejemplo, miles de tests ejecutados en CI), se obtienen stack traces y logs confusos
    • Como resultado, depurar se vuelve más difícil y cae la productividad
  • Experiencia de depuración estilo C:
    • La cadena de herramientas de depuración de Go funciona sobre bases similares a C:
      • Ofrece una experiencia de depuración primitiva, parecida a la de C
      • No resulta amigable para el desarrollador
  • Comparación con Rust:
    • Rust mejora varias limitaciones de Go:
      • Ofrece información de errores clara y útil
      • Incluye sugerencias precisas para corregir los errores
  • La experiencia de depuración en Go se basa en una filosofía de diseño enfocada en binarios optimizados, pero eso termina sacrificando la experiencia del desarrollador. En entornos donde la eficiencia de depuración es importante, puede ser recomendable considerar lenguajes alternativos.

Resumen: idoneidad y límites de Go

  • Ventajas de las herramientas integradas de Go:
    • Proporciona una toolchain básica para gestión de paquetes, pruebas y monitoreo de rendimiento
    • Puede usarse sin configuración adicional, lo que simplifica la puesta en marcha del entorno de desarrollo
  • Limitaciones:
    • "Código aburrido" y trabajo repetitivo:
      • La toolchain de Go es funcional, pero al escribir código obliga a repetir trabajo (plumbing code)
      • Ejemplo: la sintaxis monótona y las funciones limitadas reducen el interés por la tarea
    • import cycle not allowed:
      • No permite dependencias circulares (import cycle) en tests
      • Al trabajar con diseño guiado por el dominio (DDD), esto aumenta la complejidad debido a restricciones estructurales
    • Dependencia de la técnica de embedding de struct:
      • El mecanismo de embedding de struct es extraño y limitado, y eso genera fricción en su uso
  • Áreas de uso adecuadas:
    • Adecuado para desarrollo de infraestructura:
      • Herramientas a nivel de sistema como Docker, Drone y Hugo están escritas en Go
    • Útil para desarrollar servidores ligeros y aplicaciones CLI
  • Áreas poco adecuadas:
    • Desarrollo de aplicaciones empresariales complejas (por ejemplo, sistemas ERP):
      • La filosofía limitada del lenguaje y sus herramientas vuelve ineficiente la gestión de lógica de negocio a gran escala
  • Go ofrece una gran eficiencia en ciertos tipos de trabajo, especialmente relacionados con infraestructura, pero no es una herramienta adecuada para aplicaciones con dominios de negocio complejos. Incluso si el CTO está sesgado hacia el stack tecnológico de Google, conviene elegir la tecnología con cuidado.

5 comentarios

 
secret3056 2024-12-17

Si tan solo Rust hubiera tenido ?, ¿no habría sido muchísimo mejor que ahora...?

 
bbulbum 2024-12-17

Lo que sentí al usar Go es que me hizo pensar en cuánto manejo de errores implícito había estado haciendo hasta ahora.
Claro, procesar el manejo de errores en un solo punto puede verse estructuralmente más limpio, pero me da la impresión de que, al dejar explícito que se trata de una operación que puede devolver un error, terminas escribiendo código de una forma más segura.

 
tsboard 2024-12-16

if err != nil {} la verdad sí es un poco molesto. También estoy de acuerdo con las desventajas que se han señalado. Aun así, si entendemos claramente hacia dónde apunta este lenguaje y pensamos en qué aspectos aprovechar más, creo que podremos sacarle mejor partido a pesar de esas desventajas. ¡Se parece a C, pero tiene GC, además soporta genéricos aunque de forma limitada, y hasta permite compilación cruzada! Viéndolo así, ¿no es también un lenguaje bastante generoso?

 
riki3 2024-12-16

Al pasar de Java a Go, creo que al principio sentí algo parecido.
Ahora disfruto tanto Go que hasta siento que el tiempo que usé Java fue un desperdicio. Que no sea adecuado para aplicaciones de negocio complejas me hace pensar que esas aplicaciones no reflexionaron lo suficiente sobre cómo simplificar el sistema.

 
GN⁺ 2024-12-16
Opinión de Hacker News
  • Surgen problemas cuando un desarrollador de Java intenta imponer un estilo de Java en Go

    • La filosofía de Go es menos útil a corto plazo, pero marca una gran diferencia a largo plazo
    • A quienes están muy metidos en el ecosistema de la JVM les cuesta disfrutar Go
  • Muchos desarrolladores intentan abstraer demasiado pronto

    • Crean abstracciones innecesarias cuando una repetición simple sería suficiente
  • La biblioteca estándar de Go es grande, pero no tanto como para hacerlo todo

    • Hay una tendencia a reinventar la rueda en cada proyecto
    • Go es ideal para aplicaciones de servidor y CLI
  • Existen desafíos más grandes que la elección del lenguaje de programación

    • Lo importante es adaptarse a los mecanismos y la filosofía de Go
  • Es difícil entender por qué a algunos les gusta Go

    • Se prefiere más la cadena de herramientas y la facilidad de despliegue que el lenguaje en sí
  • Resulta frustrante que el equipo principal de Go revierta decisiones equivocadas

    • Existen un buen sistema de paquetes y buenas herramientas
    • Java puede ser una mejor opción para sistemas ERP complejos
  • Go tiene problemas similares a los de UNIX

    • Tiende a trasladar la complejidad al usuario
    • El runtime de Java está evolucionando rápidamente en comparación con Go