Ir al contenido
  1. Blog/

Cómo empezar un proyecto en Go

·6 mins·
Empecemos un proyecto en Go.

¿Espera, Go? #

Go, o Golang, es un lenguaje de programación introducido por Google en Noviembre de 2009. Su característica distintiva es su enfoque a la concurrencia de procesos. Es utilizado principalmente en el desarrollo de la nube, herramientas de terminal, desarrollo web y devops.

Como nos comentan nuestros amigos de JetBrains, Go está dentro de los 10 primeros lenguages por uso profesional, con un porcentaje del 7%, y se posiciona como un jugador importante en la industria financiera y la nube. Muchas de las herramientas de infraestructura de software como Docker, Kubernetes y Vault, por nombrar algunas de las más importantes, están escritas en Go.

Instalar Go #

Para continuar, debes instalar Go si aún no lo haz hecho. El cómo hacerlo dependerá de la plataforma desde dónde nos lees.

Linux #

Dependerá de tu distro. Googlea “instalar golang {tu distro}”. Si usas Fedora, como yo, ejecuta el siguiente comando:

$ sudo dnf install golang

Una vez completado, verifica la instalación.

$ go version
go version go1.20.8 linux/amd64

Mac & Windows #

Puedes encontrar los binarios aquí: https://go.dev/dl/.

Organización de archivos #

En Go, organizamos el código en paquetes que a su vez se agrupan en módulos. Estos paquetes específican sus propias dependencias y la versión de Go con la cuál funcionan.

go mod init #

Creemos nuestro primer módulo en Go. Hagamos una bonita calculadora.

En el directorio de tu elección, en mi caso ~/Source/go-calculator, ejecuta el siguiente comando.

$ go mod init {path}/go-calculator

Lo qué escribimos después de init debe ser el path desde dónde Go tools descargará nuestro módulo cuando este sea declarado como dependencia en otro módulo. Por lo general, un repositorio en línea. En mi caso: github.com/mariomenjr.

$ go mod init github.com/mariomenjr/go-calculator
go: creating new go.mod: module github.com/mariomenjr/greetings

Verás que un archivo go.mod ha sido creado en la raíz de tu proyecto. La función de este archivo es manejar las dependencias de tu proyecto. Conforme añades dependencias, este archivo registrará las versiones de los módulos en los cuáles depende tu aplicación.

main.go #

El punto de entrada un ejecutable escrito en Go es el paquete main, específicamente la función main. Crea un archivo main.go en la raíz de tu proyecto con el siguiente contenido, el nombre del archivo es opcional.

 1package main // nombre del paquete
 2
 3import "fmt" // importar dependencias
 4
 5func sum(a int, b int) int {
 6	return a + b
 7}
 8
 9func main() { // función inicio requerida
10
11	a := 1
12	b := 2
13
14	rs := sum(a, b)
15	fmt.Printf("%v + %v = %v\n", a, b, r)
16}

Lo ejecutamos.

$ go run main.go
1 + 2 = 3

Instalar una dependencia #

Ya que hemos creado nuestra primera aplicación, es hora de mejorarla. Para ello, instalaremos un módulo externo.

$ go get github.com/mariomenjr/handlr
go: downloading github.com/mariomenjr/handlr v0.1.0-alpha.9
go: added github.com/mariomenjr/handlr v0.1.0-alpha.9

Después de ejecutar el comando anterior, verás cómo el archivo go.mod ahora lista la nueva dependencia.

module github.com/mariomenjr/go-calculator

go 1.20

require github.com/mariomenjr/handlr v0.1.0-alpha.9 // indirect

El módulo que acabamos de instalar nos permitirá llevar nuestra calculadora a la web.

Para continuar, cambia el contenido de main.go por el siguiente.

 1package main // nombre del paquete
 2
 3import ( // importar dependencias
 4	"fmt"
 5	"net/http"
 6	"strconv"
 7
 8	"github.com/mariomenjr/handlr"
 9)
10
11func sumHandler(w http.ResponseWriter, r *http.Request) {
12	q := r.URL.Query()
13
14	a, _ := strconv.Atoi(q.Get("a"))
15	b, _ := strconv.Atoi(q.Get("b"))
16
17    rs := a + b
18
19	s := fmt.Sprint("<html><title>go-calculator</title><body>", a, " + ", b, " = ", rs, "</body></html>")
20
21	w.Write([]byte(s))
22}
23
24func main() { // función inicio requerida
25	h := handlr.New()
26
27	h.HandleFunc("/sum", sumHandler)
28	h.Start(1993)
29}

Otra vez ejecutamos el siguiente comando.

$ go run main.go
> Server started on port :1993

A diferencia de la vez anterior, no verás el resultado en la línea de comandos sino que debes abrir el siguiente enlace en tu navegador: http://localhost:1993/sum?a=1&b=2.

Ahora podemos modificar los valores de a y b en la URL.

Multiples paquetes #

El paquete main es el único paquete que existe en nuestro proyecto hasta ahora. A medida que tu base de código crece, lo más probable es que quieras organizar tu código acorde a su funcionalidad. Para conseguirlo, podemos crear multiples paquetes dentro de nuestro módulo.

Cada directorio puede contener un paquete, como ya existe uno en la raíz de nuestro proyecto debemos crear sub-directorios por cada nuevo paquete a implementar.

Tomando en cuenta lo anterior, creemos un paquete exclusivamente para los cálculos matemáticos y otro que nos permita construir la presentación de los resultados en el navegador. Todo esto vive actualmente en el archivo main.go.

~/Sources/go-calculator/
    main.go
    go.mod
    go.sum
    math/
        sum.go
    html/
        index.go

En el archivo math/sum.go, pega el siguiente contenido.

1package math
2
3func Sum(a int, b int) int {
4	return a + b
5}

Seguido del contenido para el archivo html/index.go.

 1package html
 2
 3import (
 4	"fmt"
 5	"net/http"
 6)
 7
 8func htmlEngine(content string) []byte {
 9    s := fmt.Sprint("<html><title>go-calculator</title><body>", content, "</body></html>")
10    return []byte(s)
11}
12
13func RenderResult(w http.ResponseWriter, content string) {
14
15	s := fmt.Sprint("<html><title>go-calculator</title><body>", content, "</body></html>")
16	w.Write(htmlEngine(content))
17}

Nota la diferencia en el “casing” del nombre de las funciones. Mientras que la función htmlEngine inicia en minúscula, RenderResult lo hace en mayúscula. Esto le dice a Go que la segunda función debe ser accesible desde otros paquetes dónde se importe este; mientras que la primera, en minúscula, solamente es accesible desde el paquete html.

Finalmente, hagamos los ajustes necesarios en el archivo main.go.

 1package main // package name
 2
 3import (
 4	"fmt"
 5	"net/http"
 6	"strconv"
 7
 8	"github.com/mariomenjr/go-calculator/html"
 9	"github.com/mariomenjr/go-calculator/math"
10	"github.com/mariomenjr/handlr"
11)
12
13func sumHandler(w http.ResponseWriter, r *http.Request) {
14	q := r.URL.Query()
15
16	a, _ := strconv.Atoi(q.Get("a"))
17	b, _ := strconv.Atoi(q.Get("b"))
18
19	rs := math.Sum(a, b)
20
21	html.RenderResult(w, fmt.Sprint(a, " + ", b, " = ", rs))
22}
23
24func main() {
25	h := handlr.New()
26
27	h.HandleFunc("/sum", sumHandler)
28	h.Start(1993)
29}

./internal/ #

Nuestro proyecto es una aplicación web que nos permite sumar dos números y nos muestra el resultado en el navegador. Sin embargo, podríamos crear un módulo separado que se encargue exclusivamente de los cálculos e importarlo desde esta aplicación cómo una dependencia.

En ese caso, es muy probable que queramos limitar los paquetes a los cuales tenemos acceso. No es una buena idea exponer métodos o paquetes que solo nos ayudan con tareas internas. Al limitar este acceso, somos libres de refactorizar cualquier paquete o método interno sin miedo a afectar a los usuarios del módulo.

Basta simplemente con mover esos paquetes que no queramos exponer a otros módulos al directorio internal. Por ejemplo, en nuestra aplicación web, los directorios quedarían así.

~/Sources/go-calculator/
    main.go
    go.mod
    go.sum
    internal/
        math/
            sum.go
        html/
            index.go

Ahora cambiamos la forma en la cuál esta dependencia interna es importada por el módulo en el archivo main.go.

 6	"strconv"
 7
 8	"github.com/mariomenjr/go-calculator/internal/html"
 9	"github.com/mariomenjr/go-calculator/internal/math"
10	"github.com/mariomenjr/handlr"
11)
12
13func sumHandler(w http.ResponseWriter, r *http.Request) {

Hay mucho más #

Con lo anterior, te mostré los pasos básicos para empezar tu proyecto en Go. Este lenguaje tiene muchas características interesantes que descubrirás a medida que profundices en él. Te animo a leer la documentación oficial para obtener más detalles. En algún momento escribiré más acerca de mi aprendizaje de Go.

À bientôt.

Referencias #