Showing posts with label golang. Show all posts
Showing posts with label golang. Show all posts

2016/11/12

GDG Berlin Golang "Movember Gophers" に行ってきた

昨日ドイツのベルリンについたばかりで、少し時差ボケってたんですが、なんとなくGDG Berlin Golang "Movember Gophers"に参加できました。

ちなみに「Movember」というのが「Moustache」と「November」の組み合わせなというわけで、イベントページのゴーファー君も立派な口ひげしてますね。

僕、カナダ人ですが、実はプログラミングや開発に興味を持ち始めたのが日本にきてからなので、こんな感じに日本の外で勉強会に参加するのって初めてでした。世界中の勉強会で何が普通なのか全くわからないんですが、とりあえずピザとビールが決まりみたいです。

ただ昨日は折り畳めて食べる巨大なピザでした・・・

あと、日本ではいつもトークを聞いてから、懇親会を行うんですが、このイベントではピザとビールが最初から出してあって、みんなが集めるの待ってるうちに飲む感じでした。トークとトークの間にみんながビールを取りに冷蔵庫にダッシュしたところ面白かったですww

さて、ピザとビールの件をほといて、トークの内容の話をしましょう。


最初の発表者が@matryer というイギリスの方でした。GoでTDDをする話をしてくれました (スライドはこちらです)。

TTDを行うときに便利なTIPを色々紹介してくれました。例えば:

  • Silk というマークダウンで書かれたドキュメントからHTTPのテストを実行できるパッケージ
  • go test -cover コマンドでテストのカバレージを確認する方法
  • 特別な理由がなければ、テストヘルパーを使わないで標準testパッケージをそのまま使おう (Go作者の意見)
  • 外部dependencyを避けるため、実際のオブジェクトじゃなくてモックしたオブジェクトを利用する (つまりinterfaceでtypeを柔軟にする)
  • interfaceを元にモックのstructを自動生成ツールの紹介
  • あるパッケージを外部からテストしたいとき、テスト専用のパッケージを作ってもいい(テストの場合同じディレクトリに複数パッケージをおいても大丈夫)


2番目の発表がに@konradreicheによるConsumer Driven Contract Testing in Goでした。

マイクロサービスのインテグレーションテストで出てくる問題を解決しようとしているPactの紹介でした。(概要から日本語で説明する自信ないので、クックパッドの記事を参考にするといいでしょう)

Pact for Goが実際にTape.tvでどういうふうに使われているかも説明してくれました。Box Officeというチケット購入システム(Ruby)とBouncerという認証用API(Go)の違うチームによって管理されているマイクロサービスがあるそうですが、共通のAPIをPactで定義することで管理のところを一部自動化できてて安心らしいです。

ただConsumer Driven Contractを使えるまでのプロジェクトのセットアップやチームが新しい仕組みになれるまでの時間の面で少し大変らしいです。


最後に@fortytw2がwatneyというRubyのvcrの移植の紹介をしました。HTTPリクエストをキャプチャーし、次回に実行した際にHTTPリスポンスを再利用することで、ネットワーク障害の影響でこける確率を低くしたり、テストを早くしたりするとても便利そうなパッケージです。

2016/11/02

Minna no Go Gengo: A Summary / Review in English (chapter 3)

Here's a continuation of my summary of the Japanese Go programming book: Minna no Go Gengo. This is chapter 3.

For anyone who has missed my other summaries, here are chapter 1 and chapter 2.

How to Make practical applications

Author: Fujiwara Shunichiro (aka @fujiwara)

3.1 Opening

First of all what does the author mean by "practical applications"?
A practical application...

  • makes it easy to look up what kind of operations it performs
  • has good performance
  • can support different inputs and outputs
  • is easy for humans to use
  • is easy to maintain

The two github repos below are referenced frequently throughout the chapter as real-world practical applications written. Both are applications created by the author.

3.2 Version Control

Many Go programs can be shipped as a single binary, so in comparison to interpreted languages, the deployment process is generally much simpler. However since we're dealing with binaries it's a good idea to make it easy to programmatically obtain the version number of the binary so users can check if they have the latest version. Using the flag package to capture whether the program was invoked with -v or --version flags is common, but instead of hardcoding the version into the source code, the author recommends making use of git tags to store the version number and then passing it to the code using the build argument ldflags. A Makefile could for example do something like this:


#!/bin/sh

GIT_VER=`git describe --tags`
go build -ldflags "-X main.version=${GIT_VER}"


The Makefile for fluent-agent-hydra seems to make use of this very technique.

3.3 Efficient Use of I/O

This section demonstrates why and how bufio should be used when dealing with I/O operations.

The first point the author makes is how useful bufio.Reader.Peek can be when you run into a situation where you want to validate data coming in from STDIN, but don't want to read everything in the buffer quite just yet. An example of this kind of scenario is in the application stretcher which expects to receive a valid JSON string via STDIN. Although it's possible to read the entirety of the input into memory and then check whether it is valid JSON or not, it's more efficient to pass the input in io.Reader directly to encoding/json.Decoder. This is where bufio.Reader.Peek comes in. A call to Peak() can be used to check if the first character looks like the beginning of a JSON array ("[") , and if not we can simply return an error without bothering to read the rest of STDIN.

Another important point the author brings up is the difference between buffering in Go as opposed to in interpreted languages such as Ruby, Perl and Python. Interpreted languages generally handle the buffering of text output automatically at run time when their enclosing program is handed to a pipe, thereby reducing the number of costly system calls. Go, on the other hand, doesn't automatically buffer anything.

For example, try inspecting the following program using strace -e trace=write ./filename | cat


package main

import (
  "fmt"
  "os"
  "strings"
)

func main() {
  for i := 0; i < 100; i++ {
    fmt.Fprintln(os.Stdout, strings.Repeat("x", 100))
  }
}


Checking the output of strace on the above program reveals that a total of 100 system calls are recorded, indicating that no buffering has taken place. The bufio package can help us improve this example.


package main

import (
  "bufio"
  "fmt"
  "os"
  "strings"
)

func main() {
  b := bufio.NewWriter(os.Stdout)
  for i := 0; i < 100; i++ {
    fmt.Fprintln(b, strings.Repeat("x", 100))
  }
  b.Flush()
}


By wrapping os.Stdout with a *bufio.Writer we can delay the system calls until Flush() is called. The default buffer size is 4096 bytes, but it can be increased as necessary. Inspecting our new and improved program in strace will show that the number of system calls has been reduced to 2 whether we pass our program to a pipe or not.

3.4 Handling random numbers

This section mostly just explains the difference between math/rand (pseudo random number generator) and crypto/rand (cryptographically secure pseudo random number generator) and shows how they can be used. I think this topic is pretty well covered in English.

3.5 Human readable numbers

The package recommended for converting file sizes and time stamps to human readable format is: go-humanize. Again the documentation for this package is in English, so probably I don't need to summarize. Just if you need to convert numbers to a more readable format, use this package rather than wasting time trying to do it yourself.

3.6 Executing external commands through Go

Generally speaking executing other programs through Go incurs a penalty in terms of starting up other processes in the background and sending data to external commands, so performance-wise, it's often preferable to implement a lot of things in pure Go. However there are of course instances where it is better to delegate the work to an existing program. This section mostly just models how to use the os/exec package to call external programs. One thing I didn't know is that if you call sh through os/exec you can use redirects and other shell sigils (>, ||, &&, etc) as normal.


exec.Command("sh", "-c", "some_command || handle_error").Output()


3.7 Timing out

While a lot of existing packages like net/http handle timeouts for you, sometimes you might want to implement a timeout yourself. This section demonstrates how you can use the time package and channels to implement a timeout yourself.


// A 10 second timer
timer := time.NewTimer(10 * time.Second)
// a channel to receive the result
done := make(chan error)

go func() {
  // call the function you want to run asynchronously in a goroutine
  done <- doSomething() // a function that returns an error
}

// use select to wait for a response from multiple channels
select {
case <-timer.C:
  return fmt.Errorf("timeout reached")
case err <-done:
  if err != nil {
    return err
  }
}


3.8 Working with signals

Go's default handling of signals is documented in os/signal. This section demonstrates how you might change the default behaviour in your own programs. A few examples of why you might want to do this is for example you have a server application and want to finish processing all incoming requests before closing or you want to make sure your program finishes writing everything currently in the buffer and properly closes open files before exiting itself. The example in the book is relatively close to the example from the os/signal docs for Notify(), so a read through that will give you the gist.

3.9 Stopping goroutines

It's easy to start a goroutine, but stopping one goroutine from inside another can be a bit tricky. There are two main ways to do this: using channels, or using the context package provided by go 1.7 and later.

The example code on page 80 shows how to use channels to stop a goroutine. The code demonstrates a program that implements concurrent workers which can process data from a queue.


package main

import (
  "fmt"
  "sync"
)

var wg sync.WaitGroup

func main() {
  queue := make(chan string)
  for i := 0; i < 2; i++ { //make two workers (goroutines)
    wg.Add(1)
    go fetchURL(queue)
  }

  queue <- "http://www.example.com"
  queue <- "http://www.example.net"
  queue <- "http://www.example.net/foo"
  queue <- "http://www.example.net/bar"

  close(queue) // tell the goroutines to terminate
  wg.Wait()    // wait for all goroutines to terminate
}

func fetchURL(queue chan string) {
  for {
    url, more := <-queue // more will be false when this closes
    if more {
      // process the url
      fmt.Println("fetching", url)
      // ...
    } else {
      fmt.Println("worker exit")
      wg.Done()
      return
    }
  }
}


When you call close() on a channel from the sending side, the second variable passed to the receiving side (the variable more evaluates to false. The goroutine is then able to close itself (by calling return) when there is no more data to receive.

The context package can be used to achieve much the same thing. The advantage that context brings to the table is a function called context.WithTimeout() which lets you handle timing out and cancellation in one fell swoop. Go Concurrency Patterns: Context from the official golang blog covers its usage extensively.

That wraps up the topics introduced in this chapter. A lot of the content was new to me, so hope to make use of some of the techniques in the future.

2016/10/05

Minna no Go Gengo: A Summary / Review in English (chapter 2)

It took me way longer than I expected to sit down and write this, but now that I have a bit of downtime before my next flight, I'd like to continue my summary of Minna no Go Gengo.

How to build multi-platform tools for your workplace
Author: @mattn

This chapter encourages readers to build multi-platform tools (Windows, Mac, Linux, etc) to support different devices coworkers use and gives some guidelines on how this can be done effectively in Go. Here is a bit of a break down of what each of the sections are and what kind of info they cover:

2.1 Why build internal tools in Go

Go makes it possible to statically build a runnable module for various OSes, so there is no need to ask users to install the Go runtime on their machines. Thanks to this, there is no worry that a different runtime implementation on a different OS will behave differently. Distributing a single binary file is all that is needed to let others use a Go program. Both of these things make Go a really good choice for internal tooling.

2.2 Implicit rules to follow

Rule one is use path/filepath to interact with the filesystem and not the path package. These two packages might be confusing to new users of Go: while path/filepath is pretty explanatory, path is a package meant for resolving relative paths in a http or ftp context. Because the path package does not recognize "\" as a path separator even on Windows, accessing a url like http://localhost:8080/data/..\main.go on a web server that makes use of the path package to locate static files could be used to expose the raw contents of other files on the filesystem

Rule 2 is to use defer to clean up resources. This is pretty well documented elsewhere, so I don't think I really need to elaborate.

The next recommendation is of particular concert to anyone who deals with Japanese or languages containing multibyte characters. Anyone interacting with programs that make use of the ANSI API in Windows to produce output will have to make use of an appropriate encoding package like golang.org/x/text/encoding/japanese to convert the input from ShiftJIS to UTF-8.

2.3 Using TUI on Windows

Linux based Text-based User Interfaces use a lot of escape sequences, many of which don't display properly in Windows. In Go you can use a library called termbox to make the process of making multi-platform TUI applications easier. Another recommended program is one of the author's own tools: go-colorable which can be used which can help produce coloured text in log output, etc.

2.4 Handling OS Specific Processes

Use runtime.GOOS to determine the OS from within a program.

This section also covers build constraints, but this topic is already well covered in English in the documentation, so I won't go into detail here.

2.5 Rely on existing tools instead of trying too hard

While it is technically possible to daemonize processes in Go by using the syscall package to call fork(2), the multithreaded nature of Go makes this a bit tricky. So it is generally recommended to use external tools to handle the daemonizing of a Go program. For Linux for example check out daemonize, supervisord and upstart and for Windows check out nssm

For Unix a regular user can't listen on port 80 or 433 so a lot of unix servers are configured to start as root and use setuid(2) to demote the permissions. However it's not recommended that you use setuid(2) in Go because it only affects the current thread. Instead use nginx or another server to reverse proxy requests from 80 or 433 to another port that Go can listen on.

2.6 Go likes its single binaries

Go makes deployment as easy as placing a single binary file on a server, but in the case of larger programs like web applications (for example) sometimes templates, pictures and other files are necessary. Try using go-bindata to pack static files as assets in a binary so that you don't have to sacrifice ease of deployment.

2.7 Making Windows applications

This section covers how to toggle whether or not your Go program displays a command prompt or not using the -ldflags="-H windowsgui" with go build and also how to link resource files (like the application's icon) using IDI_MYAPP ICON "myapp.ico"

And here are some recommended packages for building multi-platform compatible GUIs:

2.8 Configuration files

The first part of this section covers different file formats like INI, JSON, YAML, TOML and covers their strengths and weaknesses.

Aside from file format, file location on each platform can also be a source of confusion when configuring applications. On UNIX systems the standard was to place each file in the home directory like $HOME/.myapp originally, but more recently the XDG Base Directory Specification recommends that config files be placed under $HOME/.config/.

Similarly on Windows it's no problem if you use %USERPROFILE%\.config\, but the author mentioned he often places config files under %APPDATA%\my-app\.


Well that's the gist of it. I haven't really built software for Windows before mostly just because it seemed like too much trouble, but this chapter sure made it look like Go is making that whole process much easier for those of us who are used to developing for Linux.

For anyone who missed my (much briefer) summary of chapter 1, you can find it here.

2016/09/13

Minna no Go Gengo: A Summary / Review in English (chapter 1)

My copy of Minna no Go Gengo, the Golang book with the cover everyone loves, came in the mail today!

Just last week, I was talking to some gophers based in Germany and when I mentioned that a coworker of mine recently published a chapter in a book on Go, one of the guys immediately asked "Is it the one with the gophers and robot on the cover?". Since the book only exists in Japanese I was surprised that he knew about it, but I guess I shouldn't be too suprised. The cover is just too good not to share, am I right?

So I thought i'd write a quick review / summary of each chapter in case there are some gophers out there who are interested in knowing what's in the book. I've just barely begun reading, but as the title, Minna no Go Gengo (Everyone's Golang), suggests, it covers a number of topics for a range of different skill levels from how to get started for absolute beginners to more advanced topics like reflection. Each chapter is written by a different author, all of whom are well-known OSS contributors here in Japan.

The first chapter is the most beginner friendly, but also contains some stellar tips about how to write Go code in a Go-like way.

How to start writing Go code for team development.

Author: Matsuki Masayuki (aka @Songmu)

This chapter starts out with the essentials: how to install Go, an introduction to some of the core command-line tools used in Go development as well as suggestions for some useful third party tools like ghq, peco and glide). It's super concise and does a great job of covering the essentials without being too verbose.

For anyone who's written Go code before, the meat of the chapter, though is in the style guide which highlights some differences between writing programs using scripting languages like Ruby and Perl vs writing in Go. For example:

  • Avoid using regexp: use the strings package wherever possible instead. Why? They can be really slow, sometimes even slower than Perl regexp... which is pretty bad for a pre-compiled program.
  • Avoid maps. Because Go is a strongly typed language it is better to use structs. Also maps are not thread-safe. If you need to use a map alongside concurrency embed one in a struct alongside a sync.RWMutex.
  • Don't overuse concurrency. While Go is great for concurrency overusing it not only makes programs harder to read, but also increases the likelihood of race conditions.
  • Use the -ldflags and -tag options to embed useful information in a binary when using go build.
  • runtime.NumGoRoutine and runtime.ReadMemStats are useful monitoring metrics for web servers and other long running programs. golang-stats-api-handler is a useful library that provides an api interface to the go runtime package.

Hardly an exhaustive list, as this chapter is packed with useful info for people who are transitioning to Go from other languages and gives a good introduction to how to get into a Go mindset. I am looking forward to reading and writing up on the remaining chapters.