blog.syfm

徒然なるままに考えていることなどを書いていくブログ

A Philosophy of Software Design を読んだ

A Philosophy of Software Design

A Philosophy of Software Design

170 ページくらいの洋書で、ソフトウェアの Complexity (複雑さ) について扱っている。洋書ではあるけど、難しい表現はあまりなく読みやすかった。

この本の冒頭で、Complexity を「ソフトウェアシステムを理解しづらくさせたり、変更させにくくする、システムの構造に関連するすべての要素」と定義し、それによって引き起こされる問題を述べている。
それ以降の章では、いかにして Complexity を減らすかというところにフォーカスし、モジュールの設計やレイヤーごとの抽象度、エラーの定義とハンドリング、コメントの種類と記述すべき場所など、さまざまな視点から見た手法や考え方が紹介されている。
どの章も興味深い内容だったけど、特に以下の章が良かった。

  • 第 4 章「Modules Should Be Deep」
  • 第 10 章「Define Errors Out Of Existence」
  • 第 13 章「Comments Should Describe Things that Aren't Obvious from the Code」

第 4 章「Modules Should Be Deep」には「deep module」という必要最小限の公開インターフェース (API) のみで多くの機能を提供できるようなモジュール設計の考え方が登場する。これを守ったモジュールは恐らく SOLID 原則を守ったモジュールと同様の特徴を持つと思うけど、モジュールの質を「deep」かどうかで測るという新しい視点は非常にわかりやすく、面白いと思った。

第 10 章の「Define Errors Out Of Existence」での、「モジュールの使用者が知らなくてはいけない例外やエラーは、そのインターフェースの仕様の一部 (= 仕様が増えるほど Complexity も増える)」という考え方が非常に良かった。さらに、この章では、その考え方に基づいて、エラーとしてモジュールの利用者へ投げないエラーを定義したり、いくつかのエラーを集約する手法が紹介されていた。

自分が普段よく使っている Go の標準ライブラリもこういった思想に基づいて作られているので、改めてよく設計されているなぁと感じた。

第 13 章の「Comments Should Describe Things that Aren't Obvious from the Code」は個人的に一番良かった章だった。 この章ではコメントの種類を以下の 4 つに分類し、適切な箇所に適切な種類のコメントをすべきだと主張していた。

  • インターフェースコメント: モジュールを利用するにあたって、そのインターフェースの振る舞い、引数や戻り値、副作用や返す可能性のあるエラーなどの記述
  • データ構造メンバコメント: クラスのフィールド変数や、静的変数に対するコメント
  • 実装コメント: メソッドや関数内に書くコメントで、それらのコードがどう動作するかの記述
  • クロスモジュールコメント: モジュールを跨ぐ依存に関する記述

モジュールの利用者に近い (より上位な) 種類のコメントでは、どういう振る舞いをするか (how) を記述する。その内部動作を抽象化したモジュールの仕様を記述し、実装をモジュール使用者から隠蔽する。 より実装に近い (下位な) 種類のコメントでは、なにをしているか・なぜそうしているか (what / why) を記述する。コメントの読み手がコードの挙動を理解できるように正確な記述を行う。

最近は、Go ソフトウェアを書くときにかなりの頻度で作成しているパッケージの GoDoc ドキュメントを見ることで、理解しやすい記述かを客観的に確かめたりしていた。そのため、この章で紹介されていたコメントの書き方は非常に参考になった。

この本の様な、即座に自身の開発スタイルやコードレビューに適用できる内容を扱っている本は今まであまりなかったため全体的に新鮮だった。もうちょっと戦術寄りな本だとリーダブルコードが近いと思った。
冒頭でも言ったとおり、そんなにボリュームが大きくなく読みやすい英文なので洋書を読んでみたいけどハードルが高い…と感じている人も是非。

一年を振り返り… (2018)

去年は 👇

syfm.hatenablog.com

1月

初日の出

高校の友人らと毎年恒例の初日の出を見に行った。 f:id:ktr_0731:20181228163640j:plain

end of 就活

1月のカレンダーの予定を見てみたら毎週就活関連で東京へ行っていた。1月で全て終わったので以降はだいぶ落ち着いた。

OpenAppLab Aizu LT feat. CyberAgent

会津大学の LT イベントで CyberAgent のエンジニアの方々が来ていた。自分は fmt の実装について話した。

speakerdeck.com

また、CyberAgent のエンジニアの一人として c-bata さんが来ていた。ちょうど自作の CLI ツールで c-bata/go-prompt を使っていて、いろいろお話できて楽しかった。ここで話していた内容が go-prompt v0.2.0 で反映されていて嬉しかった。

qiita.com

読んだ本

SAO アリシゼーション編全巻

たとえとどかぬ糸だとしても1 (百合姫コミックス)

たとえとどかぬ糸だとしても1 (百合姫コミックス)

柴田さんが翻訳をしている本で、リーダブルコードに書かれているような、より良いコードの書き方から、自分が暗黙知として身につけているようなことまで、幅広く書かれていた。

ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック

ベタープログラマ ―優れたプログラマになるための38の考え方とテクニック

2月

インターン

3 月の第 4 週までブロックチェーン関連のインターンをしていた。ブロックチェーンコミュニティがどうも苦手で、最近はあまり関心を持たなくなってしまったけど今後どのように発展していくのかは興味がある。

f:id:ktr_0731:20181229010101j:plain
インターン中住んでいたマンション近くのイルミネーション

Go 1.10 Release Party in Tokyo

Go 1.10 リリース記念のパーティがあり、ちょうどインターン期間中で参加できそうだったので参加してきた。
tenntenn さんたちに誘われ、トークもした。20 分のトークは初めてだったのと、他のスピーカーが Go 界隈の有名人しかいなくてかなり緊張した。それでもトークで話した自作 gRPC クライアントが広く使われるようになったので参加して本当に良かったと思う。

speakerdeck.com

読んだ本

ブロックチェーンアプリケーション開発の教科書

ブロックチェーンアプリケーション開発の教科書

3 月

インターン2

3 月の最終週はネクストカレンシーで cointap のサーバサイドの開発をしていた。残念ながらリリースは中止になってしまったけど、設計に関する議論ができてすごく楽しかった。

深崎暮人

東京から会津へ帰る最後の休日で深崎暮人展に行ってきた。友人のぶんのチケットを取り忘れてしまって本当に申し訳なかった…。

f:id:ktr_0731:20181229011317j:plain
ぶれてる

2、3 月はインターン先でフルタイムで働きながら、業務時間が終わった後アルバイト先の仕事もしていたので非常にしんどい月だった。

4 月

f:id:ktr_0731:20181229011635j:plain

情報処理技術者試験

友人二人と毎度おなじみの情報処理技術者試験を受けた。自分はデータベーススペシャリストを受けて、ぎりぎり合格した ✌️

f:id:ktr_0731:20181229011812j:plain
情報処理技術者試験の朝はいつも霧に包まれている

アルバイトをやめた

会津でちょうど一年くらいやっていたアルバイトをやめた。エンジニアは学生が多く、人数も少なかったけど非常に優秀な人ばかりでここでアルバイトできて良かった。これ以降、インターンを除いて働くのをやめ、学生ニートをしている。

読んだ本

5 巻まで。久しぶりに新しい漫画を買ってみたけど良さそうだった。

5 月

f:id:ktr_0731:20181229012959j:plain

イベントに登壇したりはしてたけど、5 月は全体的に何のイベントもなく穏やかに過ごしていた。

会津 春の大 LT 大会

大 LT 大会なるものがあり、メルカリ、クックパッドGunosyCyberAgent など、Web 系の企業 8 社が集結して各企業のエンジニア + 学生がそれぞれ LT をした。 どのトークもすごく面白かったけど、特に deeeet さんと mametter さんのトークが面白かった。

今学ぶべき技術 by deeeet

techlife.cookpad.com

自分も CLI ツールのアップデートに関する話をした。

speakerdeck.com

あと、3 次会でやったジェンガが神回で、めちゃくちゃ盛り上がって楽しかった。

読んだ本

実践ドメイン駆動設計 (Object Oriented SELECTION)

実践ドメイン駆動設計 (Object Oriented SELECTION)

6 月

f:id:ktr_0731:20181229231924j:plain
すっかり見慣れたキャンパスだ

親族旅行

家族と祖父母と会津や芦の牧に旅行へ行った。自分は会津に住んでいるので、現地で合流した。住んでいると忘れてしまうけど、会津は自然豊かだし歴史もあるのですごく魅力的な土地だと思う。過ごしやすくはないけど。

f:id:ktr_0731:20181229014620j:plainf:id:ktr_0731:20181229014540j:plainf:id:ktr_0731:20181229014538j:plainf:id:ktr_0731:20181229014541j:plain

京都旅行

後述するはてなインターン大同窓会というものに参加するために京都に行くことになったので、せっかくだし一人旅をすることにした。
一週間まるまる時間を取り、そのあいだの授業はサボり、ひたすら行きたい観光地を巡った。宿を伏見区あたりで取り、伏見稲荷大社東福寺に歩いていける距離の場所で過ごしていた。伏見稲荷大社は、平日休日問わず人で溢れかえっているけど、深夜になるとほとんど人がいなくなり閑散とするので夜に行くのをおすすめしたい。さすがに山を登るのは難しいけど千本鳥居までなら明かりがあるし、ものすごく雰囲気があるので本当に良い。
寺院と違い、神社は夜中でも開いているところが多いと思う。

f:id:ktr_0731:20181229224344j:plainf:id:ktr_0731:20181229230615j:plain
藤森神社と貴船神社

f:id:ktr_0731:20181229230616j:plain
なでしこ

f:id:ktr_0731:20181229224412j:plainf:id:ktr_0731:20181229230255j:plain
あがた祭りと大吉山展望台

はてなインターン大同窓会

京都旅行の最終日にははてなインターン大同窓会があった。はてなインターンが 10 周年らしく、歴代のインターン生が一挙に集まるというイベントだった。
全員ではないものの、同期にも久しぶりに会えたし、インターネッツで見たことがある人がたくさんいて楽しかった。一次会自体は昼頃から始まり、酒を飲みつつ流れに沿って移動していたらいつのまにか鴨川にいて、結局終電までやっていた。途中、久しぶりにカマルに行った。カマル最高です。

読んだ本

亜人(12) (アフタヌーンKC)

亜人(12) (アフタヌーンKC)

7 月

親族旅行

親戚と家族、祖父母と房総半島に旅行に行っていた。思い返してみると、なんだか今年は旅行が多かった気がする。

その他にはあんまりイベントはなく、ワールドカップを見てた記憶くらいしかない。

読んだ本

Goならわかるシステムプログラミング

Goならわかるシステムプログラミング

8 月

会津旅行

高校の友人らが会津へ旅行来ていたので、いつもの観光地っぽいところを回った。

インターン

長期休暇の間、インターンをしていた。一つのチームに配属され、チーム内のメンバーとペアプロしながらマイクロサービスを開発していた。久しぶりにペアプロをしたけど、やっぱりやっていて楽しいし、理解度も格段に上がるので好き。一ヶ月半くらいしかいなかったけど、それなりに成果は出せたと思うので良かった。

GopherCon 2018

メルカリのスカラシップ制度を利用して GopherCon 2018 に行ってきた。(実質) 初海外で、何もかも新鮮だった。

f:id:ktr_0731:20181229234424j:plainf:id:ktr_0731:20181229233804j:plain
会場の様子

f:id:ktr_0731:20181229234218p:plain
自分と osamingo さん

GopherCon 2018 の詳しい様子は 👇

tech.mercari.com

読んだ本

Clean Architecture 達人に学ぶソフトウェアの構造と設計

Clean Architecture 達人に学ぶソフトウェアの構造と設計

9 月

伊香保温泉旅行 & ISUCON 8

ISUCON 8 をやっていくために伊香保へ旅行へ行き、旅館で戦った。旅館も温泉も温泉街の雰囲気も最高で良かった。
残念ながら ISUCON は負けた…。来年も旅館でやって、今度こそリベンジしたい 💪

f:id:ktr_0731:20181229235253j:plainf:id:ktr_0731:20181229235254j:plainf:id:ktr_0731:20181229235256j:plain

Student Go #1

学生 Go コミュニティによる LT イベント、Student Go に参加していた。以下のようなタイトルで発表もした。

speakerdeck.com

読んだ本

OSSライセンスの教科書

OSSライセンスの教科書

青い春を数えて

青い春を数えて

タイトルの通り、色彩と光について扱った本で、今までイラストを描くときはなんとなくで着色していたので非常に学びがあった。

カラー&ライト ~リアリズムのための色彩と光の描き方~

カラー&ライト ~リアリズムのための色彩と光の描き方~

10 月

技術書典 5

技術書典向けに大学の友人らと一章ずつ執筆し、同人誌にした。スケジュール的にかなり厳しかったけどなんとかなったので良かった。
頒布数もどの程度にすればよくわからなかったけど、完売できたので買ってくれた方々に感謝です。

イラストを描いた

実に一年ぶりくらいにイラストを描いた。ラフ自体は夏のインターン前にできてたけど、あまり進められていなかったので公開までかなり時間がかかった。

f:id:ktr_0731:20181230001247p:plain
夜行

あとは Mercari Tech Conf に行ったり、だいぶサボってた研究を再開したりしていた。

読んだ本

Martin Fowler がいる ThoughtWorks のエンジニアが書いたアーキテクチャに関する本。タイトルに惹かれてなんとなく買った本だけど、多くの学びがあって面白かった。継続的な進化を続けるために、評価基準を定義し、それを評価するための適用度関数を用意するという試みはとても興味深かった。その他にも、モノリスからマイクロサービスまでの範囲でアプリケーション・モジュールの粒度が様々なアーキテクチャたちが紹介されていて、これも個人的には新鮮だった。当たり前だけど、世の中にはモノリスとマイクロサービス以外の選択も十分存在するということを思い出させてくれた。

進化的アーキテクチャ ―絶え間ない変化を支える

進化的アーキテクチャ ―絶え間ない変化を支える

Coders at Work プログラミングの技をめぐる探求

Coders at Work プログラミングの技をめぐる探求

11 月

f:id:ktr_0731:20181230001449j:plain

11 月からはひたすら WHITE ALBUM2 をやっていた記憶しかない…。なんとなくで買ったものの、シナリオが傑作で何度も心に深い傷を負ったので、感傷的になりたい人におすすめ。11 月頃から始めて定量的に進めていたにもかかわらずすべてのシナリオが終わったのはクリスマスイブ直前だった。

読んだ本

以前から欲しいと思っていた柴田さんの書いた本。大学の売店で偶然見かけたので買った。柴田さんのプログラマ人生で得た経験がここに集約されていて、自分もずっとコードを書いていたいと改めて感じさせてくれた良い本だった。

プログラマー”まだまだ”現役続行 (技評SE選書)

プログラマー”まだまだ”現役続行 (技評SE選書)

12 月

聖地巡礼

f:id:ktr_0731:20181230002504j:plain

Go Conference 2018 Autumn

久しぶりに GoCon へ参加してきた。次はネタがあれば発表したい…! f:id:ktr_0731:20181230002713j:plain

クリスマスパーティ

大学の友人らとクリスマスパーティをした。全員が集まれるのは今年が最後なので寂しくなる。

f:id:ktr_0731:20181230002903j:plainf:id:ktr_0731:20181230002905j:plain

中学校の同窓会

成人式以来の久しぶりの同窓会だった。懐かしい顔ぶれですごく楽しかったし、いろんなことを思い出した。また集まれる機会があればいいなぁと思う。

読んだ本

並行計算のモデルの一つである CSP の紹介や、実践的な Go での並行処理パターン、Go のランタイムの仕組みなど幅広い内容で、非常に中身が濃い本だった。
これを読んでからより素直な並行処理を Go で書けるようになったので、並行処理に慣れていない Gopher はぜひ読んでおくと良いと思った。

Go言語による並行処理

Go言語による並行処理

今年買ったけど読めなかった本・読んでいる途中の本

今年もたくさんの未読本がスタックされた。第 4 Q は全然本が読めていなかったので反省したい。来年はもっと計画的に読んでいくぞ!

必要な箇所をかいつまんで読んでいたけど、読み切ったと言うには程遠い。

プロフェッショナルSSL/TLS

プロフェッショナルSSL/TLS

こちらに関しては全然読めていない…。

プロフェッショナルIPv6

プロフェッショナルIPv6

7 割くらい読み終わったけど、最近読めていないので全然終わらない。あと、内容がかなり難解なので繰り返し読まないといけないと思う。

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

今読んでいる本で、半分くらいまで読み終わった。ソフトウェアの複雑さをいかにして減らすか、という目標を達成するためにコードに対してどうアプローチしていくかを書いた本。設計パターンやデザインパターンの本は多いけど、こういった本は意外と少ない。自分が読んだ本の中でそれっぽいのは「オブジェクト指向のこころ」くらい?こちらも良い本なのでおすすめ。

A Philosophy of Software Design

A Philosophy of Software Design

オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)

オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)

終わりに

去年がすごく充実していたので、今年はそれが落ち着いて静かな年になるかな〜と思っていたら、GopherCon で発表してたり、何度も旅行行ってたりしてて、去年に負けず劣らずかなり充実していた。
今年は、なにを判断するのにも必ず複数の基準を設けて総合的に判断できるようになってきた年だった。なので良くわからない Twitter の過激な意見とかに引っ張られたりするようなこともなくなったのでだいぶ精神的に成長した気がする。

自分は大学院へは行かずに就職をするので、来年の春からはついに社会人になる。環境も大きく変わって大変だろうけど楽しみなのでこれから頑張っていきたい。

dept を使った Go ツールの依存管理

はじめに

Go プロジェクトでは、しばしば静的解析ツールが使用されます。例えば、自分のあるプロジェクトで考えてみると、ソースコードの整形には gofmt 、lint には golangci-lint/golangci-lint 、モック用コードの生成には matryer/moq 、CI でのリリース作業では mitchellh/goxtcnksm/ghr が使われています。Go は静的解析を行いやすいプログラミング言語であるため、こうした静的解析ツールは日常的に使用されています。

しかし、Go プロジェクトにおいて、そういったツールの管理に関する問題がいくつか挙げられます。

  1. ツールのバージョン管理が煩雑
  2. ツールの統一的なインストール方法がない

ツールのバージョン管理が煩雑

Go 1.11 以前のバージョンでは、go getgo1 タグ or ブランチがない限り最新のソースコードを取得します。(go1 については budougumi0617 さんの記事 が詳しいです。)
ただ、ほとんどのリポジトリでは上記のようなタグ or ブランチが用意されていないため、あまり有用ではないと感じています。

同様の理由で go get の対象パッケージの依存パッケージ群のバージョンも管理できません。(ただし、リモートリポジトリに vendor ディレクトリがある場合はそちらに配置されているパッケージが優先的に使われます。)

ツールの統一的なインストール方法がない

Go ツールのインストールは主に go get によって行われます。ツールセットをインストールしようとする場合、例えばあるプロジェクトでは README.md に記述された go get スニペットをコピペして実行したり、またあるプロジェクトでは Makefile に記述したりと様々な方法があり、ツールセットをインストールするための方法にばらつきがあります。

ktr0731/dept

幸いなことに、1 つ目の問題は Go Modules の登場によって解決されましたが、2 つ目の問題は依然として残っていました。
この問題を解決するために、dept というツールをつくりました。このツールは、プロジェクトで使用するツールセットの依存管理を行い、Go Modules を利用して依存解決を行います。 以降ではその詳細について紹介します。

github.com

Go Modules におけるツールの依存管理

Go 1.11 では Russ Cox により提案された Go Modules が実験的に導入されました。 Go Modules では、関連のある複数のパッケージをまとめたものをモジュールとして定義し、それらをセマンティックバージョニングで管理し、セマンティックインポートバージョニングによって依存解決を行います。 ライブラリだけでなくツールもモジュール単位になりうるため、セマンティックバージョニングでモジュールを管理するだけでその恩恵を受けることができます。

詳細を解説すると、このポストの本題から外れてしまうので省略します。Go Modules に関する情報はすべて以下の Wiki にまとめられています。

github.com

ツールの依存管理については Wiki に一例が紹介されています。
この方法では、tools ディレクトリに tools.go という、使用したいツールのパッケージをブランクインポートした Go ファイルを作成し、go install <package> を行うことでそれらの依存を go.mod に記録しつつ、バイナリを生成します。

この方法は、新しいメカニズムを入れずに実現できますが、ワークフローが少々煩雑です。
また、依存管理されるツールのモジュールは go.mod に記述されますが、npm の devDependencies などとは異なり、開発時のみに使用するモジュールを分けて管理することができません。

dept は、Go Modules の持つ強みを活かしつつ、上記の様な問題を解決した、より簡単に扱えるラッパーツールです。

dept を使った依存管理

deptgo コマンドと似た非常にシンプルなインターフェースを提供しています。プロジェクトに新しくツールを追加するには dept get を使います。modules-aware mode の go get と同様にバージョンを指定してインストールすることもできます。

$ dept init
$ dept get github.com/mitchellh/gox github.com/tcnksm/ghr@v0.12.0

dept get を行うと、プロジェクトルートに gotool.mod が生成されます。以降はこのファイルを元にツールセットの決定論的なビルドを行うことができます。 透過的にツールを使用したい場合、dept exec が、その他の理由で生成されたバイナリを直接扱いたい場合は dept build が使えます。

$ dept exec ghr -v
ghr version v0.12.0

$ dept build
$ ls _tools
ghr             gox

この他にもいくつか便利なサブコマンドがあります。気になった方はぜひ dept -h を叩いてみてください。

dept の実装

これ以降は dept がどうやって上記のような機能を実装しているのかや、それに伴うつらみを紹介します。

ラッパーツールと銘打っている通り、dept 内部では go コマンドのサブコマンドである go get や、go buildgo mod などのコマンドを実行しています。
例えば、新しいツールを依存に追加する dept get であれば、go getgo build などを叩いたりします。また、これらのコマンドは Go Modules を使うために常に modules-aware mode で実行されます。
このあたりの操作は多少の違いはあれど、上記で紹介した tools.go を用意する方法とほとんど同様です。

これらのコマンドから使われる Go Modules のマニフェストファイル、go.mod は、以下のような理由からプロジェクトで使用される go.mod とは別に管理しています。

  • プロジェクトで使用するモジュールと、ツールが必要とするモジュールを別々に管理したいため
  • dept のリネーム機能や、一つのモジュール内に複数のツールがある場合に go.modシンタックスではそれらを表現できないため

特に二番目の理由はなかなか厄介な問題です。go.modJSON や TOML 等のデータ記述言語ではなく、独自のシンタックスを持った DSL であるため、拡張が非常に困難です。 以前、以下の issue にて議論が行われていましたが、

  1. go.mod を読み書きできる、十分なドキュメントがある API を提供するのであれば言語がなんであれ問題ない
  2. 既存のシンタックスは必要最小限のものであるため、現段階では DSL をそのまま使うべき

といった理由で現在のシンタックスが継続して使われるようになりました。

github.com

特に read-only な操作であれば、go mod edit -json を使うことで JSON として取得できるため、現状大きな不満はありません。

ただ、今回のような go.mod の表現を拡張するといった特異なケースだとやっぱり API が欲しくなります。
今の go.mod の読み書きを扱うパッケージは以下の様に internal 以下に存在し、dept でもこのパッケージを引っ張ってきて使用しています。

modfile - GoDoc

今後このパッケージは public にすることが予定されているようなので、これを心待ちにしています…。

まとめ

  • dept を使うと、ツールの管理が楽になるよ
  • go.mod DSL は拡張が難しくてしんどい時がある