- Varias decisiones de diseño del lenguaje Go se tomaron de forma innecesaria o ignorando experiencia previa ya existente
- El problema de gestión del alcance de las variables de error dificulta la legibilidad del código y la búsqueda de bugs
- En varios aspectos, como la dualidad de
nil, el uso de memoria y la portabilidad del código, aparecen diseños poco intuitivos y alejados de la realidad
- Las limitaciones de la sentencia
defer y la forma en que la biblioteca estándar maneja situaciones excepcionales dificultan garantizar la seguridad ante excepciones
- Los problemas acumulados, como la gestión de memoria y el deficiente manejo de UTF-8, están afectando negativamente a largo plazo la calidad de los codebases en Go
Crítica de largo plazo al lenguaje Go
La falta de intuición en el alcance de las variables de error
- La sintaxis de Go amplía innecesariamente el alcance de la variable de error (
err), aumentando la posibilidad de errores
- En el código de ejemplo, la variable
err permanece viva durante toda la función y se reutiliza, lo que perjudica la legibilidad y mantenibilidad del código
- Incluso desarrolladores con experiencia sufren malentendidos y pérdida de tiempo al rastrear bugs debido a estos problemas de alcance
- La sintaxis no permite limitar correctamente esas variables a un ámbito más local
Dos formas de nil
- En Go existe la confusión de que
nil se comporta de manera distinta en tipos interface y tipos puntero
- Como en el ejemplo de abajo, aunque se asigne
nil a s (puntero) e i (interface), s==i se evalúa de manera distinta, mostrando un comportamiento inconsistente
- Este es el tipo de problema que normalmente se quiere evitar al manejar
null, y deja ver una falta de reflexión suficiente en el diseño
Límites de la portabilidad del código
- El uso de comentarios para compilación condicional es claramente ineficiente en términos de mantenibilidad y portabilidad
- Si alguna vez se ha creado software verdaderamente portable, es fácil ver que este enfoque es engorroso y propenso a errores
- Se ignoró la experiencia acumulada históricamente en portabilidad de código y casos prácticos reales
- Para más detalles, puede consultarse Go programs are not portable
La falta de claridad sobre la propiedad en append
- La relación de propiedad entre la función
append y los slices no es clara, lo que dificulta predecir el comportamiento del código
- A través del ejemplo, resulta difícil saber de antemano qué efecto real tendrá sobre el original hacer
append al slice dentro de la función foo
- Aumentan así las “quirks” del lenguaje que hay que memorizar, lo que termina provocando errores
Diseño insuficiente de la sentencia defer
- No ofrece un soporte claro para liberar recursos como sí lo hace el principio RAII (Resource Acquisition Is Initialization)
- A diferencia de las sentencias estructuradas de gestión de recursos en Java y Python, en Go no queda claro qué recursos deben liberarse con
defer
- Como muestra el ejemplo con archivos, incluso hay que lidiar manualmente con problemas de double-close, y no queda claro cuál es el orden ni la forma correctos de liberar recursos
Manejo de excepciones en la biblioteca estándar
- Go es una estructura que no soporta excepciones explícitas (
exception), pero aun así siguen ocurriendo situaciones excepcionales como panic
- En algunos casos,
panic ni siquiera termina por completo el programa, sino que queda absorbido
- Existen patrones en la biblioteca estándar (
fmt.Print, servidores HTTP, etc.) que ignoran excepciones, por lo que no es posible garantizar una verdadera seguridad ante excepciones
- Al final, escribir código seguro ante excepciones sigue siendo indispensable, pero no se pueden usar excepciones directamente
UTF-8 y las cadenas
- Aunque se meta cualquier dato binario arbitrario en el tipo
string, Go funciona sin hacer una validación especial
- Puede ocurrir que nombres de archivo creados antes de la codificación UTF-8 simplemente se omitan silenciosamente
- En tareas como respaldos esto puede causar pérdida de datos importantes, y refleja un enfoque simplista que no toma en cuenta situaciones reales de trabajo
Límites de la gestión de memoria
- Es difícil tener control directo sobre el uso de RAM, y la confiabilidad del GC (garbage collection) también tiene límites
- El uso de memoria de Go crece y eso termina convirtiéndose a largo plazo en problemas de costo y rendimiento
- En entornos con múltiples instancias y contenedores, realmente surgen problemas de costos y escalabilidad
Conclusión: había caminos mejores
- Aunque ya existían diseños de lenguajes que habían demostrado su eficacia, Go los ignoró en muchos aspectos
- A diferencia de los problemas de los primeros borradores de Java, cuando Go fue lanzado ya existían enfoques mejores
Material de referencia
Aún no hay comentarios.