Posts for: #Go

go の学び直し テスト編

23時に寝て2時に起きて気分悪くて寝付けずにだらだらしながら気付いたら5時になっていた。その後いつの間にか寝て8時に起きた。

go の学び直し

Gopher塾 #1 - Testing - DAY 3 に参加した。

マネージャーとして go 開発のマネジメントをしているため、メンバーの開発者よりは知識やスキルが高くないとコードレビューや適切な指示ができない。2018年ぐらいまで go 開発をしていたが、その後はずっと java 開発をしていたため、最近の go 開発の話題はあまり把握していない。毎週チーム勉強会 (いまのところ、go 開発の話題) をやっていると、チーム外からも開発者が参加してくれるようになった。チーム外からの開発者が go 開発するときの参考にもなるよう、マネージャーのお仕事の付加価値として、組織全体へ go 開発の知識やスキルを提供できればと考えながら働いている。

今回はテストについて話題で7割ぐらいは知っている知識ではあったが、3割ぐらいは最近の話題や静的解析の知見からの深い洞察を話されていてとても参考になった。知っている知識でも幅広いテストの話題の中で厳選されたコンテンツになるのだろうから本質的に大事なことや最初に学ぶべき優先事項を知ることもできた。私がメンバーに教えるときのコンテンツの参考として役に立つ。まったく知らなかった話題としては、txtar というテキストをアーカイブしたフォーマットをファイルシステムとして扱えるようにした txtarfs や、1.18 から追加された fuzzing というテストの入力値を自動生成する機能が追加されたこと。あと groovy でいうところの power assert に近い機能を提供するライブラリとして google/go-cmp をいまはテストに使うらしい。たまたま Go Test Comments を読んでいたら go-cmp は go の開発チームが保守していて go のバージョンに依らずほとんどの比較の要件にあうツールのように説明されていて利用を推奨している。

元同僚の来訪

0時に寝て4時に起きてドラクエタクトしてだらだらして7時に起きた。

echo を採用

昨日の続き。echo か chi でそれぞれサンプルコードを書いたものを定例でメンバーに説明して echo に決まった。echo は知っているメンバーもいたけど、chi は知らなかったみたい。アプリケーションに近いせいか echo の方が認知度が高いみたい。既存コードの移行は私がちゃちゃとやろうと着手したものの、わりとコードが込み入っていて2-3時間でできるものでもなかった。環境変数周りの処理も dry の原則に違反していたので caarlos0/env を使うことにした。エントリーポイント周りのコードをリファクタリングして merge request を作成した。明日中には既存の http ハンドラー周りの移行をしてレビューができるようにしておきたい。

遠方より来る

たまたまタイムラインで元同僚が近くに来るというのをみかけてせっかくの機会なので晩ご飯を食べに行ってきた。大阪に泊まっているのにわざわざ神戸まで足を運んでくれた。感謝。ゲームのコミュニティに属していると私は思っていたのだけど、最近はゲームよりも vr の世界の住人らしくて、vr の世界のコミュニティに入り浸っているらしい。そんな生活を何年もしているうちに仲間うちで仲良くなって、たまにオフ会で会ったりもするとのこと。全国に vr の世界の仲間がいるから出張したときにオフ会したりするそうな。oculus quest 2 をもっているけど workrooms ぐらいしか使ってなくて、若い人はもっと進んでいるなと関心をもって聞いていた。

内製のデータベースのプロダクトが完成して社内でも使ってもらう運用段階まできたとのこと。データベースをフルスクラッチから3年かけて開発できるだけの余裕のある会社は少ないだろう。本人もいくつか社内・社外の事情が重なってプロジェクトが中止にならず運がよかったと話されていた。開発の区切りもついたので今後のキャリアや転職も含めていろいろ考える時期になっているみたい。まだ30歳前後だと思うのでいろいろ挑戦したらよいと思う。

帰りに三ノ宮の街並みも少し紹介した。三宮という地名は他にも一宮から八宮まであって 神戸八社 と言う。間違えて九まであると言ってしまった。八までだった。2021年に 神戸三宮阪急ビル が完成して阪急三宮駅の周辺が再整備された。夜歩きしても楽しめる雰囲気にはなっている。

http フレームワークの選び方

昨夜いろいろあって帰ってくるのが0時過ぎになった。23時過ぎから雨降りで雨の中、自転車で帰ってきた。2時に寝て5時に起きて7時半に起きた。危うく寝坊するところだった。

母の入院

昨夜のいろいろのすべて。最悪の事態を想定してお手伝い先にも今日休むかも?と昨日の夜時点で一報を入れていた。結論としては休む必要はなかった。「ろれつが回らない」という連絡を受けて姉が救急車で病院へいくことを指示して即検査で即入院した。母は過去に目がみえなくなって脳梗塞だったことがある。幸い一通り検査して問題はなかったものの、念のために2日間入院して明日退院する予定。姉に病院の付き添いとかいろいろやってもらったので、私も週末に帰って様子をみてくる。お仕事が立て込んでてんやわんやだけど、そのために神戸で自分の会社をやっているのもあるので仕方ない。母は車を運転しない方がよいだろうという見立てで週末にレンタカーも借りた。久しぶりに高速バスではなく、高速道路をドライブしながら実家へ帰る。

echo と chi でサンプルコードを書いてみた

go の http フレームワークの選定 の続き。明日、定例があるのでメンバーにソースコードを共有しつつ、http フレームワークの採用を決めようと考えている。特定のルーティングとミドルウェアの適用をする簡単なサンプル。

net/http のレイヤーであれこれカスタマイズしたいなら chi でよい気もするけど、web api のアプリケーションのレイヤーにのみ注力したいなら echo を使った方が楽そうという私の第一印象。web api サーバーを書いてて request のパラメーターを扱うことはあっても response writer を扱う必要性をあまり感じたことがない。json しか返さないのだし、構造体を返したら勝手に json に変換してくれたらそれでいいんじゃないかと私は考えている。

新しいお仕事で3週間

2時に寝て4時に起きて仮眠して6時半に起きた。たぶん寝たんだろうぐらいの感覚。10月まで対外的には週4日で働いていたのを、11月から週5日フルタイムの働き方に移行して、やっぱりしんどいという実感がある。対外的に週4日でも10月もオフィスに来て自社のお仕事をしていたり、半日ぐらいは社外のお仕事をしたりはしていた。それでも働く義務の有無によって、意識の違いか、プレッシャーやストレスの面からなにか働き方が違うように思える。生活も働き方もまったく同じなのに。

盛り上がってないイベント

ハッシュタグ をみてもほとんど関係者や発表者しかコメントしていないようにみえた。過去に新規事業の立ち上げに協力したプロジェクトの発表があると元同僚のタイムラインで知ったのでその発表だけみてみた。私が辞めてから3年ほど経つので新規サービスも追加されていてその内容がメインだったように思う。

あまり技術的な内容ではなく、ビジネス向けでもなく、どういった属性の聴衆向けの発表なのか、私にはあまりピンとこなかった。発表の準備不足な印象を受けた。発表を無理やり押し付けられたのかもしれない。

go の Time 型とタイムゾーン

go の Time 型は Location をもっていて、タイムゾーンも一緒に扱える。モダンな言語なら時刻を扱うときにタイムゾーンをセットで扱うのでよいと私も思う。タイムゾーンをもっていない時刻型とタイムゾーンを設定するための余分なコードのことを考えずに済む。

package main

import (
	"fmt"
	"time"
)

func mustGetJST() *time.Location {
	jst, err := time.LoadLocation("Asia/Tokyo")
	if err != nil {
		panic(err)
	}
	return jst
}

func main() {
	now := time.Now()
	fmt.Println("now:", now)
	fmt.Println("jst:", now.In(mustGetJST()))
	fmt.Println("utc:", now.UTC())
}

実行結果。

$ export TZ="CET"
$ go run test_time_now.go
now: 2022-11-18 17:00:30.08305121 +0100 CET m=+0.000011788
jst: 2022-11-19 01:00:30.08305121 +0900 JST
utc: 2022-11-18 16:00:30.08305121 +0000 UTC

技術選定の根拠

0時に寝て5時に起きた。夜中に目覚めたかどうかはわからないぐらいにはたぶん寝てたと思う。

go の http フレームワークの選定

net/http で実装していた web api サーバーにフレームワーク導入しようかと考えている。いままでは認証・認可を外部で行う想定だったが、やっぱり api サーバーに実装した方がよいだろうと要件を再確認したので routing と middleware を再利用できるフレームワークを使うメリットが出てくる。net/http 上で直接 routing, middleware を実装するのは別に難しくないから自分で実装すればよいという考え方がある。一方で誰が実装しても大して変わらないものを車輪の再発明する必要があるのかというところに私は懸念に感じる。また context があとから標準ライブラリに追加されたため、net/http の HandlerFunc は context をシグネチャにもっていない。リクエストコンテキストをもっていないのが net/http の欠点だと私は考えていた。しかし、調べてたら NewRequestWithContext が追加されていてハンドラーではなくリクエストからリクエストコンテキストを扱えるようになっていた。これは私の勘違いだった。

フレームワークを使おうと決めて難しいのはなにを選ぶか。最近の流行り廃りや動向を私は知らないので基準がない。たまたましぶかわさんの記事をみつけて読んでいた。

この中で紹介されている chiecho のどちらかにしようと直観で決めた。echo は以前 go の勉強会をしたときにいけうちさんが採用していたのでよく覚えている。そのときの話しを聞いていてもよさそうにみえた。たまたま echo のサイトをみたら Shiguredo さんのロゴがあって驚いた。スポンサーをされているらしい。chi はまったく知らない。どちらも十分によく使われていて middleware も揃っているフレームワークにみえる。本質的にはどちらを選んでも構わない。一方でマネージャーとしてどういう調査をして、どういう根拠で、どの技術を選定するのか。メンバーに対して説明責任を果たすためにこの2つのフレームワークの調査をすることに決めた。私自身がどちらもフレームワークも使ったことがないので軽くコードも書いてみてどんな雰囲気なのか感触を掴みつつ、フレームワークのソースコードも読んでみようと思う。

久しぶりに go のテストコードを書いた

0時に寝て3時と5時に起きて7時に起きた。まぁまぁ眠れたと思う。

go のテストコードのサンプル

先日 Logger のコード を書いて、テストコードのサンプルも書いてみた。いま微妙に TableDrivenTests が書けてないので参照実装として Logger のデータ駆動テストを書いてチームに共有した。私も future さんのテストのチュートリアル記事を読みながら復習してた。

昔、私が go 開発していた頃にはなかった新機能としてサブテストを並列に実行できる。

uuid ライブラリの歴史的経緯

たまたま Version 1 UUID を返す NewUUID のコードをみていて、err を返しているけど、現時点の実装では err が返ることはなく、これは歴史的経緯でシグネチャを変える方が影響が大きいだろうという意図でそうなっているらしい。

ここでは New を使えとも書いてあるけれど、これはエラーが発生したときに panic が発生するのでこれはこれでいいんやろか?という疑問も出てくる。

ログおじさん

23時に寝て3時半に起きて眠れそうになかったからそのまま5時からオフィスで作業してた。

システム構成の検討

コンサルタントから顧客要件のヒアリングを行い、プロダクトを提供するインフラのシステム概要を mermaid で書いた。オンプレとクラウド環境のそれぞれを同じコンテナアプリケーションで動かすための構成を検討した。クラウド環境の一例として aws の構成を考えていて、https と http のプロトコル変換のようなことをするには api gateway を経由しないといけないと考えていたら、alb に証明書を設定して api gateway なくてもいけるとはらさんに教えてもらった。昔からできたそうで、なぜか私が長い間ずっと勘違いしていた。また時間があるときに自分でもやってみようと思う。

Logger の再実装

プロダクトのコアな部分の実装は私がみた方がよいだろうと考えていて、そのうちの1つ Logger の設計がよくなかったので私が作り直した。といっても cybozu-go/log を使った薄いラッパーを設けただけ。チームメンバーからどこでエラーが起きているか追跡しにくいという声があったのでログ出力したところのソースコードの情報を出力しようと考えた。ググればたくさん出てくる。スタックフレームにアクセスする標準パッケージとして runtime を使うとできる。runtime.Caller と runtime.Callers は似て非なる関数のようでファイル名と行番号だけでよければ Caller を使った方がシンプルになると思う。関数名もほしかったら Callers を使ったスタックフレーム自体から取得する必要がある。

func Trace(skip int) (file string, funcName string) {
  pc := make([]uintptr, 15)
  n := runtime.Callers(skip, pc)
  frames := runtime.CallersFrames(pc[:n])
  frame, _ := frames.Next()
  _file := frame.File[strings.Index(frame.File, sourceRepositoryPath)+8:]
  file = fmt.Sprintf("%s:%d", _file, frame.Line)
  return file, frame.Function
}

この情報を cybozu-go/log の map に追加するようなログ関数を提供するようにした。cybozu-go/log は標準の log パッケージに足りないところだけを追加していて、そのシンプルさと拡張性の高さを私は気に入ってよく使っている。私が気に入っているのでもっと有名になってほしい。

前のお手伝いでもログ基盤を含めて Logger を作っていて、またいまも Logger を作り直していて、気付いたら私は Logger やログ出力に一家言あるような、ログおじさんになりつつある。

よい go コードを書くためのガイド

2時に寝て6時に起きて2度寝したら8時だった。生活リズムがおかしい。

Go Code Review Comments の学び直し

私の周りでは Go Code Review Comments というドキュメントが引用されているのをよくみかける。google 社での go のコードレビューのときによくある指摘をまとめたものである。pr/mr を送る前にこれぐらいは自分でチェックしようといったガイドになる。私自身、過去に何度か読んでいるとは思うが、久しぶりに go 開発をするので学び直しも兼ねて読み直すことにした。うちのチームは java 開発者が多いせいか、go のコードで go っぽくないところがいくつか散見されていた。チームメンバーにも共有する意図も含めて2回にわけて勉強会をしてみんなで読み合わせをする。その下調べとして既存のコードでこのガイドに準拠していないコードがあればそれはわかりやすい事例になるので探したりしていた。

設計談義

0時に寝て6時に起きた。2時と3時ぐらいに起きたけど、まぁまぁ眠れた。

go の interface の考え方

メンバーと設計の議論をしていて interface の考え方の概念を誤解しているように感じたので Go Code Review Comments の interfaces で書いてあることの意図や背景などを解説した。メンバー全員を集めて30分ほどで説明した。既存のコードは過剰に interface を設計していて、特定のメソッドを呼び出すラッパー関数を設けて、そのシグネチャに interface を受け取って構造体のメソッドを呼び出すコードを書いている。こんな感じのコード。

type myBehavior interface {
  doSome(data string) error
}

type myObject struct {
  myBehavior
}

func (o *myObject) doSome(data string) {
  ...
}

func handleSome(o myBehavior, data string) error
	return o.doSome(data)
}

handleSome のようなラッパー関数は不要だし、myObject の構造体に interface を埋め込む必要はないし、Go Code Review Comments では構造体を定義しているところで interface を提供しない方が保守コストが下がってよいよと提案している。これは java のような nominal subtyping と go の structural subtyping の違いで go らしい interface は構造体の提供側ではなく、呼び出し側で勝手に定義して任意の振る舞いを強制できるといった内容を java と go のコードを比較しながら説明した。そして、この話しが重要になるのはサードパーティのライブラリを利用するときに interface が変わると、それを使っている開発者に大きな影響を与えるので interface を提供するなら慎重に練ったものを公開しないといけないという java 開発から得られた知見などが影響しているのではないかという私見も話した。さらに自分たちが管理しているコードなら interface が変わろうが struct のメソッドが変わろうが、すべて自分たちが変更できる権限をもっているから設計時に厳密に interface やメソッドの振る舞いを詰めきれなかったとしても、後から必要ならいつでもいくらでも変えればいいだけと一緒に話した。開発のバランス感覚は経験からでないと身に付かないものだと思う。

出張の最終日

出張の最終日

0時に寝て7時に起きた。疲れているせいか、よく眠れたと思う。わりと出張でよく眠れているので普段眠れていなかったのは体力が余っているからではないかという気もしてきた。

課題の洗い出し

一昨日の続きでわかっていることや進捗のあったものを確認しながら、追加で課題を作って整理していく。まだまだ課題が足りないのでどんどん作っていかないといけない。それと同時に go のソースコードを読みながら設計や改善の要点を私の中で把握していく。java に慣れたプログラマーが書いた go のコードなので java の考え方の影響が強いようにみえた。私がいくつかアドバイスする余地はあるようにみえた。google でコードレビュー時によくある指摘事項をまとめた有名な wiki がある。メンバーに聞いたらちゃんと読んだことがないということだったので2-3回かけてみんなで読んで学ぶ機会にする。私自身、数年前に読んで忘れていていることも多いだろうから学び直し。テストのページは2019年9月に追加されている。たぶん読んだことない。

課題管理勉強会

1時間分ぐらいの資料を用意したつもりが35分で終わってしまった。勉強会の雰囲気が固かったのか、慣れない場所での説明だったのか、マスクした状態で長々と話すことも過去に一度もやったことなくて話しにくかった。初めての試みであまりうまくいかなかったが、初めてやることでうまくいかないのは私にとって当たり前のことなので次の勉強会に向けて改善していきたい。どのぐらい伝わったのかわからないけれど、もっと参加者を巻き込んだ活気のある勉強会になるように努めていきたい。

リアル飲み会

19時から3年ぶりに友だちとリアル飲み会。せっかく東京に行く機会だからと5日のうち3日飲んでいたので後半になるほどバテていった。これは加齢による体力低下もあるのだろう。娯楽はどういうものか?という定義や在り方の議論が盛り上がって、私は暇つぶしの時間であって何もしないのでぼーっとしているのも退屈だからその時間を埋めるもの、楽しければいいけど楽しくなくても、どうせ何もしない時間なのであまり気にしないといった考え方をしている。私の友だちは楽しむために娯楽に集中するとか、その時間を無駄にしないようになるべく楽しめる娯楽を選択するとか、24時間のうち、1時間足りとも無駄な時間にはしないぞという姿勢がみえて、私からみたらそんな生活はしんどくないですか?みたいな気持ちになった。おそらく時間を無駄にしたことがストレスになるからそういう姿勢になるのだろうと推測する。娯楽をしながらだらだら時間を過ごすということはないらしい。オンライン飲み会はちょくちょくしていたものの、3年ぶりにオフ会をしたので飲食代をご馳走になった。感謝。前も会社を作った後の飲み会でご馳走になっていて、なかなか私からお返しできていない。それを覚えておくためにもここに書いておく。

本棚に埋もれて眠る

この日は 新宿 BOOK AND BED TOKYO に泊まった。前に浅草の同施設に泊まったことはあったけれど新宿は初めて。大雑把に言えば本屋とカプセルホテルが合体したような施設になる。この非日常の雰囲気が好きなので機会があれば泊まるようにしている。宿泊費は6,000円とカプセルホテルより高くビジネスホテルより安いという価格帯。ここに来て本を読んだり泊まったりしている人はコワーキングスペースもしくはコミュニティ的なスペースが好きで本も好きな人たちだと思う。勉強会に行く感覚と似ている。そういう自分と似た人たちが集まる空間そのものが価値観の共有だったり安心感につながっていて私はそういう空気も楽しんでいたりする。とはいえ、バテバテで疲れていたので少しだけ本を読んでわりとすぐに寝た。