$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

Hatena-Textbook 2018 学習日記(4)

Hatena-Textbook 2018 学習日記(3) - $shibayu36->blog;の続き。

https://github.com/shibayu36/go-Intern-Diary/pull/2 で、ダイアリー作成とダイアリー一覧まで作った。記事作成系は出来てないけど、とりあえずここまでやれば次のGraphQLやReactあたりの学習ができるはず。

次のようなことが学習できてよかった。

  • jmoiron/sqlx の使い方
  • goのテストのやり方いろいろ
  • monkey.Patchによるメソッド置き換え

jmoiron/sqlx の使い方

最初はgodocの https://godoc.org/github.com/jmoiron/sqlx の方を読んでいたら全く分からなかったのだが、途中でgithubのREADME.mdを見れば良いことが分かってようやく使い方がわかった感じ。より詳しい使い方を知るには http://jmoiron.github.io/sqlx/https://github.com/jmoiron/sqlx/blob/master/sqlx_test.go を見ると良い。

ちなみにsqlxのコードを軽く読んでて面白いなーと思ったのは https://github.com/jmoiron/sqlx/blob/38398a30ed8516ffda617a04c822de09df8a3ec5/sqlx.go#L876..L985 あたり。reflexで代入先の変数の型を見ながら、SELECTの結果をいい感じに代入してくれる。すごい。

goのテストのやり方いろいろ

次の資料がいろいろ参考になった。


一つ分からなかったことがある。実装したドメインロジックを使ってテストデータ作成用テストユーティリティを作るときに、どこに置けばよいかが分からない。

例えばテスト用にCreateTestUserというメソッドを作るとして、このメソッドはservice.CreateNewUserという本番でも使うメソッドを使って実装したい。この時

  • testutil/testutil.goの中にCreateTestUserを置くと、service/service_test.goみたいなところでCreateTestUserを使ったときにimport cycle not allowedのエラーが出てしまう
  • service/service_test.goにCreateTestUserを置くと、service package以外から参照できない。例えばweb/web_test.goからCreateTestUserが使えない
  • service/testutil.goみたいなところに置くと、この関数をテスト以外でも使えてしまって事故りそう

ということで置き場所が分からない。testing - import cycle in golang with test packages - Stack Overflowのコメント欄でも困っている様子だが、答えが出ていない。

どうすれば良いかご意見募集。

monkey.Patchによるメソッド置き換え

bou.ke/monkey.Patchを使うと、メソッドを置き換えられるようだ。いろいろ使い道ありそう。例えば https://github.com/tkuchiki/faketime/blob/master/faketime.go ではテスト時に時刻をfakeするためmonkey.Patchを使っている。

「FACTFULNESS」を読んで、自分の会社の長期的な変化にも目を向けたいと感じた

FACTFULNESSという本が面白いという話を聞いたので読んだ。前評判どおり、非常に面白く読んで良かったなと感じた。

この本は「10の思い込みを乗り越え、データを基に世界を正しく見る習慣」を教えてくれる本であった。この本が事例として挙げているのは世界の情勢や貧困などであったが、自分が働いている会社など自分を取り巻く環境にも同じ考え方が適用できるなという印象を持った。


例えば自分の会社について、「最近全然だめで最悪だ」と思うことはないだろうか。僕は何か悪いことが続くと、このようなことが頭によぎってしまうことが多い。しかしこの本の「ネガティブ本能」という章に書かれている内容を読んで、ハッとさせられた。

● ネガティブなニュースに気づくこと。そして、ネガティブなニュースのほうが、圧倒的に耳に入りやすいと覚えておくこと。物事が良くなったとしても、そのことについて知る機会は少ない。すると世界について、実際より悪いイメージを抱くようになり、暗い気持ちになってしまう。ネガティブ本能を抑えるには、「悪いニュースのほうが広まりやすい」ことに気づくこと。
● 「悪い」と「良くなっている」は両立する。「悪い」は現在の状態、「良くなっている」は変化の方向。2つを見分けられるようにしよう。「悪い」と「良くなっている」が両立し得ることを理解しよう。
● 良い出来事はニュースになりにくい。ほとんどの良い出来事は報道されないので、ほとんどのニュースは悪いニュースになる。悪いニュースを見たときは、「同じくらい良い出来事があったとしたら、自分のもとに届くだろうか?」と考えてみよう。
● ゆっくりとした進歩はニュースになりにくい。長期的には進歩が見られても、短期的に何度か後退するようであれば、その後退のほうが人々に気づかれやすい。
● 悪いニュースが増えても、悪い出来事が増えたとは限らない。悪いニュースが増えた理由は、世界が悪くなったからではなく、監視の目がより届くようになったからかもしれない。
● 美化された過去に気をつけよう。人々は過去を美化したがり、国家は歴史を美化したがる。

FACTFULNESS(ファクトフルネス)10の思い込みを乗り越え、データを基に世界を正しく見る習慣 (Kindle Locations 1058-1067)

まさに自分はこれにハマっているなと感じた。確かに悪いニュースは耳に入りやすく、良いニュースは知る機会が少ない。さらには長期的なゆっくりした改善は気づきにくい。これによって実際よりもより悪く感じてしまっていたのだと気づいた。

このような考え方に支配されすぎないように、良いニュースには意識的に着目し、さらにたまには数年前と比べ長期的にどのような変化があったかを見返すように意識しておこうと感じた。


僕は特に「ネガティブ本能」という章が印象に残ったが、他の本能についても参考になることが多かった。興味があれば買って読んでみて欲しい。

読書ノート

* ネガティブなニュースに気づくこと。そして、ネガティブなニュースのほうが、圧倒的に耳に入りやすいと覚えておくこと。物事が良くなったとしても、そのことについて知る機会は少ない。すると世界について、実際より悪いイメージを抱くようになり、暗い気持ちになってしまう。 1057
    * 「悪い」と「良くなっている」は両立する。「悪い」は現在の状態、「良くなっている」は変化の方向。2つを見分けられるようにしよう。「悪い」と「良くなっている」が両立し得ることを理解しよう。 1057
    * 良い出来事はニュースになりにくい。ほとんどの良い出来事は報道されないので、ほとんどのニュースは悪いニュースになる。悪いニュースを見たときは、「同じくらい良い出来事があったとしたら、自分のもとに届くだろうか?」と考えてみよう。
    * ゆっくりとした進歩はニュースになりにくい。長期的には進歩が見られても、短期的に何度か後退するようであれば、その後退のほうが人々に気づかれやすい 1057
    * 悪いニュースが増えても、悪い出来事が増えたとは限らない。悪いニュースが増えた理由は、世界が悪くなったからではなく、監視の目がより届くようになったからかもしれない。
    * 美化された過去に気をつけよう。人々は過去を美化したがり、国家は歴史を美化したがる。
* じつは、貧しい子供を助けないと、人口はひたすら増え続ける 1301
* 何かの重大さを勘違いしないために最も大切なのは、ひとつの数字だけに注目しないことだ 1953
    * それと比較できるような他の数字も必ず参考にする
* どの数字が重要かを知ったりするのに使える簡単なテクニックとは、最も大きな数字を見つけること。「8割はどこにあるのだろう?」「なぜこの項目は、こんなに大きいのだろう?」「ということは何が考えられるだろう?」と問いかける 2038
* 「いますぐに決めなければならない」と感じたら、自分の焦りに気づくこと。いま決めなければならないようなことはめったにないと知ること 3744

Hatena-Textbook 2018 学習日記(3)

Hatena-Textbook 2018 学習日記(2) - $shibayu36->blog; の続きです。

今回は https://github.com/shibayu36/go-Intern-Diary/compare/01b1518eb0159b4a6d410188fd70ca1901a0e0ef...dca88a611ca9bf338f7fc901a11c1ebbe063ec56 あたりまで。ユーザー名からユーザーを探してくるメソッドや、ログイン用トークンの発行まで行った。

学んだことは

  • ランダム文字列を作る方法
  • database/sqlとgo-sql-driver/mysqlの関係

ランダム文字列を作る方法

go-Intern-Diaryでランダム文字列を作っているところは、テスト用のユーティリティとログイン用トークンの発行。

テスト用は

import "math/rand"
// テストでランダム文字列を使いたいときが多い
func randomString() string {
	return strconv.FormatInt(time.Now().Unix()^rand.Int63(), 16)
}

これはmath/randを用いて64bitのランダム整数が作られて、それを16文字(4bit)で文字列化するので、16文字の[0-9a-f]の文字列が出来るみたい。


続いてログイン用トークンの発行。

import "crypto/rand"
func generateToken() string {
	table := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@"
	l := len(table)
	ret := make([]byte, 128)
	src := make([]byte, 128)
	rand.Read(src)
	for i := 0; i < 128; i++ {
		ret[i] = table[int(src[i])%l]
	}
	return string(ret)
}

これは128文字のランダム文字列を作っている。crypt/randを使っているので暗号学的に安全なランダム文字列が作られる。tableが64文字、byteが8bitで256通りのランダムな値が作られるので、使う文字に偏りなくランダムな文字列が生成されそう。

database/sqlとgo-sql-driver/mysqlの関係

database/sqlはデータベースアクセスへのインターフェースで、go-sql-driver/mysqlは接続先のデータベース種別ごとのドライバとなっている。go-sql-driver/mysqlの説明を見ると、以下のようにimportするだけでdatabase/sqlに登録される。

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

これどうなってるのかなと思ったら、database/sqlRegisterという関数があって、これをgo-sql-driver/mysql/driver.goのinit関数で呼んで、ドライバを登録しているいるようだった。なるほど。