Monday, August 7, 2017

12 Indispensable Go Packages and Libraries

12 Indispensable Go Packages and Libraries

Go is an amazing language with a lot of momentum, and it's focused on simplicity. This approach is evident in its standard library, which provides all the essentials, but not much more. 

Fortunately, Go has a vibrant community that creates and shares a lot of third-party libraries. In this tutorial, I'll introduce you to 12 of Go's best packages and libraries. Some of them have relatively narrow scope and can be added to any projects, while others are huge projects that you can incorporate into massive, large-scale distributed systems.

Awesome Go

Before diving into the libraries themselves, let me introduce you to Awesome Go, a very active and curated list of Go libraries and other resources. You should visit every now and then and check what's new.

1. Golang-Set

Go has arrays, slices and maps, but it doesn't have a set data structure. You can mimic a set with a map of bools, but it's nice to have an actual data type with the right operations and semantics. This is where golang-set comes in. Here is a basic example of creating a new set, adding items and testing for membership:

Note that the package name is "mapset". In addition to the basics, you perform all set operations like union, intersection, and difference. You can also iterate over the set values: 

2. Color

Let's continue with the color theme. When writing command-line programs, it is useful to use colors to highlight important messages or distinguish between errors, successes, and warnings. 

The color package gives an easy way to add some color to your programs (see what I did there?). It uses ANSII escape codes and supports Windows too! Here is a quick example:

The color package supports mixing colors with background colors, styles like bold or italic, and sprinkling color with non-color output.

The color package has other useful features. Go ahead and explore more.

3. Now

Now is a very simple package that provides a convenience wrapper for the standard time package and makes it easy to work with various date and time constructs around the current time. 

For example, you can get the beginning of the current minute or the end of the Sunday closest to the current time. Here is how to use "now":

You can also parse times and even add your own formats (which will require updating the known formats). The Now type embeds time.Time, so you can use all of the time.Time methods directly on Now objects.

4. Gen

The gen tool generates code for you—in particular, type-aware code that tries to alleviate the gap of not having templates or generics in Go.

You annotate your types with a special comment, and gen generates source files that you include in your project. No runtime magic. Let's see an example. Here is an annotated type.

Running gen (make sure it's in your path) generates person_slice.go:

The code provides LINQ-like methods to operate on the PersonSlice type. It's simple to understand and nicely documented. 

Here is how you use it. In the main function, a PersonSlice is defined. The age() function selects the age field from its Person argument. The generated GroupByInt() function takes the age() function and returns the people from the slice grouped by their age (34 is just Jim, but 23 has both Jane and Kyle).

5. Gorm

Go is known for its spartan nature. Database programming is no different. Most popular DB libraries for Go are pretty low-level. Gorm brings the world of object-relational mapping to Go with the following features:

  • Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
  • Callbacks (Before/After Create/Save/Update/Delete/Find)
  • Preloading (eager loading)
  • Transactions
  • Composite Primary Key
  • SQL Builder
  • Auto Migrations
  • Logger
  • Extendable, write Plugins based on GORM callbacks

But it doesn't cover everything. If you come from Python, don't expect SQLAlchemy magic. For more fancy stuff, you'll have to go a lower level. Here is an example of how to use Gorm with sqlite. Note the embedded gorm.Model in the Product struct.

6. Goose

One of the most important tasks when working with relational databases is managing the schema. Modifying the DB schema is considered a "scary" change in some organizations. The goose package lets you perform schema changes and even data migrations if needed. You can goose up and goose down to go back and forth. Mind your data, though, and make sure it doesn't get lost or corrupted.

Goose works by versioning your schema and using migration files corresponding to each schema. The migration files can be SQL commands or Go commands. Here is an example of a SQL migration file that adds a new table:

The -- +goose up and -- +goose down comments tell goose what to do to upgrade or downgrade the schema.

7. Glide

Glide is a package manager for Go. Under a single GOPATH, you may have many programs that have conflicting dependencies. The solution is to have each program manage its own vendor directory of package dependencies. Glide helps with this task.

Here are the features of glide:

  • Support versioning packages including Semantic Versioning 2.0.0 support.
  • Support aliasing packages (e.g. for working with github forks).
  • Remove the need for munging import statements.
  • Work with all of the go tools.
  • Support all the VCS tools that Go supports (git, bzr, hg, svn).
  • Support custom local and global plugins.
  • Repository caching and data caching for improved performance.
  • Flatten dependencies, resolving version differences and avoiding the inclusion of a package multiple times.
  • Manage and install dependencies on-demand or vendored in your version control system. 

The dependencies are stored in glide.yaml, and glide provides several commands to manage dependencies:

8. Ginkgo

Ginkgo is a BDD (Behavior Driven Development) testing framework. It lets you write your tests in a syntax that resembles English and allow less technical people to review tests (and their output) and verify that they match the business requirements. 

Some developers like this style of test specification too. It integrates with Go's built-in testing package and is often combined with Gomega. Here is an example of a Ginkgo + Gomega test:

9. Etcd

Etcd is a reliable distributed Key-Value store. The server is implemented in Go, and the Go client interacts with it though gRPC.

It focuses on the following:

  • Simple: well-defined, user-facing API (gRPC).
  • Secure: automatic TLS with optional client cert authentication.
  • Fast: benchmarked 10,000 writes/sec.
  • Reliable: properly distributed using Raft.

Here is an example of connecting to the server, putting a value and getting it, including timeouts and cleanup.

10. NSQ

NSQ is a great distributed queue. I've used it successfully as a primary building block for large-scale distributed systems. Here are some of its features:

  • Support distributed topologies with no SPOF.
  • Horizontally scalable (no brokers, seamlessly add more nodes to the cluster).
  • Low-latency push based message delivery (performance).
  • Combination load-balanced and multicast style message routing.
  • Excel at both streaming (high-throughput) and job oriented (low-throughput) workloads.
  • Primarily in-memory (beyond a high-water mark messages are transparently kept on disk).
  • Runtime discovery service for consumers to find producers (nsqlookupd).
  • Transport layer security (TLS).
  • Data format agnostic.
  • Few dependencies (easy to deploy) and a sane, bounded, default configuration.
  • Simple TCP protocol supporting client libraries in any language.
  • HTTP interface for stats, admin actions, and producers (no client library needed to publish).
  • Integrates with statsd for real-time instrumentation.
  • Robust cluster administration interface (nsqadmin).

Here is how to publish a message to NSQ (error handling is elided):

And here is how to consume:

11. Docker

Docker is a household name now (if your family members are mostly DevOps people). You may not be aware that Docker is implemented in Go. You don't  typically use Docker in your code, but it is a significant project and deserves to be recognized as a hugely successful and popular Go project.

12. Kubernetes

Kubernetes is an open-source container orchestration platform for cloud-native applications. It is another monster distributed system implemented in Go. I recently wrote a book called Mastering Kubernetes where I go in detail over the most advanced aspects of Kubernetes. From the Go developer's point of view, Kubernetes is very flexible, and you can extend and customize it via plugins.

Conclusion

Go is a great language. Its design philosophy is to be a simple and approachable language. Its standard library is not as comprehensive as some other languages like Python. 

The Go community stepped up, and there are many high-quality libraries you can use in your programs. In this article, I introduced 12 libraries. I encourage you to look for other libraries before jumping in and implementing everything from scratch.


No comments:

Post a Comment