フューチャー技術ブログ

チームの開発生産性を高めるための心がけ

はじめに

Technology Innovation Group 辻です。
秋のブログ週間の 4 本目です。

最近はアーキテクトとしてチームにジョインすることも増えてきました。より素早く、継続的にビジネス上の価値を提供するためにチームの開発生産性は重要です。チームの生産性を高めるために私が心がけているいくつかの内容を紹介します。

心がけ

  1. 開発上のボトルネックを取り除く
  2. コードべースの品質を保つ
  3. コードを読みやすくする
  4. 素早くレビューに取り組む、質問/相談にレスポンスする
  5. 体裁の一貫性を保つ

1.開発上のボトルネックを取り除く

開発上のボトルネックになっているポイントを発見し、原因を特定し、対応する、ということです。一例をあげると以下のようなことです。

  • コードの責務がはっきりしておらず、改修時の影響が大きくなる。意図しない挙動になる
  • そもそもテストコードがなく、機能仕様が満たされているのかわからない
  • 改修しようと思ったが、そもそもコードベースのテストが失敗していた
  • SDK が素朴な API のみで構成されており、コードの記述量が増える、全体の見通しがわかりにくい
  • CI 環境でのテスト実行に時間がかかり、素早いフィードバックが得られない
  • 必要なテストコードが膨大になり、テストの実装に時間がかかる、またテストコードのメンテナンスが難しい
  • デプロイが属人的で、デプロイ職人しかデプロイできない、デプロイには秘伝のコマンドが必要になる

ボトルネックになるポイントは開発の規模/仕様/特性あるいは開発体制によっても変わります。アーキテクトとして実際の開発に向き合い、まだコードも書くからこそ、開発上のボトルネックポイントがわかり、またどうすればいいのかいくつかの手段のなかから最適な選択ができます。

2.コードべースの品質を保つ

品質を保つことは開発生産性に大きく影響があります。え、品質? 生産性は関係ないのでは? と思う方もいるかもしれません。しかし、そうではありません。品質が悪いと手戻りが発生し、結果的に生産性に跳ね返ります1。品質を保つからこそ高い生産性が得られます。品質と生産性の議論は t_wada さんの『質とスピード』などの資料を参照してください。

コードベースの品質を保つために実践しているいくつかのプラクティスを紹介します。

ユニットテストを充実させる

  • データパターンを網羅する

機能要件を満たすユニットテストを書きます。具体的にはインプットデータを入力したときに、想定しているアウトプットデータが出力されていることを確認します。業務上想定している入力パターンと出力パターンの網羅性が重要です。テストケースレビュー時は特にこのデータパターンの網羅性を意識して、業務観点から抜けているケースがないか気にしながらレビューしています。

なおコードカバレッジはテスト品質の指標の 1 つとしてよく挙げられますが、私は品質の絶対的な指標とはせずに、参考値として捉えています。もちろんデータパターンを網羅したテストを実装した結果、コードカバレッジが低ければなにか問題があるかもしれません。

  • なるべくモックを使わず、本番環境に近い状態でテストする

サーバアプリケーションの機能であれば、データベースへの IO を伴うことが多いでしょう。ユニットテストでも、モックを使わずになるべく実環境に近い状況でテストできるように整えています。たとえばデータベースであれば、ローカル環境にコンテナとして立ち上げて、そのデータベースに本番環境と同等の DDL を適用し、その環境をユニットテストに使用します。もちろんアプリケーションから外部の API にリクエストする場合はローカル環境に同等の環境を用意するのは難しいため、この場合はモックしてユニットテストすることは妥当です。Cypress などを使ったフロントエンドの E2E テストをローカルで実施するときに、バックエンド API に本物の実装を使うことはテストのコストが高くなるため、モックすることもあるでしょう。

自動テストを行う

  • 意図しない振る舞いをより早く捉える

ユニットテストを充実させたうえで、それを継続的にテストします。あるタイミングでは PASS していた実装もバグ修正や機能追加、リファクタリングなどにより変化するものです。コードの変更だけでなく、ランタイムのバージョンをアップデートするなどのインフラ関連の変更もあるでしょう。こうしたコードやインフラの変更による影響が意図しているものだけであるか、意図せず挙動が変わっていることがないか、PR をマージする前に自動テストして確認します。そして自動テストを PASS した PR だけをマージします。自動テストが失敗していれば、その内容を実装者に確認します。

万が一 master ブランチを使った自動テストが失敗していた場合は slack などに通知を飛ばすようにしています。迅速に状況を確認し、影響度に応じて対応します。

  • テストを十分早く動作させる

最初のボトルネックのところにも少し書きましたが、テストコードが増えるにつれ、テストの所要時間が増えることがよくあります。自動テストは必要ですが、そのテストを十分早い時間で動作させることも必要です。高速化するための方針としては、テスト範囲を狭める、テストを分割して並列に実行できるようにする、などがあります。今、私が所属しているチームでは後者の方針で CI 環境上での自動テストを高速化しています。具体的には CI 環境に CircleCI を使っており、テスト分割と並列実行にある circleci tests split などを組み合わせてテストを分割し、分割したテストを異なるコンテナ上で並列に実行しています。

3.コードを読みやすくする

読みやすいコードはコードが修正しやすく、また修正に伴う影響範囲も把握しやすいです。本番環境で運用されるソフトウェアのコードであれば、一度書いたらそれで終わりとはならず、ビジネスの進化、外部環境の変化、ソフトウェアの不具合などにより、将来の自分あるいは他の誰かに読まれます。コードが継続的に読まれる以上、その可読性は開発生産性に大きく影響します。

とはいえコードの可読性はこれだけで本一冊かけるテーマですので、詳細は『リーダブルコード』などの書籍や、ソースコードを綺麗にするためにまず心がけたい3点 の記事に譲ります。

私がレビューで特に気をつけて確認しているポイントは以下です。

  • 意図した命名になっているか、不必要に抽象的な命名になっていないか?
  • コードの責務は妥当か?
  • シンプルに実現しているか、早すぎる最適化をしていないか?
  • コードベースの構造と照らし合わせて、追加/修正するコードやモジュールの粒度感/構造は妥当か?

4.素早くレビューに取り組む、質問/相談にレスポンスする

この項目はコミュニケーションに関する心がけです。

レビューを受けたときは素早く取り組むようにしています。コードレビューに関する Google のプラクティス3にも「あるタスクに集中的に取り組んでいる最中でなければ、コードレビューの依頼が来たらすぐに着手してください」と書いてありました。レビューした側は作業がブロッキングされることが多く、進捗を出しにくいからです。シニアなメンバーであればうまくコンテキストスイッチできるケースも多いですが、ジュニアなメンバーだとタスクをシングルで進めることも多く、レビュー待ちによるブロッキングの影響はより大きいと感じています。

レビューだけでなく普段のコミュニケーションでも同様です。最近はリモートで非同期コミュニケーションを取りながら開発することが増えており、より意識しています。たとえば「ここの仕様がわからず、ちょっと XXX について教えてください」「実装方針を相談したいのですが、…」みたいな質問/相談があります。質問/相談した側としてはその内容を解消しないと次の進捗が出しにくいケースがあり、このようなテキストコミュニケーションも気づいたタイミングで素早くレスポンスするようにしています。
レスポンスするのが重要です。すぐに回答できなければ「ちょっと今回答できないので 1 時間後に回答します」とか、自分ではわからなければ「私はわからないです、ZZZ さんわかりますか?」みたいなレスポンスも有効です。何かしらのレスポンスがあるだけでも受け手の印象は変わります。

5.体裁の一貫性を保つ

最後はやや具体的な心がけですが、地味に効果的です。

コードレビューをしていると、コードのフォーマットやファイル終端の改行有無、文字コードなどの体裁が開発者の中で一貫しておらず、PR にコメントすることがあります。しかし、本来であれば、このような体裁に関するコメントは不要です。コードのロジックそのもののレビューに集中できることが望ましいです。コードベース全体や開発者の間で、体裁に一貫性があることが重要です。チーム内で方針を合意して、設定としてコードベースに反映するのが良いでしょう。これにより自転車置場の議論4を避けられます。

ファイルの改行コード、インデントなどの設定は EditorConfig を使うことが多いです。VSCode2や IntelliJ IDEA など多くのエディタがサポートしています。EditorConfig の設定ファイル例は以下のとおりです。

.editorconfig
root = true

indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.json]
indent_style = space
indent_size = 2

コードフォーマットはチームで会話して決めた方針を Makefile などに記述して make fmt などでフォーマットすることが多いです。たとえば SQL のフォーマットに future-architect/uroboroSQL-formatter を使うと決めたのであれば、以下のように fmt のタスクとしてフォーマットのコマンドを記載するイメージです。

fmt:
@usqlfmt -m directory files

まとめ

チームの開発生産性を高めるいくつかの私の心がけを紹介しました。抽象度の高いものからすぐに実践できそうな具体的なものまで様々ピックアップしました。普段、技術ブログにはプログラミング、特に Go 言語に関する記事を投稿することが多いですが、秋のブログ週間ということで、私のいくつかの心がけを言語化することにチャレンジしました。

最後まで読んでいただきありがとうございました。

アイキャッチはGerd AltmannによるPixabayからの画像を利用させていただきました。