Introducción
En el artículo anterior expliqué los módulos en Go. Los módulos definen qué es un proyecto: el perímetro, su identidad global y la base sobre la que se construyen las dependencias y la reproducibilidad.
Sin embargo, un módulo por sí solo no organiza el código internamente ni establece límites entre unas partes y otras. Un módulo puede crecer sin control, con cientos o miles de archivos compartiendo el mismo espacio conceptual. Para resolver este problema, Go introduce su siguiente concepto fundamental: los paquetes.
Este artículo explica qué es un paquete en Go, qué reglas impone el lenguaje, cómo se estructuran los proyectos y por qué la simplicidad del sistema de paquetes es una de las claves de la claridad y mantenibilidad del código Go.
Paquetes en Go
Un paquete es la unidad básica de organización y encapsulación del código en Go. Un paquete agrupa código que:
- Está relacionado conceptualmente.
- Comparte un mismo espacio de nombres.
- Se compila como una unidad.
- Define qué símbolos expone y cuáles mantiene internos
En Go los paquetes no son opcionales:
- Todo archivo .go pertenece obligatoriamente a un paquete.
- Un archivo .go no puede pertenecer a más de un paquete.
- No existe código “suelto” que no pertenezca a ningún paquete.
Para entenderlo sin rodeos: en Go, un módulo representa un proyecto completo. Define su identidad, su versión y sus dependencias. Un módulo está compuesto por uno o varios paquetes. Los paquetes son las piezas en las que se organiza el código fuente. Y cada paquete cumple una responsabilidad concreta dentro del proyecto. Los paquetes viven siempre dentro de un módulo.
Ejemplo típico de estructura:
mi-proyecto/
├── go.mod
├── main.go
├── config/
│ └── config.go
├── server/
│ └── server.go
└── storage/
└── storage.go
Aquí tenemos:
- Un módulo (mi-proyecto, definido en go.mod)
- Varios paquetes: main, config, server, storage
Un directorio, un paquete
Go impone una regla simple pero muy estricta:
Cada directorio del proyecto define exactamente un paquete
Esto tiene varias consecuencias importantes:
- Todos los archivos .go dentro de un mismo directorio deben declarar el mismo
package. - No puedes mezclar varios paquetes en un mismo directorio.
- La estructura de carpetas refleja directamente la estructura lógica del código.
Ejemplo:
// archivo: server/server.go
package server
...
// archivo: server/router.go
package server
...
Ambos archivos pertenecen al mismo paquete server y Go los compila como una sola unidad lógica.
Declaración del paquete
En Go, todo archivo fuente debe comenzar con una declaración package:
package nombre_del_paquete
Esta línea determina a qué paquete pertenece el fichero fuente. En este ejemplo:
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("Hola mundo")
}
el fichero fuente main.go pertenece al paquete main.
Esta línea es obligatoria para que el código compile. Si no defines package:
$ cat main.go
import "fmt"
func main() {
fmt.Println("Hola mundo")
}
se genera un error de compilación:
$ go run main.go
main.go:3:1: expected 'package', found 'import'
El nombre del paquete no tiene por qué coincidir con el nombre del directorio, pero hacerlo es una convención fuertemente recomendada. No seguirla genera confusión innecesaria.
Tipos de paquetes en Go
En Go existen dos grandes categorías de paquetes:
- El paquete main
- Los paquetes de librería
El paquete main
El paquete main es especial. Indica que el código es un programa ejecutable.
Un programa ejecutable en Go debe cumplir dos condiciones:
- Contener un paquete llamado
main - Definir una función
main()
Ejemplo:
package main
import "fmt"
func main() {
fmt.Println("Hola, mundo")
}
Características importantes:
- Solo puede existir un paquete
mainpor binario ejecutable - El paquete
mainno está pensado para ser reutilizado - Es el punto de entrada del programa (entry point).
- La función main() no recibe parámetros ni devuelve valores.
Paquetes de librería
Todo lo que no sea un binario ejecutable es un paquete de librería. Los paquetes de librería:
- No se ejecutan por sí solos.
- Encapsulan funcionalidad reutilizable.
- Están pensados para ser usados desde otros paquetes
Ejemplo:
package mathutils
func Sum(a, b int) int {
return a + b
}
Normas de nomenclatura
Algunas normas que se siguen habitualmente:
- Usa nombres cortos, claros y en singular: json, http, server
- Evita nombres genéricos: utils, common, helpers
Paquetes con múltiples archivos
Un paquete puede contener tantos archivos como sea necesario:
mathutils/
├── add.go
├── multiply.go
└── helpers.go
Todos los ficheros de este paquete declaran:
package mathutils
Los símbolos no exportados son visibles entre todos los archivos del paquete, lo que permite dividir código en varios ficheros fuente sin perder encapsulación.
Paquetes de la librería estándar
Go incluye una biblioteca estándar muy rica y bien diseñada:
| Librería | Uso |
|---|---|
| fmt | formateo de texto y operaciones de entrada/salida básicas |
| net/http | servidores y clientes HTTP completos |
| encoding/json | codificación y decodificación JSON |
| os | interacción con el sistema operativo (archivos, procesos, entorno) |
| io | abstracciones e interfaces fundamentales de entrada/salida |
| time | manejo de tiempo, duraciones y temporizadores |
| sync | primitivas de sincronización para concurrencia segura |
Con la librería estándar podrías hacer prácticamente cualquier proyecto sin usar librerías externas. Aquí puedes encontrar la documentación oficial de la librería estándar. Si quieres aprender Go en serio, explorarla es una obligación.
Puedes usar la herramienta go doc para revisar la documentación oficial desde la línea de comandos:
$ go doc fmt
Conclusión
Si los módulos definen el perímetro del proyecto, los paquetes definen su arquitectura interna.
Go apuesta por reglas simples y explícitas: un directorio es un paquete, no hay magia y no hay ambigüedad. Entender bien los paquetes es esencial para escribir código Go claro, mantenible y idiomático.
El módulo ya está definido, el código ya está organizado. Ahora toca entender cómo colaboran estas piezas entre sí: cómo se comunican los paquetes, cómo se diseñan APIs internas y cómo evitar acoplamientos innecesarios.
¿Has aprendido algo leyendo este artículo? Únete al canal de Telegram del blog, y cuéntame qué tema te gustaría que abordara a continuación. Allí respondo personalmente a cada pregunta planteada. Muchas gracias por leerme y nos vemos en el próximo artículo!
Pulso la tecla ESC, dos puntos wq!
Use the share button below if you liked it.
There's not much you can do without a CPU.