Go (o Golang) es un lenguaje de programación relativamente nuevo, y no hay nada gusta más a un desarrollador que aprender un nuevo lenguaje. Como muchos inventos, Go fue creado a partir de un experimento. El objetivo de sus creadores era tener un lenguaje que resolviera las malas prácticas de otros manteniendo las partes buenas. Se lanzó en marzo de 2012 y desde entonces ha llamado la antención a muchos desarrolladores de diferentes campos.
Durante el segundo cuarto de este año me uní a ViVA XD, una plataforma de entretenimiento para vuelos que cambia el mundo en cada viaje. Elegimos Go para construir toda la infraestructura. Go era y es una elección óptima en términos de rendimiento y por su proceso de desarrollo rápido y sencillo.
En este artículo, veremos una breve introducción a Go y debería servir como motivación para aprender más.
Empezando
No tenía experiencia previa con Go y, como habitualmente cuando estudio un nuevo lenguaje, empece por consultar la página oficial de Golang. Encontré las instrucciones para instalarlo en mi sistema operativo y tutoriales, una muy buena documentación. Se trata del primer lenguaje de tipado estático con el que me he enfrentado. Recomiendo el Tour de Go, un tutorial interactivo para familiarizarse con la sintaxis y los literales. Terminé el tour en un par de días y me hice una idea de como funcionan las cosas en el entorno de Go, como variables, tipos, estructuras, punteros, listas, etc. En este punto aún no conocía todo acerca de Go, pero mi experiencia previa con otros lenguajes me permitió desarrollar mi pimera tarea en mi nuevo trabajo. Go te permite compilar el código fuente en un único binario para cualquier plataforma. Nuestra aplicación se ejecuta en Linux, así que si tuvieramos un desarrollador trabajando con Mac, lo podría compilas fácilmente
GOOS=linux go build y en cuestion de segundos tienes un compilado de Linux listo.
Profundizando
Me fui familiarizando con las sintaxis yo troas partes importantes de Go, las ‘gorutinas’, concurrencia, manejo de errores, paquetes, interfaces, asignaciones de dos valores, etc…
Sin excepciones
En Go, las funciones normalmente devuelven un valor y un error, pero no estamos limitados a sólo esto. Las funciones pueden devolver múltiples valores. Manejar errores en Go es sencillo, comprobamos el segundo valor retornado (o la posición donde se devuelve el error desde la función). Esta estructura es un buen modo de encadenar errores de un punto a otro.
type Server struct {}
func main() {
err := s.Run()
}
func (s *Server) Run() (err error) {
http.HandleFunc("/", s.handleHomeRequest)
err = http.ListenAndServe(":4000", nil)
if err != nil {
return err
}
return nil
}
Variables y declaraciones
En Go, tpdas las variables deben definirse, no podemos tener asignaciones tipo x = 2.
package main
import (
"fmt"
)
func main() {
var num int
num = 20
fmt.Printf("The number is %d\n", num)
}
Declaramos una variable llamada num de tipo int. Go, por defecto, asigna el valor cero a las variables. Los enteros valen 0, las booleanas falso, los strings «», … Con este patrón puedes pensar que habrá que teclear mucho, así que Go también tiene el operador :=
Así que podemos reescribir la declaración anterior como num := 20. Si se trata de una nueva variable, podemos usar :=
Asignación de dos valores
Los interfaces en Go so usan para hacer exactamente lo que están diseñados para hacer en cualquier lenguaje, que es agrupar
lógicamente código que tiene comportamiento parecido, no reducir el código.
En Go, cada tipo implementa al menos 0 métodos, lo que significa que cada tipo implement un interface{} especial 0. Esto es útil cuando desconocemos el tipo de variable.
var someData interface{}
err := json.Unmarshal(raw_bytes, &someData)
if err != nil {
log.Error(err)
}
Para obtener el tipo, usamos la aserción Type. Es una sentencia sencilla, si la aserción falla, el valor asignado tendrá el valor por defecto del tipo. Otra manera de hacer esto es usar la asignación de dos valores. Asignamos un segundo valor en la aserción del tipo que guardará una booleana indicando si ha tenido éxito.
jsonStruct := someData.(map[string]interface{})
num := jsonStruct["num"].(int)
str, ok := jsonStruct["str"].(string)
if !ok {
log.Error("error converting to string")
}
Lo mismo aplica para recuperar valores de un mapa
data := make(map[string]int)
data["result"] = 20
val, ok := data["result"] // returns false if key isn't found
if !ok {
log.info("Value for key not found!!")
}
Gorutinas
La mayoría de los lenguajes modernos como Python, Java, etc, se crearon desde un entorno de hilo único (no multi-hilo). La mayoría de ellos soporta multi-hilo, pero se enfrentan a ciertos problemas derivados de la ejecución concurrente, bloqueo de hilos o bloques mutuos. Esto hace que sea difícil crear una aplicación multi-hilo en estos lenguajes.
En Java, la creación de nuevos hilos es poco eficiente con respecto a la memoria. Cada hilo consume aproximadamente 1Mb de memora. Si necesitas lanzar miles de hilos, puedes llegar a cerrar la aplicación por falta de memoria. Además, la comunición entre dos hilos es muy complicada.
Go fue lanzado en 2009, cuando los procesadores multi-core ya estaban disponibles. Está construido teniendo en cuenta la concurrencia. Go tiene gorutinas en lugar de hilos. Consumes casi 2Kb de memoria, así que puedes lanzar millones de ellas en cualquier momento.
Algunos beneficios de usar gorutinas
- Las gorutinas evitan que tengamos que recurrir a cierres de exclusión mutua (mutex locking) cuando compartimos estructuras de datos.
- Las gorutinas se inincian más rápidamente que los hilos.
- Las gorutinas hacen uso de canales, un modo incorporado de comunicación entre ellos mismos.
- Las gorutinas y los hilos de sistema operativo no tienen un equivalencia 1 a 1. Una única gorutina puede ejecutarse en múltiples hilos. Las gorutinas se multiplexan en un pequño número de hilos de sistema operativo.
Más sobre concurrencia por Rob Pike (en inglés)
¿Escrito en Go? Fácil de mantener
Go omite intencionadamente muchas características de los lenguajes orientados a objetos modernos.
- No hay clases. Todo se divide en paquetes. Go sólo tiene structs.
- No hay soporte para herencia. Go hace que sea fácil de entender el código, ya que no hay super clases.
- No hay excepciones.
- No hay genéricos.
- No hay anotaciones
- No hay constructores
Mejorando
Después de consultar todos los recursos oficiales de Go, estuve buscando constantemente más documentación de Go. Alguno de los mejores que he encontrado son Go by example, Go Book, Effective Go, (en inglés).
Estos recursos me ayudaron y me siguen ayudando, aunque a veces sientes algo de frustración, acaba siendo divertido.
Conclusión
Go es muy diferente a otros lenguajes orientados a objetos, y tiene su lado bueno. Esta respaldado por Google y lo usan grandes compañías como IBM, Intel, Medium y Adobe
(https://github.com/golang/go/wiki/GoUsers)
Ya tenía experiencia en programación antes de aprender Go, así que la mayoría de conceptos no eran nuevos para mi, pero aún así Go es sencillo si eres principiante.
Puedes consultar el artículo original en inglés en:
https://dev.to/codehakase/how-i-learned-go-programming
Go es un excelente lenguaje de programación. Yo estoy llevando el curso gratis de Go en https://apuntes.de/golang
A mi me encanta Go, a pesar de algunas de sus fallas, como el verboso manejo de errores, creo que sus puntos fuertes: la velocidad de compilación y de desarrollo compensan las pocas fallas que tiene. Sin olvidar que debe usarse para lo que fue diseñado por google, vamos, no vas a culpar a Go por no ser un lenguaje para sistemas operativos.
Ciertamente Go no va a hacerte ver como un programador súper dotado, pero creo que tiene mucho que ofrecer si se abandona esa idea de que mientras más complejo y difícil sea un lenguaje mejor.