2022 年振り返り(ソフトウェアエンジニアリング)

あけましておめでとうございます。

オープンソース活動は変わらず元気に続けてます。 子育ての中で時間を見つけるのは大変なので、子どもが生まれた直後からベビーシッターを積極的に利用してます。

2022 年は、専門的なソフトウェアエンジニアリングと生活全般を分けて、振り返りをまとめました。 この記事はソフトウェアエンジニアリングについてです。

登壇

4/23(土)に開催された Go Conference 2022 Spring に登壇しました。

Protocol Buffer 言語をパースする go-protoparser と Protocol Buffer スキーマファイルをチェックする protolint を自作したときの経験はどこかで整理しておきたいと思っていたので良い機会になりました。

Go Conference 2022 Spring で採択されたプロポーザル(CfP) - yoheimuta’s blog にそのときの Cfp(プロポーザル)を公開しているので、発表背景など詳しくはそちらを参照してください。

発表後、下のように書いてくれた方(自分のすぐ後のセッションで GC について発表されていた)がいました。 レキサーとパーサーを分けて実装するという一番伝えたかったポイントに言及されていて良かったです。 自分にとっては当たり前になってましたが、実際に書くときにはその発想にならなかったり、どう書くかわからないものだと思います。

他人がオーナーのプロジェクトへの参加

所属企業で MySQL のシャーディングソリューションに Vitess を採用することにしたので、今年の後半は合間の業務時間も使って Vitess にいくつかコミットしました。 Vitess の CDC キャプチャには Debezium を使うのが一般的なので、そちらにもコミットしました。

debezium/debezium-connector-vitess

Debezium は変更データキャプチャ (Change Data Capture; CDC) のための低遅延データストリーミングプラットフォームを提供するオープンソースプロジェクトです。Debezium は MySQL のシャーディング用プロキシである Vitess にも対応していて、debezium-connector-vitess がその実装にあたります。

github.com

  • debezium-connector-vitess には他のすべての connector(例えば debezium-connector-mysql)でサポートされている、起動時のスナップショット取得機能がサポートされていませんでした。Vitess のバックエンドである MySQL のバイナリログは通常一定期間で削除されるので、バイナリログのストリーミングだけだと完全なデータを再現することができません。例えば、シャーディング後の MySQL クラスタで以前のような複雑な JOIN クエリをサポートするために、Flink などでリアルタイムに Materialized テーブルを作ろうと思ったとき、これだと困ります。
  • この PR がマージされた v2.1 からは、Debezium を起動するとまず MySQL クラスタ(Vitess)の現在のスナップショットを一貫性を保ったまま取得して、それが完了してから更新履歴のストリーミングがはじまるようになります。
  • Slack/Salesforce 社もこの機能を要望していて、設計やレビューを手伝ってくれました。最初に大規模に使いそうなので、問題なく動いて欲しいです 🙏
  • v2.1 は 2022.12.22 にリリースされてました

vitessio/vitess

Vitess は MySQL の水平スケーリングを行うためのデータベースクラスタリングを提供するミドルウェアです。 YouTube が開発して後に OSS 化されました。データベース分野で初の CNCF の Graduated project です。

Slack, Square, GitHub, Shopify, HEY (DHH の) など導入事例は豊富で、これらの会社が積極的にコントリビュートしてます。

github.com

  • Vitess は多くのコンポーネントが協調動作して動くので、開発環境を作ったりそれぞれの挙動を理解するのが最初の関門です。幸い examples ディレクトリがあるので、そこで docker-compose up -d したらまさかの失敗、というわけで修正しました。レビューの過程で開発者から細かいところを指摘してもらえたので、システム理解を深める良い機会になりました。Vitess v15 リリースのコントリビューターにちゃっかり入ってたのは 🉐。

github.com github.com

  • 前述の debezium-connector-vitess にスナップショット機能を追加する上で見つけた課題に対応した PR たちです。ほかにも一つがレビュー中、もう一つが実装待ち(自分の)です。Vitess v15 以下には connector のスナップショット機能を fault tolerant するために必要な機能が欠けてます。fault tolerant とは例えば、失敗したらリトライするなどです。Vitess 公式 slack のスレッドで相談しつつ、issue 化しては PR を投げてます。これ専用のスレッドは、2022.08.22 からはじまり、こんなに長いスレッドはお目にかかれないというほど長大になってます。振り返ると、メンテナーに意図が伝わらなかったり、レスポンスが長い時間返ってこなかったときには焦った記憶があります。
  • Vitess v16 に入る予定なので、そちらがリリースされたら debezium-connector-vitess にリトライ機能を入れたいです。

自分がオーナーのプロジェクトへの参加

細かいのを挙げるときりがないので、印象深いリリースや出来事を五つ挙げます。

yoheimuta/protolint

protolint は Protocol Buffer のスキーマファイルが、Google公式スタイルガイドに関するルールや独自ルールに違反していないかチェックする linter/fixer です。 plugin も書けるので社内独自ルールの違反も見つけることができます。

今年は、長年の悲願だった「必須ルールすべてに fixer を実装する」がようやくできました。 fixer が揃ってからスター数の増加傾向も少し高くなっている気がします。353 ⭐

github.com

  • linter で見つかったルール違反を自動で直してくれます。自分の中では fixer と formatter は別物という認識で、formatter はあるスタイルに沿って全部書き換える一方、fixer は一つ一つの細かいルールごとに修正してくれるものです。その意味で、protobuf の fixer でこれくらい細かいルールに対応しているソフトウェアは OSS にはないと思います。
  • 需要があるのはわかりつつ、linter の中で lexer を再度動かすという設計(これが一番書く量が少なく実装できる)に二の足を踏んでいたのですが、下のようなツイートを燃料に書き上げました。おっしゃるとおり。今はそんなことないので、使ってみてください 🤝

github.com

  • fixer の拡充が終わって数カ月後に受け取った機能リクエスト。fixer で直されると後方互換性が壊れるから、違反した行だけ 「rule 適用を無効にするコメントを挿入する」オプションを用意して欲しいという内容。
  • これは感銘を受けたリクエストで、API 用途で利用されるスキーマファイルの linter/fixer ならではの要望です。ソースコードの変数名のケースを直して互換性が壊れることはあまりないので、普通の fixer はそこまで考慮を求められないと思います。この人たち(当時は Secureworks という会社のアカウントっぽかった)のように多くのリポジトリを抱えているところには大事そうなので対応しました。
  • この対応で、protolint -fix -auto_disable=next . で互換性を保ったままスタイル違反を修正できるようになりました。すでにコメントを使って rule 適用を無効にする機能はあったので、この PR ではそのコメントをルール違反があった行の直前に挿入するだけで楽勝だと思っていたら全然そんなことはなくて、だいぶうんうん唸りながら書くことになりました。まず、すべてのルール修正が後方互換性を壊すわけではなくて、例えば import 文のソートは API 処理時には関係ないのでこれをどう扱うかを決める必要があります。後方互換性を壊すルールだけコメントを挿入してそれ以外は今まで通り直してしまうことにしました。次に、コメントをどこに挿入するかで、シンプルなのは違反がある行の上になるのですが、リクエストをくれた人は inline コメントがお望みでした。inline だとすでにコメントが書いてあったときどうするのかとか、1 行 80 文字を超えたときに別の lint エラーが発生するのをどうするか、複数の rule 違反が同じ行で重なったときにはどうするかなど色々なケースを考える必要が出てきます。あまりオプションを増やしたくもないので、良いバランスを探るのとそれを実装するのが大変でした。

blog.cybozu.io

  • cybozu.com のバックエンドでスキーマファーストな開発手法を導入するにあたって、社内独自ルールを強制するために protolint の plugin 機構を活用している、というアドベントカレンダー記事です。
  • 記事中、感謝されたり褒められていて読んでて気持ちよかったです(耳が痛いところは素通りしているとも言えるかも)。plugin の作り方がすごい丁寧に書いてあるしサンプルリポジトリもあるので、README からリンクを貼らせてもらったほうがいいかも。
  • plugin 機構はどれくらい使われているかわからなかったので、あまり目が行き届いていないかもしれません。ビルトインのルールと同じことができないとかあったら feature request か PR ください 😸

github.com

  • 自分が知らないところで、Homebrew 本体に protolint が年末組み込まれていました。5,463 個(現時点での homebrew-core にある Formula 数)あるソフトウェアの仲間入りです。これで brew install protolint だけでダウンロードできるようになりました 🎉

yoheimuta/action-protolint

reviewdog で protolint を動かす GitHub Action を公開しました。

github.com

reviewdog を使ってみたい、GitHub Action を公開してみたい、というだけをモチベーションに着手しました。 reviewdog は PR review 時に見やすくて便利、GitHub Action は Dockerfile と action.yaml の二つを用意すれば簡単に作れる、という触れ込み通りだけど、その実感を得られたのが学びですね。

投稿した記事

itnext.io

  • MySQL をシャーディングしたときに isolation level がどう変わるのか整理した記事を書きました。MySQL のデフォルトの isolation level は REPETABLE READ ですが、一般にシャーディングするとより isolation が緩い READ COMMITTED になると言われてます。そのような挙動の変化がどうして発生するのか、また具体的なアプリケーションでそれぞれがどう動くのか、自分が Vitess 導入過程で気になった疑問に答えました。整理しながら、分散 MySQL で REPETABLE READ を実現している TiDB はすごいと思う一方、それがすべてのユースケースで求められる要件でもないと再確認できました。

読んで良かった本

www.oreilly.com

  • Apache Flink 入門書です。少し情報は古いですが、公式ドキュメントよりも体系的にまとまっているので、まず全体像を掴むのにとても役に立ちました。子どもとコロナ隔離中に読んでいたので、子どもには「今からリスの図鑑読むね」と言い聞かせてました。
  • この本を読みながら、Flink SQLflink-cdc-connectors を使った MySQL の Materialized Table リアルタイム作成の POC を作りました。Flink SQL は強力で、いつも通りの JOIN 文を書くだけで、裏側で負荷を考慮したストリーミング JOIN を行う JobGraph (Dataflow) が出来てしまいます。flink-cdc-connectors は Debezium を内包しているので、インフラ構築は Flink 導入だけで済みます。処理を再開するときには、MySQL のバイナリログを途中から読むか、スナップショットを取って最初から読み込めばいいので、わざわざ Kafka を立てる必要もありません。