こんにちは。 Goを推進するGolang推進グループに所属してGoエンジニアをしている @yoskeoka です。
2020年11月〜2021年5月まで、書籍「Go言語による並行処理」(日本語翻訳版) の社内輪読会を全20回×60分かけて行いました。 この書籍の内容が気になっている人や、輪読会の題材としてどうなの?ということについて、得られた知見を共有したいと思います。
Goでは基礎的な文法を説明した入門的な書籍以外はあまり多く出版されていません。2018年にこの書籍の和訳が出版されたときはGoを高度に使いこなしていくためには必須の一冊ではないかと思い購入して一読した記憶があります。
それから月日は経ち、あるマイクロサービスの開発で、並行処理が有効な場面で、並行で通信する実装をする機会がありました。コードレビューで並行処理が正しく行えているのかわかりにくい、fan-in, fan-outパターンを使えばもっと上手くやれるのでは 等々の激しい議論が交わされました。 その結果ですが、Goの並行処理を語る上での共通言語は身につけておいた方がいいよねということになり、改めてしっかりと本を読む機会として、社内輪読会を主催することにしました。
書籍について
こちらの日本語翻訳版を使用しました。 日本語翻訳版は、訳者による訳注や補遺が追加されていたりするので、おすすめです!
輪読会の進め方
目的
輪読会をする目的は以下のようにしました。
- 並行処理が求められるときの会話の共通言語(キーワードとか)を身に着ける
- 実戦レベルに身に着けるところまでは求めない
- 概念、何がうれしいのかとかは全員理解したい
- Go自身への理解を深める
進行
輪読会で進める範囲を事前に10ページ程度決めておき、章の内容に合わせて読むパートと書くパートとして進めました。 それぞれの進め方の概要と、対応章は以下の通りにしました。
- 1, 2, 6章は読むパート
- 当日は担当を決めて 1. セクションごとに要約作成まとめ、 2. 気付きの発表、3. 疑問、理解不足の解消 を順に行う
読むパート時間配分
時間 | 項目 | 補足 |
---|---|---|
5分 | オープニング | 挨拶とか、今日の進め方の確認 |
25分 | 要約作成 | セクション毎に担当を振って、まとめる or 読んできてない人は読む |
25分 | 内容確認・議論 | 疑問解消、内容理解を進める |
5分 | クロージング | まとめ、次回の予定確認 |
- 3, 4, 5章は書くパート
- 範囲の説明テキストは事前に読むが、コードは眺める程度でOK)
- モブプロ形式で書く(ドライバは1回開催ごとに交代)
書くパート時間配分
時間 | 項目 | 補足 |
---|---|---|
5分 | オープニング | 挨拶とか、今日の進め方の確認 |
45分 | モブプロ | コードを写経、動かす |
5分 | まとめ | 疑問点、気付きがあれば共有する |
5分 | クロージング | まとめ、次回の予定確認 |
なぜ輪読会なのにコードをモブプロのように書くことを選択したのか?について補足しておくと、 3章、4章、5章はGoで実際に並行処理を実装するための機能、パターン、テクニックをコード例を元に解説しています。 ならば、その理解度を高めるためには実際にコードを写経して動きを追った方が良いと考えました。
全20回の内訳
20回の間に、各回でどんな範囲を扱ったかも共有しておきますので、参考までに。
回 | 章 | ページ | 進め方 | 内容 |
---|---|---|---|---|
1 | 1章 | p1-10 | 読む | 1 並行処理入門〜 1.2.3 メモリアクセス同期 |
2 | 1章 | p10-22 | 読む | 1.2.4 デッドロック、ライブロック、リソース枯渇 〜1.3 複雑さを前にした簡潔さ |
3 | 2章 | p23-35 | 読む | 2.1 並行性と並列性の違い〜 2.4 Goの並行処理における哲学 |
4 | 3章 | p37-49 | 書く | 3.2.1 WaitGroup |
5 | 3章 | p49-59 | 書く | 3.2.2 MutexとRWMutex〜3.2.4 Once |
6 | 3章 | p59-70 | 書く | 3.2.5 Pool〜3.3 チャネル(途中まで) |
7 | 3章 | p65-79 | 書く | 3.3 チャネル |
8 | 3章 | p79-86 | 書く | 3.4 select文〜3章終わり |
9 | 4章 | p87-96 | 書く | 4.1拘束〜4.3ゴルーチンリークを避ける |
10 | 4章 | p96-106 | 書く | 4.4 orチャネル〜4.6 パイプライン |
11 | 4章 | p106-117 | 書く | 4.6.1 パイプライン構築〜4.7 ファンアウト、ファンイン |
12 | 4章 | p118-126 | 書く | 4.7 ファンアウト、ファンイン〜4.10 bridgeチャネル |
13 | 4章 | p 126-138 | 書く | 4.11 キュー〜4.12 contextパッケージ |
14 | 4章 | p138-148 | 書く | 4.12 contextパッケージ〜4.13 まとめ |
15 | 5章 | p149-164 | 読む1 | 5.1 エラー伝播 〜 5.2 タイムアウトとキャンセル処理 |
16 | 5章 | p164-177 | 書く | 5.3 ハートビート〜5.4 複製されたリクエスト |
17 | 5章 | p 175-191 | 書く | 5.4 複製されたリクエスト〜5.5 流量制限 |
18 | 5章 | p191-198 | 書く | 5.6 不健全なゴルーチンを直す〜5.7 まとめ |
19 | 6章 | p199-214 | 読む | 6.1 ワークスティーリング〜6.3 結論 |
20 | 補遺 | p215-227 | 書く | 補遺A , 補遺B, 勉強会〆 |
実際にやってどうだったか
私自身は、輪読会という形式の勉強会を実施するのは初めてでした。 まずは準備として、何度か社内勉強会や輪読会をしているチームリーダーの @ysakura_ に輪読会で得たいものや進め方を持って相談にいきました。
相談内容として、得たいものは冒頭の目的のところの通り、進め方の案は、参加コストをなるべく下げるために事前の予習がなくても参加できる進め方にしたい と考えて相談したのですが、本の内容は難しめなので事前にしっかりと読み込んでおいて要約を作り、当日はディスカッションに充てるのがいいとアドバイスを貰いました。
実際にやったところ、60分で本書を10ページ程度読んで内容について話すというのはかなり無茶がありました。 そこですぐに軌道修正し、範囲は事前に読むことにしました。ただし、書くパートについては、当日コードをしっかり理解する時間に充てているので、コードは細かく読まなくてOKとしました。
そんなこともありましたが、読むパートでは予定通りの流れでスムーズに進めることができたと思います。
書くパートでは、モブプログラミングのやり方を踏襲し
- 事前に読んで、どんな内容かは把握しておく
- ドライバー役はあらかじめ決めておいて、コードを書いて実行できる環境を準備しておく
- ナビゲーター役がどこのコードを書くか指示する
- ドライバー役はコードを写経する
- 実行して結果を確認
- コード改変したり、わかりにくい部分を読み解いたりするためにワイワイする
といった雰囲気で進めました。
5章のコードは、紙面の節約のためにコードが不完全であることが多いので、それまでに書いたコードを保管しておくか、サポートリポジトリをすぐに参照できるようにしておいた方が良いです。併せて、Pull Requestsも確認すると良いです。不完全で想定通りに動かない場合などは有志がPRを作成している場合があります。
また、今回はドライバー役を決めるために、最初に参加者に番号を振っておいて、次回のドライバー役は次の番号の人としました。こうしておくことで、次の人が予定合わなくなってしまっても、自動的にその次の人にスムーズに担当をお願いすることができました。
良かったこと、悪かったこと
本書から得られると期待していた知識はきちんと得られたのは良かったことかと思います。
- 並行処理の用語、考え方、パターンが身についた
- Goのプリミティブと標準パッケージを使った並行処理のパターンが定着した
そして、輪読会なのにモブプログラミング形式でサンプルコードを動かすというアプローチは、想定より効果があったと思います。 サンプルコードは、その通りに写経しているつもりでも動かないということは発生しがちなので、経験者も交えて書くことで、動かないトラブルにもスムーズに対応できたと思いますし、紙面では本質ではないため説明されていない事項も補足することが出来たりしました。
また、入社1ヶ月で勉強会を主催したことで
- 社内で勉強会を主催したことで、普段交流のない他チームと面識が出来た
- Golang推進グループとして、Goの人と認知度が上がった
というような、副次的な効果もありました。
悪かったこととしては、勉強会の進め方自体の部分で
- 勉強会の開催時間を固定していたので、業務都合が変わった人は途中から参加できなくなってしまった
- 予習を無くして、参加ハードルを下げようとしたが、結局30分〜60分程度の予習は必要になった
- 一定ペースで進めるため、要約を作成するだけや、コードを写経するだけに近い内容になってしまった回があった
というのがありました。 これらはもう少し柔軟な進行をすれば良くなるとは思いますが、勉強会進行のための管理コストが増大するので悩みどころです。
参加者フィードバック
参加者にアンケートに回答してもらったので、いくつか参加者の声を紹介します。
自力で読み進めていなかった部分も本勉強会に参加したことで読むことができました。 とてもよい経験となりました。
以前に1読していたがわかったようなわからないような…という気持ちのままだったのが輪読会を通して「なんでこうなってるんでしたっけ?」がわかるようになったので☆5です!実際にサンプルコードを書いたり、書いたコードに少し手を入れた上で解説してもらえたのがGoodでした。
勉強会の課題感は、参加者の方々も感じていたようです。
自分の自習不足ですが読むことやコードを追うことに手一杯でそのさきの議論があまりできなかった気がしました。
最終的に4名固定になってしまった…。10名だと多すぎて無言の人がでてしまうが主催者を除いて6名くらいは常時いる勉強会だとより議論が活発化して得るものがあったんじゃないかなぁと思います。時間を固定して開催していたけどメンバーが集まりやすい時間を都度調整するタイプだと参加率があがるのでは?と少し考えていました。
再度輪読会をするとしたら
以下のようなことはしっかりとやりたいです。
予習としてやって欲しいことを明示
書くパートのドライバをお願いした人が、書くのが遅くなってしまった場合に備えて、予め書く予定のコードを事前に書いて動作まで確認していたということがありました。当日のドライバ担当をスムーズに出来るようにとの配慮だとは思いますが、予習として期待することをきちんと提示しておけば良かったと思いました。 また、当日の予定がずれてしまっても問題ないことも強調しておけば良かったと思います。 (動機の問題で、配慮からならやりすぎて欲しくないけど、自発的なら是非自習をやった方がいいと思います)
参加者同士のコミュニケーション時間を確保
当日やる内容が、なぞるだけで終わってしまわないように内容を打ち切ってでも、質疑やディスカッションの時間は確保する方が良さそうです。 内容をなぞるだけなら一人でも出来るので、内容の理解を深めたり発展させることが出来るのが勉強会として人を集める意義ではないかと思います。
まとめ
Go言語による並行処理は、Goの特徴の並行処理をうまく扱えるようになるための必須の知識が詰まった良書です。 ある程度Goは書き慣れてきたなというタイミングのGopherにピッタリの書籍かと思います。 今回紹介した通りの進め方がベストというわけではないですが、参考にして、一度輪読会を開催してみてはいかがでしょうか?
マネーフォワードでは、エンジニアを募集しています。 ご応募お待ちしています。
【サイトのご案内】 ■マネーフォワード採用サイト ■Wantedly ■京都開発拠点
【プロダクトのご紹介】 ■お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android
■ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』
■だれでも貯まって増える お金の体質改善サービス 『マネーフォワード おかねせんせい』
■金融商品の比較・申し込みサイト 『Money Forward Mall』
- 5章は書くパートだと説明しましたが、5.1, 5.2 に関しては読み物な内容だったので読むパートの進め方をしました↩