Cómo organizar un proyecto Go con múltiples archivos: bajo el capó

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Un proyecto Go de un solo archivo es fácil. ¿Y de diez?

\n\n

Imagina: estás escribiendo una utilidad en Go para analizar registros. Al principio, todo cabe en un solo archivo main.go. Funciona, todo perfecto. Pero después de una semana, el código crece: aparecen funciones para leer archivos, para filtrar, para enviar datos a la base de datos. Un solo archivo se convierte en un monstruo de 2000 líneas. ¿Te suena familiar?

\n\n

Aquí surge la pregunta que atormenta a uno de cada dos principiantes (y que ha acumulado miles de visitas en Stack Overflow): ¿cómo organizar correctamente un proyecto Go con múltiples archivos? No solo esparcir el código en carpetas, sino hacerlo de manera que funcione, se compile y no genere errores como undefined o import cycle not allowed.

\n\n

En este artículo, no solo te daremos una plantilla. Miraremos bajo el capó del compilador de Go y entenderemos cómo funciona realmente la combinación de archivos, paquetes y módulos. Aprenderás por qué go run *.go a veces salva y a veces no, y cómo construir una arquitectura que escale.

\n\n

Archivo, paquete, módulo: la jerarquía básica

\n\n

Antes de lanzarnos al código, analicemos tres conceptos clave. Sin ellos, la organización de un proyecto Go se convierte en un juego de adivinanzas.

\n\n
    \n
  • Archivo (.go) — es simplemente un archivo de texto con código. Por sí mismo, no significa nada para el compilador.
  • \n
  • Paquete (package) — es un grupo lógico de archivos que se encuentran en el mismo directorio. Todos los archivos en una carpeta deben tener la misma declaración package. Si en la carpeta hay archivos con diferentes paquetes, el compilador mostrará un error.
  • \n
  • Módulo (go.mod) — es la raíz de tu proyecto. Define el nombre del módulo, sus dependencias y las versiones de Go. Un módulo puede contener muchos paquetes.
  • \n
\n\n

Regla de oro: un directorio = un paquete. La excepción son las pruebas, pero hablaremos de eso más adelante.

\n\n

Ejemplo práctico: proyecto "Analizador de registros"

\n\n

Vamos a crear un pequeño proyecto que lea un archivo de registro, filtre las líneas por una palabra clave y muestre el resultado. Lo haremos primero "a lo bruto" (un solo archivo) y luego lo dividiremos correctamente en varios archivos.

\n\n

Etapa 1: Todo en un solo archivo (mal)

\n\n
// main.go\npackage main\n\nimport (\n    "bufio"\n    "fmt"\n    "os"\n    "strings"\n)\n\nfunc readLog(path string) ([]string, error) {\n    file, err := os.Open(path)\n    if err != nil {\n        return nil, err\n    }\n    defer file.Close()\n\n    var lines []string\n    scanner := bufio.NewScanner(file)\n    for scanner.Scan() {\n        lines = append(lines, scanner.Text())\n    }\n    return lines, scanner.Err()\n}\n\nfunc filterLines(lines []string, keyword string) []string {\n    var result []string\n    for _, line := range lines {\n        if strings.Contains(line, keyword) {\n            result = append(result, line)\n        }\n    }\n    return result\n}\n\nfunc main() {\n    lines, err := readLog("server.log")\n    if err != nil {\n        fmt.Println("Error:", err)\n        return\n    }\n    filtered := filterLines(lines, "ERROR")\n    for _, l := range filtered {\n        fmt.Println(l)\n    }\n}\n
\n\n

Funciona. Pero imagina que readLog se vuelve más complejo (necesita soporte para gzip, codificaciones) y filterLines se llena de expresiones regulares. El archivo se volverá ilegible.

\n\n

Etapa 2: Dividir en paquetes (bien)

\n\n

Creemos la estructura de directorios:

\n\n
log-analyzer/\n├── go.mod\n├── main.go\n└── pkg/\n    └── logreader/\n        ├── reader.go\n        └── filter.go\n
\n\n

Inicializamos el módulo:

\n\n
go mod init log-analyzer
\n\n

Ahora escribamos el código del paquete logreader. Observa: todos los archivos en la carpeta pkg/logreader/ tienen package logreader.

\n\n

pkg/logreader/reader.go

\n\n
package logread                

Blogs

Book Recommendations