Goでリリースビルド時にコンパイルから外れるassertionパッケージつくったよー

## はじめに
- `assert` 無いの不便
- `panic` でもいいけどリリースビルドには含めたくない
- `go build` 時に `-tags=release` するとコンパイルから省かれる `assertion` パッケージつくった

## つくったもの
- [ryskiwt/assert-go](https://github.com/ryskiwt/assert-go)

## 追記
よくよく考えたら `if` の中で `panic` するのと同じかー。Equalsとかはむしろ関数呼び出し分遅くなる。

結論 : ビルド時に行単位で消し去る方法ほしい

## さらに追記
- パフォーマンス重視の場合のために、定数 `assert.ENABLED` を追加。`const`なのでインライン化されて消える。

```go
if assert.ENABLED && v != 1 {
    panic(assert.NewMsg(v, 1))
}
```

- 入力引数評価のせいで遅くなるのを回避するために関数で渡すように変更し、 `1 ns/op` まで高速化

```go
assert.Equals(func() (assert.G, assert.W) { return v, 1 })
assert.WithMsg(func() (bool, string) { return v == 1, assert.NewMsg(v, 1) })
```


## つかいかた
これだけ。アサーションエラーすると問答無用で `panic` します。

```go
import "github.com/ryskiwt/assert-go"

v := 1

// CASE 1 (about 0.33 ns/op)
if assert.ENABLED && v == 0 {
	panic(assert.DefaultMsg)
}
// -> panic: assrtion error


// CASE 2 (about 0.33 ns/op)
assert.Do(v == 0)
// -> panic: assrtion error


// CASE 3 (about 1.00 ns/op)
assert.Equals(func() (assert.G, assert.W) { return v, 0 })
// -> panic: assrtion error: got=1, want=0


// CASE 4 (about 1.00 ns/op)
assert.WithMsg(func() (bool, string) {
	return v == 0, assert.NewMsg(v, 0)
})
// -> panic: assertion error: got=1, want=0
```

## ビルド時のはぶきかた

### Build for Debug
普通にビルドするとアサーションは省かれる

```sh
$ go build
```

### Build for Release
`-tags=assert` つけてビルドするとアサーションが有効になる

```sh
$ go build -tags=assert
```

## ベンチマーク
- [assert-go/benchmark_test.go](https://github.com/ryskiwt/assert-go/blob/master/benchmark_test.go)

### 結果
```
$ go test -run NONE -bench . -benchmem                                                                                                                    +[develop]
testing: warning: no tests to run
BenchmarkNone-4            	2000000000	         0.31 ns/op	       0 B/op	       0 allocs/op // no assertion
BenchmarkFlag_True-4       	2000000000	         0.33 ns/op	       0 B/op	       0 allocs/op // fastest
BenchmarkDo_True-4         	2000000000	         0.31 ns/op	       0 B/op	       0 allocs/op // fastest
BenchmarkEquals_True-4     	2000000000	         1.01 ns/op	       0 B/op	       0 allocs/op // 3 times slower
BenchmarkWithMsg_True-4    	2000000000	         0.96 ns/op	       0 B/op	       0 allocs/op // 3 times slower
BenchmarkDo_False-4        	2000000000	         0.32 ns/op	       0 B/op	       0 allocs/op
BenchmarkFlag_False-4      	2000000000	         0.31 ns/op	       0 B/op	       0 allocs/op
BenchmarkEquals_False-4    	2000000000	         1.11 ns/op	       0 B/op	       0 allocs/op
BenchmarkWithMsg_False-4   	2000000000	         1.03 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	github.com/ryskiwt/assert-go	12.039s
```
- boolで渡す `assert.Do` か、 `assert.ENABLED` の場合はほぼ影響なし (0.33 ns/op)
- funcで渡す `assert.Equals` と `assert.WithMsg` は3倍くらい遅い (1.00 ns/op)

```
$ go test -run NONE -bench . -benchmem -tags=assert                                                                                                       +[develop]
testing: warning: no tests to run
BenchmarkNone-4            	2000000000	         0.31 ns/op	       0 B/op	       0 allocs/op
BenchmarkFlag_True-4       	2000000000	         0.32 ns/op	       0 B/op	       0 allocs/op
BenchmarkDo_True-4         	1000000000	         1.95 ns/op	       0 B/op	       0 allocs/op
BenchmarkEquals_True-4     	30000000	        58.8 ns/op	      16 B/op	       2 allocs/op
BenchmarkWithMsg_True-4    	 5000000	       335 ns/op	      64 B/op	       4 allocs/op
BenchmarkDo_False-4        	panic: assertion error

goroutine 27 [running]:
panic(0xe5c40, 0xc420490030)
	/usr/local/Cellar/go/1.7.3/libexec/src/runtime/panic.go:500 +0x1a1
pgithub.com/ryskiwt/assert-go.Do(0x16fedc00)
	/path/to/repos/src/github.com/ryskiwt/assert-go/debug.go:9 +0x80
pgithub.com/ryskiwt/assert-go_test.BenchmarkDo_False(0xc4200ac280)
	/path/to/repos/src/github.com/ryskiwt/assert-go/benchmark_test.go:47 +0x3e
testing.(*B).runN(0xc4200ac280, 0x1)
	/usr/local/Cellar/go/1.7.3/libexec/src/testing/benchmark.go:139 +0xaa
testing.(*B).run1.func1(0xc4200ac280)
	/usr/local/Cellar/go/1.7.3/libexec/src/testing/benchmark.go:208 +0x5a
created by testing.(*B).run1
	/usr/local/Cellar/go/1.7.3/libexec/src/testing/benchmark.go:209 +0x7f
exit status 2
FAIL	github.com/ryskiwt/assert-go	7.332s
```

## おわりに
- 関数の中身を空にしとけば、インライン展開されて消えてなくなるかな〜と期待したけど甘かった（引数は評価されちゃう）
- Golangの関数呼び出し結構コスト高い
- 低レイヤあんまり分かってない素人の作なので、つっこみください
- インターフェース使いにくいとかもコメントください。改善します
- 既出だよ馬鹿野郎っていうのも、つっこみください（あるならそっち使いたい）

本日は以上です。