Programemos con Go: Organización del Código del Lenguaje Go
Spanish (Español) translation by Javier Salesi (you can also view the original English article)
Go es un lenguaje especial entre los lenguajes modernos. Es muy tajante. Por ejemplo, hay un formato cierto. Go te dirá cómo espaciar tu código y dónde colocar tus llaves. Pero va mucho más profundo que eso.
Go también te dirá cómo capitalizar tus funciones y variables para hacerlas públicas o privadas. Dictaminará la estructura del directorio de tu código. Ésto podría llegar como una sorpresa para los desarrolladores que vienen a Go desde lenguajes de programación más liberales.
En éste artículo, exploraré algunas de las restricciones de Go, discutiré sus méritos, y sugeriré opciones para situaciones comunes.
Proyecto Euler
Cuándo comencé a aprender Go, elaboré una solución al Problema #6 y sólo la puse en un subdirectorio junto con soluciones para otros problemas en otros lenguajes. Ver Proyecto Euler.
El problema es que Go no quiere que sólo coloques aleatoriamente los archivos Go por cualquier parte. Más tarde me dí cuenta que mientras si funciona en casos muy simples dónde no importas otros paquetes, en realidad no es adecuado.
Dependencias
Cada programa no trivial se compone de múltiples archivos o módulos o componentes o clases. Sólo usaré "archivo" como un término general. Con frecuencia están agrupados en librerías, paquetes o ensamblados. Sólo utilizaré "paquete" como un término general. El código que escribes depende del código en otros archivos y paquetes.
Necesitas decirle a tu código cómo encontrar esos paquetes y archivos para usar su funcionalidad. Cada lenguaje tiene su propio término: import (importar), include (incluir), require (requerir). Sólo usaré "importar" como término general.
Algunos lenguajes (o herramientas específicas del lenguaje) también te permiten instalar dependencias desde un repositorio de paquete remoto e instalarlas en una ubicación local estándar desde la que puedes importar.
En los lenguajes de programación más comunes, tienes mucha libertad. En C/C++, le dices al compilador/enlazador dónde están los archivos y las librerías estáticas (usando modificadores de la línea de comando o variables de entorno como INCLUDE_DIR). En Python, puedes instalar paquetes de PyPI usando setup.py o con pip de PyPI y repositorios de control remotos. Después importas basándote en la ruta de búsqueda del paquete sys.path.
A la Manera de Go
Go, como siempre, es más prescriptivo. Puede ofender tu creatividad que no puedas decidir dónde colocar las cosas, pero al final del día no importa realmente, y hay suficiente flexibilidad para atender varias situaciones.
Go requiere que coloques tu código en un espacio de trabajo. Un espacio de trabajo es sólo un directorio con tres subdirectorios: src, pkg y bin. Se recomienda que mantengas todos tus proyectos bajo un solo espacio de trabajo. De ésta forma pueden depender mutuamente y compartir paquetes de terceros.
Nota: Actualmente trabajo en Windows y uso PowerShell para muchos de los ejemplos interactivos. Para la siguiente sección, quería mostrar la estructura de directorios de mi espacio de trabajo usando el comando tree. Windows tiene su propio comando tree.exe, pero es muy limitado (no tiene niveles). Supuestamente hay un comando tree muy completo para Windows aquí.
Pero el sitio fue inalcanzable. Terminé disparando un contenedor de Docker ejecutando Ubuntu, montando mi espacio de trabajo Go como /docs/Go, y usando el comando tree de Linux para mostrarlo. Así que no te confundas si ves un entorno Linux mostrando directorios y archivos de Windows con extensiones .exe.
Aquí está mi actual espacio de trabajo en Go. El directorio bin contiene varios comandos/herramientas de Go, y el depurador delve. El directorio pkg tiene un subdirectorio con la plataforma (Win 64) que contiene los paquetes organizados por su origen (github.com, golang.com, etc.). El directorio src tiene subdirectorios similares para el repositorio o sitio web de origen (github.com, golan.org, etc.).
1 |
root@67bd4824f9d5:/docs/Go# tree -n -L 3 |
2 |
|
3 |
|-- bin |
4 |
| |-- dlv.exe |
5 |
| |-- go-outline.exe |
6 |
| |-- go-symbols.exe |
7 |
| |-- gocode.exe |
8 |
| |-- godef.exe |
9 |
| |-- golint.exe |
10 |
| |-- gometalinter.exe |
11 |
| |-- gopkgs.exe |
12 |
| |-- gorename.exe |
13 |
| |-- goreturns.exe |
14 |
| `-- guru.exe |
15 |
|-- pkg |
16 |
| `-- windows_amd64 |
17 |
| |-- github.com |
18 |
| |-- golang.org |
19 |
| |-- gopkg.in |
20 |
| `-- sourcegraph.com |
21 |
`-- src |
22 |
|-- github.com |
23 |
| |-- alecthomas |
24 |
| |-- derekparker |
25 |
| |-- go-web-crawler |
26 |
| |-- golang |
27 |
|
28 |
| |-- lukehoban |
29 |
| |-- multi-git |
30 |
| |-- newhook |
31 |
| |-- nsf |
32 |
| |-- rogpeppe |
33 |
| |-- tpng |
34 |
| `-- x |
35 |
|-- golang.org |
36 |
| `-- x |
37 |
|-- gopkg.in |
38 |
| `-- alecthomas |
39 |
`-- sourcegraph.com |
40 |
`-- sqs |
41 |
|
42 |
|
43 |
27 directories, 11 files |
44 |
Veamos lo que hay dentro de los proyectos origen que he creado bajo src : the go-web-crawler. Es muy simple aquí: sólo una lista llana de archivos Go, una licencia, y un archivo README.
1 |
root@67bd4824f9d5:/docs/Go# tree src/github.com/go-web-crawler/ -n
|
2 |
src/github.com/go-web-crawler/ |
3 |
|-- LICENSE |
4 |
|-- README.md |
5 |
|-- channel_crawl.go |
6 |
|-- main.go |
7 |
`-- sync_map_crawl.go |
8 |
|
9 |
0 directories, 5 files |
GOROOT y GOPATH
Dos variables de entorno controlan tu destino en la tierra de Go. GOROOT es dónde está la instalación de Go:
1 |
09:21:26 C:\Users\the_g\Documents\Go> ls Env:\GOROOT |
2 |
|
3 |
Name Value |
4 |
---- ----- |
5 |
GOROOT C:\Go\ |
6 |
|
7 |
09:21:35 C:\Users\the_g\Documents\Go> ls c:\go |
8 |
|
9 |
|
10 |
Directory: C:\go |
11 |
|
12 |
|
13 |
Mode LastWriteTime Length Name |
14 |
---- ------------- ------ ---- |
15 |
d----- 8/16/2016 10:38 AM api |
16 |
d----- 8/16/2016 10:38 AM bin |
17 |
d----- 8/16/2016 10:38 AM blog |
18 |
d----- 8/16/2016 10:38 AM doc |
19 |
d----- 8/16/2016 10:38 AM lib |
20 |
d----- 8/16/2016 10:38 AM misc |
21 |
d----- 8/16/2016 10:38 AM pkg |
22 |
d----- 8/16/2016 10:38 AM src |
23 |
d----- 8/16/2016 10:38 AM test |
24 |
-a---- 8/16/2016 1:48 PM 29041 AUTHORS |
25 |
-a---- 8/16/2016 1:48 PM 1168 CONTRIBUT |
26 |
-a---- 8/16/2016 1:48 PM 40192 CONTRIBUT |
27 |
-a---- 8/16/2016 1:48 PM 1150 favicon.i |
28 |
-a---- 8/16/2016 1:48 PM 1479 LICENSE |
29 |
-a---- 8/16/2016 1:48 PM 1303 PATENTS |
30 |
-a---- 8/16/2016 1:48 PM 1638 README.md |
31 |
-a---- 8/16/2016 1:48 PM 26 robots.tx |
32 |
-a---- 8/16/2016 1:48 PM 5 VERSION |
Nota que el directorio raíz de Go parece un superconjunto de un espacio de trabajo con los directorios src, bin y pkg.
GOPATH apunta a tu espacio de trabajo. Así es como Go encuentra tu código.
1 |
09:21:53 C:\Users\the_g\Documents\Go> ls Env:\GOPATH |
2 |
|
3 |
Name Value |
4 |
---- ----- |
5 |
GOPATH c:\Users\the_g\Documents\Go |
Hay un montón de otras variables de entorno relacionadas con Go, muchas de las cuáles requeriste establecer en el pasado (por ejemplo, GOOS y GOARH ). Ahora son opcionales, y no deberías meterte con ellas a menos que realmente lo necesites (por ejemplo, cuándo se hace una compilación múltiple). Para ver todas las variables de entorno de Go, escribe: go env .
1 |
09:51:10 C:\Users\the_g> go env |
2 |
set GOARCH=amd64 |
3 |
set GOBIN= |
4 |
set GOEXE=.exe |
5 |
set GOHOSTARCH=amd64 |
6 |
set GOHOSTOS=windows |
7 |
set GOOS=windows |
8 |
set GOPATH=c:\Users\the_g\Documents\Go |
9 |
set GORACE= |
10 |
set GOROOT=C:\Go |
11 |
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64 |
12 |
set CC=gcc |
13 |
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 |
14 |
set CXX=g++ |
15 |
set CGO_ENABLED=1 |
Instalar e importar
Cuándo creas un programa o librería en Go, puedes instalarla. Los programas van al directorio bin de tu espacio de trabajo, y las librerías van al directorio pkg del espacio de trabajo. En Windows, descubrí que tu %GOPATH%/bin no está en el directorio %PATH%, así que Windows no pudo encontrar mi ejecutable. Lo agregué al PATH de Windows y todo funcionó. Aquí está cómo revisar en PowerShell que tu PATH contenga el directorio bin en tu espacio de trabajo:
1 |
10:56:19 C:\Users\the_g> $env:path.split(";") | grep go |
2 |
|
3 |
C:\Go\bin |
4 |
c:\Users\the_g\Documents\Go\bin |
Veamos todo ello en acción.
Si voy a mi directorio go-web-crawler y escribo go install entonces go-web-crawler.exe es creado en c:\Users\the_g\Documents\Go\bin :
1 |
11:09:18 C:\Users\the_g> ls $env:GOPATH/bin |
2 |
|
3 |
|
4 |
Directory: C:\Users\the_g\Documents\Go\bin |
5 |
|
6 |
|
7 |
Mode LastWriteTime Length Name |
8 |
---- ------------- ------ ---- |
9 |
-a---- 8/15/2016 11:05 AM 15891456 dlv.exe |
10 |
-a---- 8/15/2016 10:08 AM 3972608 go-outline.exe |
11 |
-a---- 8/15/2016 10:10 AM 4502528 go-symbols.exe |
12 |
-a---- 9/18/2016 10:14 AM 1849856 go-web-crawler.exe |
13 |
-a---- 8/15/2016 10:08 AM 12097024 gocode.exe |
14 |
-a---- 8/15/2016 10:17 AM 6642688 godef.exe |
15 |
-a---- 8/15/2016 9:32 AM 6625792 golint.exe |
16 |
-a---- 8/15/2016 10:14 AM 6352896 gometalinter.exe |
17 |
-a---- 8/15/2016 10:10 AM 2738688 gopkgs.exe |
18 |
-a---- 8/15/2016 10:10 AM 6961152 gorename.exe |
19 |
-a---- 8/15/2016 10:09 AM 7291904 goreturns.exe |
20 |
-a---- 8/15/2016 10:11 AM 9722368 guru.exe |
Ahora puedo ejecutarlo desde mi web crawler de Go desde cualquier lugar.
1 |
11:10:32 C:\Users\the_g> go-web-crawler.exe |
2 |
|
3 |
found: http://golang.org/ "The Go Programming Language" |
4 |
found: http://golang.org/cmd/ "" |
5 |
not found: http://golang.org/cmd/ |
6 |
found: http://golang.org/pkg/ "Packages" |
7 |
found: http://golang.org/pkg/os/ "Package os" |
8 |
found: http://golang.org/pkg/fmt/ "Package fmt" |
9 |
found: http://golang.org/ "The Go Programming Language" |
Múltiples Entornos en Go
Eso está muy bien, pero a veces la vida no es tan sencilla. Puedes querer tener múltiples espacios de trabajo separados. Es más, puedes querer tener múltiples instalaciones de Go (por ejemplo, diferentes versiones) y múltiples espacios de trabajo para cada una. Puedes hacer ésto al establecer dinámicamente GOPATH para cambiar el espacio de trabajo y establecer GOROOT para cambiar la instalación activa de Go.
Hay varios proyectos de código abierto para gestión de paquetes, dependencias y entornos virtuales. Por alguna razón, la mayoría no soportan Windows. No estoy seguro por qué tales herramientas tienen que ser para una plataforma específica. Puedo escribir un gestor de entorno Go multiplataforma por mí mismo uno de éstos días.
Conclusión
Go se trata de eliminar la complejidad incidental. A veces viene como muy estricto y prescriptivo. Pero si te pones a pensar como los diseñadores que utilizan Go, empiezas a comprender que el evitar, prohibir u obligar a ciertas cosas realmente hace todo más sencillo.



