書籍『Powerful Command-Line Applications in Go』でGoによるCLIツール作成のための「パワー!」をもらった

この記事は🎅GMOペパボエンジニア Advent Calendar 2022の21日目の記事です。

まず始めに: GoとCLIツールの相性の良さ

Goの主な用途にCLIツールを書くというのがあると思います。

シングルバイナリにコンパイルされることや、クロスコンパイルが容易なことから、kubernetes/kubectlhashicorp/terraformといった広く使われているCLIツールもGoで作成されています。

私も、tnagatomi/takolabelという、GitHubのlabelsを複数のリポジトリに跨って操作できるツールを作成したりしました(このツールが生まれた経緯についてはこちら: 初めてのGo製CLIツール作成、初めてのOSS公開に込められた物語)。

特に、Goで作成されたCLIツールのユーザーとして思うのは、依存関係を気にすることなく、バイナリ1発で実行できるというのが本当に強力だということです。

そして『Powerful Command-Line Applications in Go』と出会った

さて、そんなこんなで、GoでのCLIツール作成技術を上げたいなと思っていたところ、redditr/golangでこんなポストを発見しました:

Is there a practical Golang entry point for experienced programmers? : golang

PythonによるAutomate the Boring Stuff with Pythonに相当するGoの本はないかとの質問ポストでしたが、それに対するコメントの中にPowerful Command-Line Applications in Go: Build Fast and Maintainable Toolsが紹介されていたのです。

発売時点ではRed HatでAutomation Consultantとして働いているRicardo Gerardiによる本とのことで良さそうと思い、早速買ってみて読んだところ、これが実際にとてもとても良い本だったのでした。

この本では、実際に動くCLIツールを、サンプルコードと共にテストを書きながら学びます。
そのトピックは、ファイル、プロセス、REST APIインタラクティブなターミナルツール、SQLデータベースと広範囲です。そのことから、CLIツールに留まらず、Goでテスタブルな良いコードを書く方法を学ぶのにもうってつけです。

この記事では、その中から特に役に立つと思ったtipsを何個かご紹介します。気になった方は是非本を買ってみてください。

標準出力のテストにはio.Writerを使う

標準出力のテストってしづらいですよね。そこがio.Writerの出番です。
テストしたい関数の引数に、io.Writerを指定し、実際の実行ではos.Stdoutを使い、テストではbytes.Bufferなどにキャプチャさせて比較させるのです。

ずいぶんと既知の方法ではありますが、実際に動くCLIツールの例をもって教えてくれるので、頭にスッと入ってきます。

余談ですが、こういう時にGoの美しいインターフェイスの設計を思い知らされます。

パッケージを適切に分ける

なんでもかんでもmainパッケージに突っ込む、というのは避け、外部から利用できるような形でパッケージを分けます。
そうすることで、ローカルで使っていたものをWeb APIのモデルとしても再利用させるといったことができます。

自分自身がユーザーだとしても、責務の境界線を敷いたりといったことに役に立つはずです。

Repositoryパターンを使う

Repositoryパターンにより、データソースを簡単に切り替えられるようにします。

操作系を、インタフェースのメソッドとして定義し、実際の操作はインメモリやSQLのものとして実装させるのです。これにより、テストもしやすくなります。

これもずいぶんと既知の方法ですが、繰り返しになるものの、実際に動くCLIツールで示してくれるので、とても解りやすいです。

統合テストは実APIなりを叩く方法もある

結合テストをどう書くか、というところはけっこうな悩みどころだと思います。
モックを使うと実際のAPIに追従できなかったりという問題が起こる可能性がありますし、実際のAPIを叩くと実環境に影響がでる可能性があります。

そこで、この本では、build constraintsを使い、統合テストファイルにtagを付与した上で、通常のテストでは実行されないようにし、-tagsオプションを使って散発的に実行するようにしています。

統合テストは通ったのに、実際には動かないといったことを避けるためのバランスの取れた方法で、なるほどなーと思いました。

自前で用意するAPIの場合、テスト用の環境を用意してあげたりすると良さそうですね。

Cobraの使い方

kubernetes/kubectlghでも使われている、メジャーなCLI用ライブラリであるspf13/cobraの使い方も教えてくれます。

コマンドのmarkdownページを出力してくれる、doc.GenMarkdownTreeといった便利関数は知りませんでした。 Versionというプロパティも地味に知らずにいました。

ちなみに、Cobraの作者であるSteve Francia aka spf13さんがこの本の前書きを書いています。そのことからも、この本の品質は保証されていると言って良いのではないでしょうか?

まとめ

他にも、main関数から適切に関数を分離してテストしやすくすることや、Golden filesによるテストの仕方や、関数の型を作っての処理の分岐のさせ方や、httptestパッケージの使い方や、ダッシュボードを作るためのTermdashライブラリの使い方など、とにかくお役立ち情報満載の本でした。

GoでのCLIツール作りをもっと上手くなりたいという方は手にとってみてはいかがでしょうか。

pragprog.com

ゲームのタイムアタック、シューティングゲーム、プログラミングにおける最適化の共通点

僕は現在はソフトウェアエンジニアとして働いていますが、定職に就く前は働かずにゲームをとことん遊んでいました。

その中でも特に遊んだのが海外ゲーム、そしてシューティングゲーム(海外では「Shoot 'em up」と呼ばれます)です。
海外ゲームについては普通に遊ぶのはもちろんですが、いかに早くクリアするかということをしていました。いわゆるタイムアタック(海外では「Speedrun」と呼ばれます)というものです。

これらのこととプログラミングは全く関係ないようですが、プログラミングをしている中で、時々、これらのことでやってたことじゃないか、と思う場面があります。

抽象化できる共通点があるのではないかと思い、この記事で言語化を試みてみます。

遊んでいたゲームの種類

どういうゲームを遊んでいたかという文脈が大事になってくると思うので、説明をします。

海外ゲーム

海外ゲームについては、特にFPSやRPGを遊んでいました。それぞれの代表作のうち、シングルプレイヤーのもので僕が遊んでいた頃で言うと、Half-Lifeシリーズ、Diabloシリーズといったところでしょうか。 タイムアタックがどのようなものかというのは動画を見ていただくと分かると思います。 ※3D酔いというものがあるので、苦手な方は注意をお願いします。
今はVRに注力するJohn Carmackも主要な開発者であるQuakeというゲームのものです。

www.youtube.com

どうでしょう。極めて無駄のない動きじゃないでしょうか。

シューティングゲーム

シューティングゲームとなると、どういうゲームか馴染みのない方もいると思うので、ご紹介します。 先祖はインベーダーゲームとかになるのでしょうか。どういった様子かは動画を見ていただいたほうが早いと思います。
僕も大好きだった、難易度が最高級に高いと言われている怒首領蜂大往生の動画をご紹介します。
下記リンクは「2周目」という、同じステージを難易度を大幅に上げて臨む場面からスタートします。

youtu.be

どうでしょう。鬼のような難易度じゃないでしょうか。

共通点

では、タイムアタック、シューティングゲーム、プログラミングにおける最適化の3つに共通するものとは何でしょうか。
それらについて、1つずつ見ていきたいと思います。

1つ目の共通点「観察」

まず、1つ目は「観察」です。

タイムアタックでは、ステージがどのような構成になっているか、敵キャラクターがどのような動きをし、どのような攻撃をしてくるか、どこにアイテムがあるか、などを観察します。
シューティングゲームも同様です。敵キャラクターがどのような動きをし、どのような弾を撃ってくるか、などを何回も何回も何回もプレイすることで観察します。

では、プログラミングにおける最適化はどうでしょうか。こちらも、どのような処理が行われていて、どこにボトルネックがあるかを観察します。「観測」という言葉のほうがこの世界では一般的ですかね。

プログラミングではリバースエンジニアリングという言葉がありますが、タイムアタックやシューティングゲームにおいても、ただ観察するだけではなく、時にはゲームの実装まで予想しながら分析をすることもあります。

2つ目の共通点「試行」

2つ目は「試行」です。

タイムアタックでは、このジャンプやアクションでショートカットが可能か、このアイテムは取らずとも十分に進行させることが可能か、といったことを試します。
シューティングゲームでは、どの順番で敵を倒すのが安全か、どのようにコンボを繋げば点数が高くなるか、といったことを試します。
どちらも、何百、何千、何万、いや何百万といった試行になるかもしれません。

プログラミングでは、仮説や実証に基づき小さな単位で変更を行います。小さな単位で行うのは差分を細かくチェックするためで、タイムアタックでもシューティングゲームでも同じですね。

3つ目の共通点「評価」

3つ目は「評価」です。

タイムアタックでは、試行した結果、それによりどれだけのタイムが削られたか、Aを選んでBを捨てた結果、それ以降の流れはどうなるかといったことを評価します。
シューティングゲームでは、動きのパターンを決めたことでどれだけ楽になったか、点数が実際に上がったか、といったことを評価します。

プログラミングでは、実行速度やリソースの消費が改善されたかどうかを評価します。

この観察→試行→評価という流れは、ゲームかプログラミングかでサイクルは違えど、改善のためにひたすらループを回すものとなります。

4つ目の共通点「結合」

最後が「結合」です。このフェーズで、これまでの3つが実際に機能するかどうかチェックすることになります。

タイムアタックでは、それぞれのステージで決めた動きが全体としてのタイムの削減に繋がるかを、通してチェックします。
シューティングゲームでは、1ステージ目では低スコアに終わる動きでも、2ステージ以降ではトータルで高くならないか、といったことをチェックします。

プログラミングでは、結合テストなどを行い、1つのコンポーネントの変更が他に影響を与えていないか、トータルではパフォーマンスが下がっていないかといったことをチェックします。

最後に

ここまで、ゲームのタイムアタック、シューティングゲーム、プログラミングの最適化における共通点を書いてみました。

勢いで雑に書いてみた文章ですが、他にこれらのことを経験した方なら、もしかしたら「うんうん」と頷いていただけるかもしれないですね。
共通しているのは根気いるよね〜というところでしょうか。
書いていて思ったのですが、もっと広く一般化できるものなのかもしれませんね。

最後に一言、「最適化 is fun」

数学を一生の趣味にしてみる

子どもが生まれて勉強に取れる時間も必然と少なくなったので、勉強することを絞る必要があるのだが、何をやろうかと思った時に数学をやっていこうとなった。

きっかけとしては、アルゴリズムとデータ構造みたいな基礎的な技術を身に着けるのが長期的に見て役に立つのではないかと思い、問題解決力を鍛える!アルゴリズムとデータ構造を読み始めたところ、序盤に極限の式が出てきて読み取れず、やっぱ数学やった方がいいなとなったことがある。

前から、競プロや機械学習をやりたいが、数学力不足を感じていたというのも大きい。
2016年のプログラマーとして社会人になったけど高校数学を1から独学しているという記事にも書いたが、高校を1年で中退しているので、単純に数学コンプレックスみたいなものを持っているというのもある。

そこで考えたのが、数学を一生の趣味にするのもいいんじゃないかと。
詰将棋を解くような感覚で数学の問題を解いていく。
虚数の情緒』や『オイラーの贈物』といった読み物の楽しみにも事欠かない。

業務力向上には直接的にはほとんど結びつかないとは思うのだが、業務に関することは業務中に覚えてしまえばいいし、長期的に見れば数学の応用が必要になる場面が来て、やがて実を結ぶかもしれない。

そんなわけで、まずは高校数学の勉強を進めており、長岡の教科書数学I・Aを終えた。
教科書を読んだだけでは身についた気がしないので、問題集をやろうと数学I・A 入門問題精講を始めた。 定番のチャート式はボリュームが大きすぎる感があるのでこちらを選んだ。 著者のツイートで社会人にも勧められていたのがけっこう決め手になった。「はじめに」の中で、公式や定理を丸暗記するのではなく、その過程で身につける「考え方」が大事であり、魚を与えるのではなく、釣りの仕方を教えるという話をしているのも良い。
これと並行して基礎問題精講もやっていく予定。

今は妻子が起きる前の朝6時に起きて、1時間を勉強に充てている。
これから続く数学の旅でどこまで行けてどんな景色が見れるのか、楽しみだ。

お子がもうすぐ生まれる予定なのでルーチンを見直した

あと数ヶ月で初めての子どもが生まれる予定だ。自分の過去を振り返ると奇跡に近いことだなぁと思う。ここまで繋いでくれた色んな人に感謝。

さて、そうなると使える時間がかなり変わってくるだろうから、それに備えてルーチンを見直した。

まず、体力と精神面での健康が大事になってくるだろうから、運動をしっかりやっていく。
朝の出勤前の30分程度の散歩は継続できているので、あとはそれにプラスしてSwitchでのエクササイズをやる。
リングフィット アドベンチャーとFit Boxing 2の両方をやってみたけど、短時間で済むし、クリアという目標があるリングフィット アドベンチャーを中心にひとまずやっていこうと思う。

夜に風呂をわかすタイミングをキューにしてやろうとしていたのだけど、夕食を食べた後は1日の疲れでどうしてもダラダラしてしまい、気力がわかず習慣化できなかったので、朝やることにする。
ただ、朝は出勤前の勉強時間に充てているのでどうしようかと考えていたところ、妻に日ごとに勉強と運動を交互にすればいいんじゃないとアドバイスをいただけた。

というわけで、朝のルーチンとして、月・水・金は勉強、火・木は運動って感じにしようと思う。土日は朝たっぷり時間があるので、両方やる感じ。

勉強の内訳としては、平日は数学、土日は技術という感じ。数学は1年ぐらいで高校3年の範囲を終わらせようかとも思っていたけど、焦らずのんびりやっていこうと思う。

こんな感じで設定してみたが、思った通りにいかないことが多くなるとは思う。
そんな時でも、1度きりの生活をどうせなら楽しんで過ごしていきたい。

『Clean Coder』を読んだ ― ボブおじさんに学ぶプロの職業倫理

ソフトウェア・エキスパートであるRobert C. Martinことボブおじさんによる『Clean Coder』を読みました。

この本の原著がリリースされたのは2011年と結構前なのですが、具体的なプログラミング手法などではなく、プログラマーの働き方について書かれた本なので、今でも十分に読む価値はあると思いました。

序章で以下のように書いてある通り、本書は各章でボブおじさんの失敗談が書かれたあと、それを受けてプロはどうあるべきかが書かれているという構成をとっています。

本書は、私の間違いの一覧であり、これまでの悪事の記録であり、私と同じ道を歩まないための指針であると考えていただきたい

プロ意識とは自分で責任を取ることに他ならず、コミットメントを安易にしないことや、言う必要がある場面ではノーと言うことなどの重要性が説かれています。

特に印象的だったのがプロの労働倫理として、雇用主のために働く週40時間とは別に、自分のキャリアを強化する週20時間を作ろうと書いてあることです。会社で働く時間とは別に学習する時間をそれだけ用意するということです。
これは賛否両論ある意見だと思いますが、本当のプロになるにはそれだけの覚悟が必要なのだということなのだと思います。
ここのところ向上心がそれほど持てず、ぬるま湯に浸かりつつあった自分にはハッとさせられる考え方でした。

他にも目次にある通り、コーディング、テスト駆動開発、練習といったコーディングについての話や、受け入れテスト、テスト戦略といったテストについての話、時間管理、見積もり、プレッシャー、協力、指導・徒弟制度・職人気質といった仕事全般の話について広範囲に書かれています。特にPERTといった見積もりについての話は失敗しがちなので参考になりました。

ボブおじさんの半世紀近い経験を元にしたプログラマーとして働くことのエッセンスが込められた本でした。
僕も一人のプロであるということを忘れず、日々の行動を見直していこうと思いました。

2022-02 振り返り

2022年2月の振り返り。まだフォーマットが定まってないので適当に。

技術

Go 周り

  • Effective Go
  • Go Code Review Comments
  • Go Test Comments
  • Practical Go: Real world advice for writing maintainable Go programs
  • エキスパートたちのGo言語

この辺りを読んだ。

Go はシンプルな言語とはいえ、やはり良いコードを書くには色々と覚えることがあるなと思った。
Effective Go みたいに公式のプラクティス集がまとまっているのは有難い。

機械学習

  • Kaggle Learn - Intro to Machine Learning
  • Kaggle Learn - Intermediate Machine Learning
  • Coursera - Machine Learning

Kaggle の 30 Days of ML というチュートリアル集をやって、Coursera の Andrew Ng 先生の Machine Learning を少し進めたが、機械学習に行くまでに最低限の数学をちゃんとやっておきたいなとなってストップした。

しばらくは機械学習には触れずに数学をやっていこうと思う。

数学

  • 長岡先生の授業が聞ける高校数学の教科書
  • Khan Academy

高校数学レベルの数学を学ぶにはどれが良いのかなぁと色々探った結果 Khan Academy をやっていたのだけど、同じことを違う動画で何度も説明したり、途中の計算が丁寧すぎたりとちょっと退屈だったので、 reddit などで評判の良かった Serge Lang の Basic Mathematics という本で学んでいくことにした。

評判がすこぶる良い MIT OpenCourseWare のLinear Algebra を受講することが目標。

プリンシプル オブ プログラミング

t-wada さんも良書と言っているので気になっていたこの本をようやく読み始めた。

各原則が短くまとまっていてとても良い本。出典なども書いてあるので広がりもありそう。

少しずつ読み進めていこうと思う。

WEB+DB PRESS Vol.127

リファクタリング特集は面白かった。凝集度と結合度、いつも理解が曖昧なのだけど、結構シンプルに考えることができるのだなと分かった。

趣味・娯楽

ゲーム

ゼルダの伝説 ブレス オブ ザ ワイルドを進めている。自由度が高すぎてどこに行けばいいか難しい。そして死にまくり。オールタイムベスト的なゲームなので、じっくり大事に攻略サイトを封印して進めようかと思ったけど、レシピとか分からんやろって感じなので解禁して進めている。

映画

ゲーム・ナイト、フリー・ガイ、地球外少年少女を観た。

結婚生活を描いた映画で検索して見つけたゲーム・ナイトがなかなか面白かった。レイチェル・マクアダムスやっぱ良いなと思った。

楽器

Beginner to Badass を進めていたが、スラップのところでうまくいかずに停滞してしまった。

発表の機会もなく、一人で黙々とだとモチベーションがなかなか続かないので、コロナの状況下が明けてバンド活動とかがしやすくなった時に楽器はやるかなーと思い始めているところ。

まとめ

Go 周りを学びつつ、機械学習のための数学を何で勉強していくか定まってきた感じ。

プライベートの勉強は数学をメインにして、その傍らで技術書を少しずつ読み進めていくスタイルで進めていこうと思う。

私生活も色々と忙しくなってくるので、楽器はいったん置いておくなど、やることは絞っていく方向にしていく。

2022-01 振り返り

振り返りは大切ということで、今月から月単位での振り返りをやってみる。日記を書くのは続けるのが難しそうだが、月ペースなら楽そうってのがある。
学生時代はブログで勉強の振り返りをやっていたのだが、これからは勉強以外も含めた総合的な振り返りをやっていこうと思う。

というわけで振り返る。

読んだ本

The Go Programming Language

去年6月に読み始めて、"8. Goroutines and Channels" まで読んでいたのだが、長いこと積まれていて気持ち悪かったので、エイヤとそこから最後まで読み通した。

この本はCSチックで骨太な本で、全部理解しようとするとかなり腰を据えて取り組む必要があるので、8章からは、後で「あそこに書いてあったな」ぐらいのインデックスを貼る意味でほとんど見出しだけ追うみたいな読み方をした。 こういう読み方はあまりしてこなかったのだが、じっくり読んでも結局内容を忘れることが多いので、このような必要ドリブンな読み方もしていきたいと思う。

インターフェイスについての詳細など、Goを真に理解する上で大事なことが書かれている本ではありそうなので、腕を上げた後でまた読み返したいと思う。

長岡先生の授業が聞ける高校数学の教科書

今年は数学をやっていくぞということで開始。数学1 第1章 数と式を終えたところまで40ページ進めた。

このペースだと数学Cまで全て終えるまでに2年ぐらいかかってしまうので、もっとペースを上げていこうと思う。
この教材は音声講義が入っている本で、とても興味深い話が聞けるのだが、全部聴いていると時間がかかるし、既に一度4年ほど前に数Cの途中まで進めてはいるので、音声講義は本を読んだだけで理解できなかったところだけ聴くようにする。

早く高校数学を終わらせて最終目標の機械学習に進みたいと思っている。が、積み上げる学問なので、慌てずじっくり理解していく。

趣味・娯楽

映画

レディ・バード』、『サイダーのように言葉が湧き上がる』、『浅草キッド』、『朝が来る』を観た。

レディ・バード』は難しい時期の女子高生の成長物語。前々から観たかったのだけど、母との絆などとても良かった。女性視点だとまた違って見えるのだろうなぁ。

浅草キッド』も人情溢れる良い映画だった。あまり昔は良かったというのは好きではないのだけど、その時代を一生懸命に生きた人たちがいたのだなぁと心揺さぶられた。

ベース

楽器をやるとなったら毎日練習したりしていたのだが、色々やることがある中でなかなか厳しいので、楽器は緩く週末だけやる感じにすることにした。

BassBuzzというサイトのBeginner to Badassを進めている。
これも1回途中まで進めていて、以前はModule 10まで終えていたので、ざっと復習をしていてModule 07まで終えたところ。
まずはこのコースをしっかり終えて、色々曲を覚えていきたい。

ゲーム

Oculus Quest 2でHalf-Life: Alyxを遊んでいる。弾が少ないゲームで操作も慣れないのでなかなか難しい。これを遊ぶと他のVRゲームが遊べなくなるとさえ言われるゲームなので、じっくり楽しんでクリアしたい。

まとめと今後

結婚したり、年初だったりと、気づいたら終わっていたという感じの月だった。

2月はもっと落ち着くと思うので、数学にどっぷり取り組んでいきたい。
引き続きGoのスキルも上げたいので『Effective Go』、『Go Code Review Comments』、『エキスパートたちのGo言語』、『Go言語による並行処理』と読んでいく。
同僚に刺激を受けてKaggleを始めたのでそちらも進めていく。

やってくぞー。