12 Indispensable Go Paquetes y Librerías
Spanish (Español) translation by James (you can also view the original English article)
Go es un lenguaje asombroso con mucho ímpetu, y se centra en la simplicidad. Este enfoque es evidente en su biblioteca estándar, que proporciona todo lo necesario, pero no mucho más.
Afortunadamente, Go tiene una vibrante comunidad que crea y comparte un montón de librerías de terceros. En este tutorial, te introduzco a 12 de Go mejores paquetes y bibliotecas. Algunas de ellas tienen alcance relativamente estrecho y pueden agregarse a cualquier proyecto, mientras que otros son grandes proyectos que usted puede incorporar en sistemas distribuidos a gran escala, masivos.
Awesome Go
Antes de zambullirse en las bibliotecas de sí mismos, permítanme presentarles a Awesome Go, una lista muy activa y curada de Go bibliotecas y otros recursos. Debe visitar de vez en cuando y comprobar lo nuevo.
1. Set de Golang
Go tiene arreglos de discos, láminas y mapas, pero no tiene una estructura de datos del sistema. Puede imitar un conjunto con un mapa de bools, pero es bueno tener un tipo de datos reales con las operaciones de derecha y semántica. Esto es donde golang-set. Aquí es un ejemplo básico de crear un nuevo conjunto, agregar elementos y pruebas para ser miembro:
1 |
package main |
2 |
|
3 |
import ( |
4 |
"fmt" |
5 |
"github.com/deckarep/golang-set" |
6 |
) |
7 |
|
8 |
|
9 |
func main() {
|
10 |
basicColors := mapset.NewSet() |
11 |
basicColors.Add("Red")
|
12 |
basicColors.Add("Blue")
|
13 |
basicColors.Add("Green")
|
14 |
|
15 |
if basicColors.Contains("Green") {
|
16 |
fmt.Println("Yay! 'Green' is a basic color")
|
17 |
} else {
|
18 |
fmt.Println("What a disappointment! 'Green' is not a basic color")
|
19 |
} |
20 |
|
21 |
|
22 |
if basicColors.Contains("Yellow") {
|
23 |
fmt.Println("Yay! 'Yellow' is a basic color")
|
24 |
} else {
|
25 |
fmt.Println("What a disappointment! 'Yellow' is not a basic color")
|
26 |
} |
27 |
} |
28 |
|
29 |
Output: |
30 |
|
31 |
Yay! 'Green' is a basic color |
32 |
What a disappointment! 'Yellow' is not a basic color |
Observe que el nombre del paquete es "mapset". Además de lo básico, es realizar todos las operaciones Unión, intersección y diferencia. Usted también puede iterar sobre los valores:
1 |
package main |
2 |
|
3 |
import ( |
4 |
"fmt" |
5 |
"github.com/deckarep/golang-set" |
6 |
) |
7 |
|
8 |
|
9 |
func main() {
|
10 |
basicColors := mapset.NewSet() |
11 |
basicColors.Add("Red")
|
12 |
basicColors.Add("Blue")
|
13 |
basicColors.Add("Green")
|
14 |
|
15 |
otherColors := mapset.NewSetFromSlice([]interface{}{"Orange", "Yellow", "Indigo", "Violet"})
|
16 |
rainbowColors := basicColors.Union(otherColors) |
17 |
|
18 |
for color := range rainbowColors.Iterator().C {
|
19 |
fmt.Println(color) |
20 |
} |
21 |
} |
2. Color
Continuemos con el tema de color. Al escribir programas de línea de comandos, es útil utilizar colores para destacar mensajes importantes o distinguir entre errores, éxitos y advertencias.
El paquete de color da una manera fácil de añadir color a sus programas (ver lo que hice allí?). ¡Utiliza códigos de escape ANSII y soporta Windows también! Aquí está un ejemplo rápido:
1 |
package main |
2 |
|
3 |
import ( |
4 |
"github.com/fatih/color" |
5 |
) |
6 |
|
7 |
func main() {
|
8 |
color.Red("Roses are red")
|
9 |
color.Blue("Violets are blue")
|
10 |
} |
Las ayudas del paquete de color mezclando colores con los colores de fondo, estilos como negrita o cursiva y riego color con salida sin color.
1 |
package main |
2 |
|
3 |
import ( |
4 |
"github.com/fatih/color" |
5 |
"fmt" |
6 |
) |
7 |
|
8 |
func main() {
|
9 |
minion := color.New(color.FgBlack).Add(color.BgYellow).Add(color.Bold) |
10 |
minion.Println("Minion says: banana!!!!!!")
|
11 |
|
12 |
m := minion.PrintlnFunc() |
13 |
m("I want another banana!!!!!")
|
14 |
|
15 |
slantedRed := color.New(color.FgRed, color.BgWhite, color.Italic).SprintFunc() |
16 |
fmt.Println("I've made a huge", slantedRed("mistake"))
|
17 |
} |
El paquete de color tiene otras características útiles. Seguir adelante y explorar más.
3. Now
Now es un paquete muy simple que proporciona un contenedor de comodidad para el paquete de tiempo estándar y facilita trabajar con varias construcciones de fecha y hora en la época actual.
Por ejemplo, puede llegar el principio del minuto actual o al final del domingo más cercano a la hora actual. Aquí es cómo utilizar "Now":
1 |
package main |
2 |
|
3 |
import ( |
4 |
"github.com/jinzhu/now" |
5 |
"fmt" |
6 |
) |
7 |
|
8 |
func main() {
|
9 |
|
10 |
fmt.Println("All the beginnings...")
|
11 |
fmt.Println(now.BeginningOfMinute()) |
12 |
fmt.Println(now.BeginningOfHour()) |
13 |
fmt.Println(now.BeginningOfDay()) |
14 |
fmt.Println(now.BeginningOfWeek()) |
15 |
fmt.Println(now.BeginningOfMonth()) |
16 |
fmt.Println(now.BeginningOfQuarter()) |
17 |
fmt.Println(now.BeginningOfYear()) |
18 |
|
19 |
} |
20 |
|
21 |
Output: |
22 |
|
23 |
All the beginnings... |
24 |
2017-06-04 16:59:00 -0700 PDT |
25 |
2017-06-04 16:00:00 -0700 PDT |
26 |
2017-06-04 00:00:00 -0700 PDT |
27 |
2017-06-04 00:00:00 -0700 PDT |
28 |
2017-06-01 00:00:00 -0700 PDT |
29 |
2017-04-01 00:00:00 -0700 PDT |
30 |
2016-12-31 23:00:00 -0800 PST |
Puede también analizar tiempos y añadir sus propios formatos (que serán necesario actualizar los formatos conocidos). El tipo Now incorpora time.Time, así que puede usar métodos time.Time de tiempo directamente en objetos de Now.
4. Gen
La herramienta gen genera código para usted, en particular, que tipo de código que intenta paliar el vacío de no tener plantillas o genéricos en Go.
Anota los tipos con un comentario especial, y gen genera archivos de origen que se incluyen en el proyecto. No hay magia de tiempo de ejecución. Veamos un ejemplo. Aquí es un tipo de anotación.
1 |
// +gen slice:"Where,Count,GroupBy[int]" |
2 |
type Person struct {
|
3 |
Name string |
4 |
Age int |
5 |
} |
Ejecutando gen (Asegúrese de que esté en tu camino) genera person_slice.go:
1 |
// Generated by: gen |
2 |
// TypeWriter: slice |
3 |
// Directive: +gen on Person |
4 |
|
5 |
package main |
6 |
|
7 |
// PersonSlice is a slice of type Person. Use it where you would use []Person. |
8 |
type PersonSlice []Person |
9 |
|
10 |
// Where returns a new PersonSlice whose elements return true for func. See: https://clipperhouse.github.io/gen/#Where |
11 |
func (rcv PersonSlice) Where(fn func(Person) bool) (result PersonSlice) {
|
12 |
for _, v := range rcv {
|
13 |
if fn(v) {
|
14 |
result = append(result, v) |
15 |
} |
16 |
} |
17 |
return result |
18 |
} |
19 |
|
20 |
// Count gives the number elements of PersonSlice that return true for the passed func. See: http://clipperhouse.github.io/gen/#Count |
21 |
func (rcv PersonSlice) Count(fn func(Person) bool) (result int) {
|
22 |
for _, v := range rcv {
|
23 |
if fn(v) {
|
24 |
result++ |
25 |
} |
26 |
} |
27 |
return |
28 |
} |
29 |
|
30 |
// GroupByInt groups elements into a map keyed by int. See: http://clipperhouse.github.io/gen/#GroupBy |
31 |
func (rcv PersonSlice) GroupByInt(fn func(Person) int) map[int]PersonSlice {
|
32 |
result := make(map[int]PersonSlice) |
33 |
for _, v := range rcv {
|
34 |
key := fn(v) |
35 |
result[key] = append(result[key], v) |
36 |
} |
37 |
return result |
38 |
} |
El código proporciona LINQ-like métodos para operar en el tipo de PersonSlice. Es fácil de entender y muy bien documentado.
Aquí es cómo usarlo. En la función principal, se define un PersonSlice. La función age() selecciona el campo de la edad de su argumento Person. La función GroupByInt() genera la función age() y vuelve la gente de la rebanada agrupada por su edad (34 es a Jim, pero 23 tiene Jane y Kyle).
1 |
package main |
2 |
|
3 |
import ( |
4 |
"fmt" |
5 |
) |
6 |
|
7 |
// +gen slice:"Where,Count,GroupBy[int]" |
8 |
type Person struct {
|
9 |
Name string |
10 |
Age int |
11 |
} |
12 |
|
13 |
func age(p Person) int {
|
14 |
return p.Age |
15 |
} |
16 |
|
17 |
func main() {
|
18 |
people := PersonSlice {
|
19 |
{"Jim", 34},
|
20 |
{"Jane", 23},
|
21 |
{"Kyle", 23},
|
22 |
} |
23 |
|
24 |
groupedByAge := people.GroupByInt(age) |
25 |
|
26 |
fmt.Println(groupedByAge) |
27 |
} |
28 |
|
29 |
|
30 |
Output: |
31 |
|
32 |
map[34:[{Jim 34}] 23:[{Jane 23} {Kyle 23}]]
|
5. Gorm
Go es conocido por su carácter espartano. Programación de base de datos no es diferente. Las bibliotecas más populares de DB para ir son bastante bajo nivel. Gorm trae el mundo de Mapeo objeto-relacional para Go con las siguientes características:
- Asociaciones (tiene uno, tiene muchos, pertenece, muchos a muchos, polimorfismo)
- Devoluciones de llamada (antes y después de crear/guardar/actualizar/borrar/buscar)
- Precarga (ansioso por carga)
- Transacciones
- Clave Primaria Compuesta
- Constructor SQL
- Migraciones Automatica
- Registrador
- Extensible, escribir Plugins basado en callbacks GORM
Pero no cubre todo. Si vienes desde Python, no esperes magia SQLAlchemy. Para más cosas de lujo, usted tendrá que ir un nivel más bajo. Aquí es un ejemplo de cómo usar Gorm con sqlite. Tenga en cuenta el gorm.Model incrustada en la estructura del producto.
1 |
package main |
2 |
|
3 |
import ( |
4 |
"github.com/jinzhu/gorm" |
5 |
_ "github.com/jinzhu/gorm/dialects/sqlite" |
6 |
) |
7 |
|
8 |
type Product struct {
|
9 |
gorm.Model |
10 |
Code string |
11 |
Price uint |
12 |
} |
13 |
|
14 |
func main() {
|
15 |
db, err := gorm.Open("sqlite3", "test.db")
|
16 |
if err != nil {
|
17 |
panic("failed to connect database")
|
18 |
} |
19 |
defer db.Close() |
20 |
|
21 |
// Migrate the schema |
22 |
db.AutoMigrate(&Product{})
|
23 |
|
24 |
// Create |
25 |
db.Create(&Product{Code: "L1212", Price: 1000})
|
26 |
|
27 |
// Read |
28 |
var product Product |
29 |
db.First(&product, 1) // find product with id 1 |
30 |
db.First(&product, "code = ?", "L1212") |
31 |
|
32 |
// Update - update product's price to 2000 |
33 |
db.Model(&product).Update("Price", 2000)
|
34 |
|
35 |
// Delete - delete product |
36 |
db.Delete(&product) |
6. Goose
Una de las tareas más importantes cuando se trabaja con bases de datos relacionales es administrar el esquema. Modificando el esquema de DB se considera un cambio de "miedo" en algunas organizaciones. El paquete de Goose le permite realizar cambios de esquema y migraciones de datos incluso si es necesario. Puede goose up y goose down para ir hacia adelante y hacia atrás. Mente sus datos y asegúrese de que no Haz perdido o dañado.
Ganso obras de control de versiones el esquema y utilizando archivos de migración correspondientes a cada esquema. Los archivos de migración pueden ser comandos SQL o comandos Go. Este es un ejemplo de un archivo de migración de SQL que agrega una nueva tabla:
1 |
-- +goose Up |
2 |
CREATE TABLE person ( |
3 |
id int NOT NULL, |
4 |
name text, |
5 |
age int, |
6 |
PRIMARY KEY(id) |
7 |
); |
8 |
|
9 |
-- +goose Down |
10 |
DROP TABLE person; |
El -- +goose up y -- +goose down comentarios dicen goose qué hacer para mejorar o degradar el esquema.
7. Glide
Glide es un gestor de paquetes para ir. Bajo una sola GOPATH, pueden tener muchos programas que tienen dependencias contradictorias. La solución es que cada programa de administrar su propio directorio de proveedores de las dependencias del paquete. Glide ayuda con esta tarea.
Aquí están las características de Glide:
- Soporte de paquetes de control de versiones incluyendo soporte semántico versión 2.0.0.
- Soporte paquetes de aliasing (por ejemplo, para trabajar con horquillas de github).
- Eliminar la necesidad de que las declaraciones de importación de descripciones.
- Trabajar con todas las herramientas de Go.
- Soporte todas las herramientas de VCS que Go apoya (git, bzr, hectogramo, svn).
- Soporte custom plugins locales y globales.
- Repositorio de almacenamiento en caché y caché de datos para mejorar el rendimiento.
- Aplane las dependencias, las diferencias de versión y evitando la inclusión de un paquete varias veces.
- Gestionar e instalar dependencias bajo demanda o vendored en su sistema de control de versión.
Las dependencias se almacenan en glide.yaml, y planeo proporciona varios comandos para manejar las dependencias:
1 |
create, init Initialize a new project, creating a |
2 |
glide.yaml file |
3 |
config-wizard, cw Wizard that makes optional suggestions |
4 |
to improve config in a glide.yaml file. |
5 |
get Install one or more packages into |
6 |
`vendor/` and add dependency to |
7 |
glide.yaml. |
8 |
remove, rm Remove a package from the glide.yaml |
9 |
file, and regenerate the lock file. |
10 |
import Import files from other dependency |
11 |
management systems. |
12 |
name Print the name of this project. |
13 |
novendor, nv List all non-vendor paths in a |
14 |
directory. |
15 |
rebuild Rebuild ('go build') the dependencies
|
16 |
install, i Install a project's dependencies |
17 |
update, up Update a project's dependencies |
18 |
tree (Deprecated) Tree prints the |
19 |
dependencies of this project as a tree. |
20 |
list List prints all dependencies that the |
21 |
present code references. |
22 |
info Info prints information about this |
23 |
project |
24 |
cache-clear, cc Clears the Glide cache. |
25 |
about Learn about Glide |
26 |
mirror Manage mirrors |
27 |
help, h Shows a list of commands or help for |
28 |
one command |
8. Ginkgo
Ginkgo es un framework de pruebas de BDD (Behavior Driven Development). Le permite escribir las pruebas en una sintaxis que se asemeja a Inglés y permitir a la gente menos técnica examinar las pruebas (y su producción) y verificar que coinciden con los requerimientos del negocio.
Algunos desarrolladores como este estilo de la especificación de prueba demasiado. Se integra con el paquete de prueba incorporado de ir y se combina a menudo con Gomega. Este es un ejemplo de un Ginkgo + Gomega prueba:
1 |
actual, err := foo() |
2 |
Ω(err).Should(BeNil()) |
3 |
Ω(actual).ShouldNot(BeNil()) |
4 |
Ω(actual.result).Should(Equal(100)) |
9. Etcd
Etcd es una tienda confiable de clave y valor distribuida. El servidor se implementa en Go, y aunque cliente vaya interactúa con él gRPC.
Se centra en lo siguiente:
- Simple: bien definida, orientada al usuario API (gRPC).
- Seguro: automático TLS con autenticación de cliente cert opcional.
- Rápido: entre 10.000 escrituras por segundo.
- Confiable: correctamente distribuida utilizando balsa.
Aquí es un ejemplo de conexión con el servidor, colocando un valor y conseguirla, incluyendo tiempos de espera y limpieza.
1 |
func test_get() {
|
2 |
cli, err := clientv3.New(clientv3.Config{
|
3 |
Endpoints: endpoints, |
4 |
DialTimeout: dialTimeout, |
5 |
}) |
6 |
if err != nil {
|
7 |
log.Fatal(err) |
8 |
} |
9 |
defer cli.Close() |
10 |
|
11 |
_, err = cli.Put(context.TODO(), "foo", "bar") |
12 |
if err != nil {
|
13 |
log.Fatal(err) |
14 |
} |
15 |
|
16 |
ctx, cancel := context.WithTimeout(context.Background(), |
17 |
requestTimeout) |
18 |
resp, err := cli.Get(ctx, "foo") |
19 |
cancel() |
20 |
if err != nil {
|
21 |
log.Fatal(err) |
22 |
} |
23 |
for _, ev := range resp.Kvs {
|
24 |
fmt.Printf("%s : %s\n", ev.Key, ev.Value)
|
25 |
} |
26 |
// Output: foo : bar |
27 |
} |
10. NSQ
NSQ es una gran cola distribuida. Lo he utilizado con éxito como un bloque principal de construcción para sistemas distribuidos a gran escala. Estas son algunas de sus características:
- La ayuda distribuidas topologías con ningún SPOF.
- Horizontal escalable (no brokers, perfectamente añadir más nodos al clúster).
- Baja latencia empuje basado en entrega de mensajes (rendimiento).
- Combinación de equilibrio de carga y enrutamiento de mensajes de multidifusión de estilo.
- Excel en streaming (alto rendimiento) y trabajo orientado a las cargas de trabajo (bajo rendimiento).
- Sobre todo en la memoria (más allá de una agua marca alta mensajes transparente se guardan en el disco).
- Servicio de detección de tiempo de ejecución para los consumidores encontrar productores (nsqlookupd).
- Seguridad de capa de transporte (TLS).
- Formato de datos independiente.
- Algunas dependencias (fáciles de implementar) y sane, delimitado, configuración por defecto.
- Protocolo TCP simple apoyo a bibliotecas de cliente en cualquier idioma.
- Interfaz HTTP para estadísticas, acciones de la administración y los productores (biblioteca de cliente no es necesario para publicar).
- Se integra con statsd para instrumentación en tiempo real.
- Interfaz de administración de clúster robusto (nsqadmin).
Aquí es cómo publicar un mensaje en NSQ (manejo de errores se omite):
1 |
package main |
2 |
|
3 |
import ( |
4 |
"github.com/bitly/go-nsq" |
5 |
) |
6 |
|
7 |
func main() {
|
8 |
config := nsq.NewConfig() |
9 |
p, _ := nsq.NewProducer("127.0.0.1:4150", config)
|
10 |
|
11 |
p.Publish("topic", []byte("message"))
|
12 |
p.Stop() |
13 |
} |
Y aquí está cómo consumir:
1 |
package main |
2 |
|
3 |
import ( |
4 |
"sync" |
5 |
"fmt" |
6 |
"github.com/bitly/go-nsq" |
7 |
) |
8 |
|
9 |
func main() {
|
10 |
wg := &sync.WaitGroup{}
|
11 |
wg.Add(1) |
12 |
|
13 |
config := nsq.NewConfig() |
14 |
q, _ := nsq.NewConsumer("topic", "channel", config)
|
15 |
handler := nsq.HandlerFunc(func(message *nsq.Message) error {
|
16 |
fmt.Printf("Got a message: %v", message)
|
17 |
wg.Done() |
18 |
return nil |
19 |
}) |
20 |
q.AddHandler(handler) |
21 |
q.ConnectToNSQD("127.0.0.1:4150")
|
22 |
wg.Wait() |
23 |
} |
11. Docker
Docker es un nombre familiar ahora (si los miembros de su familia son en su mayoría gente de DevOps). No es consciente que el Docker es implementado en Go. Por lo general no utiliza Docker en el código, pero es un proyecto importante y merece ser reconocida como un proyecto de Go enormemente exitoso y popular.
12. Kubernetes
Kubernetes es una plataforma de orquestación de contenedor de código abierto para aplicaciones nativas de nube. Es otro sistema de monstruo distribuido en Go. Recientemente escribí un libro llamado Dominando Kubernetes donde ir en detalle sobre los aspectos más avanzados de Kubernetes. Desde el punto de vista del desarrollador vaya Kubernetes es muy flexible, y puede extender y personalizar mediante plugins.
Conclusión
Go es una gran lengua. Su filosofía de diseño es un lenguaje simple y accesible. Su biblioteca estándar no es tan completo como otros lenguajes como Python.
Se acercó la comunidad Go, y hay muchas bibliotecas de alta calidad que se pueden utilizar en sus programas. En este artículo, introduje las 12 bibliotecas. Le animo a buscar otras bibliotecas antes de saltar e implementar todo desde cero.



