開発の品質を上げた7つの方法 - ソース管理、コード管理、テスト導入、開発環境の4つの視点から

ソフトウェア開発における、開発管理の手法やツールには、「品質」を向上させるという目的が存在しますが、開発者はまず、手法やツールの先にある「品質」とは何かを理解する必要があります。ソース管理、コード品質管理、テスト導入、開発環境の4つの視点から、「品質管理」の現場で直面した実例と課題とその解決策について小林昌弘さんが解説します。

開発の品質を上げた7つの方法 - ソース管理、コード管理、テスト導入、開発環境の4つの視点から

はじめまして、株式会社エンバインド代表の小林です。私はこれまでいくつかのITベンチャーに所属しつつ、そこで技術的な方針を決める役割を数多くこなしてきました。その中には、新しいスタッフと共に新規のサービスを立ち上げる場合や、既存のプロジェクトがうまく進まない場合に参加し、問題解決方法などについていろいろと実施や提案をしてきました。

また、社内のプロジェクトだけではなく、問題に直面した外部プロジェクトに途中から参加し、問題の原因を探し、ゴールに導く「クローザー」のような役割を担うことも多くあります。

その中で、多くの方が開発管理を難しく考え過ぎているという印象を抱くようになりました。

そこで今回は、私が開発現場で経験した、あるいは見てきた失敗において、どのような課題を見つけて解決案を考えてきたかについて紹介します。同じような課題を感じている方々に、それらの事例を参考にしていただければと思います。

多くの開発現場で感じた課題

筆者は2000年くらいまで、汎用機を使い、COBOLで金融システムの開発をしていました。2000年というと少々古い印象を持つかもしれませんが、COBOLのOS、メモリ、CPUなどは仮想化されています。また、障害の時には緊急リリースの手順やテストの方法なども手法として定まっていました。

2000年以降はインターネット上でサービスを提供するITベンチャーに転職しましたが、そこで体験した開発管理手法は、むしろ金融システム開発時より後退している印象があったのです。また、開発管理の重要性をきちんと認識していない開発者が多いことにも驚かされました。例えば、プロジェクトリリースの直前にハードディスク障害などでコードが消えてしまったというようなアクシデントがあってから、はじめてソースの中央管理の必要性が理解されるといった雰囲気です。

こうした過去の経験と比べてみると、現在のWebシステムの開発現場では、多くの開発者がソース管理を当たり前のように導入し、若いITエンジニアでもいろいろな管理方法に興味を持ち、そしてさまざまなツールを駆使していることに感心します。

しかし一方で、多くの開発現場で管理手法やツールの「べき論」が過剰に議論され、開発自体の楽しさを減衰させてしまっているようにも感じるのです。多過ぎる開発ルールやツール運用などが負荷になり、プログラミング自体が苦痛に感じる、というケースは往々にしてあるでしょう。また、管理ツール導入を推進する側からは、いざ導入してはみたものの、あまりうまく運用されておらず、どうしたらいいのか分からないという話を聞くこともありました。

手法やツールは手段であり「目的」ではない。目指すべき「品質」を具体的に考えよう

管理手法やツールには、「品質」を向上させるという目的があります。では、ここで取り沙汰される「品質」とは? 私たち開発者は、手法、ツールの先にある目的、つまり「品質」とは何かを知る必要があります。そして、目的を達成するための手法こそが「品質管理」なのです

本稿では、「品質管理」を教科書的に学ぶのではなく、私が過去に経験した、品質管理における課題とその解決を、ケーススタディとして解説します。それゆえ、言葉の定義が多少、ISO(国際標準化機構、International Organization for Standardization)やITILITIL(Information Technology Infrastructure Library)といった中で定義されているものと異なる場合もあるかと思います。ご了承ください。

[Note] ISOとITILについて

・ISO - 国際標準規格を定めたもの。品質管理に関してはISO9000sがある。
・ITIL - ITサービスを運用する上でのベストプラクティスをまとめたもの。

個人的には、ISOはあくまで「規格」であり、定義やルールという位置付けを強く感じます。一方、ITILはサービスを運用する上での考え方や必要な事項などが多数示されています。私は、実際の開発現場で試行錯誤した末にITILについて知ったのですが、Webシステムの品質を学ぶ上でより身近な教科書として活用し得るテキストだと感じます。

「品質」と「品質管理」

まず、「品質」とはそもそも何を示しているのでしょうか。私がソフトウェア開発プロジェクトにおける品質について考える際は、以下を項目として挙げます。

  • (1) 要求した機能を満たしているか
  • (2) 予定したスケジュールに収まるか
  • (3) 予定した人数で収まるか
  • (4) 安全性(セキュリティやスケーラビリティ)は満たしているか
  • (5) 継続性(継続して機能開発ができる、使い続けられる)は満たしているか

「品質」の定義として(1)~(4)については多くの方に同意してもらえると思います。一方で、生み出された品質を“維持する”という指針には違和感を覚える方がいるかもしれません。

ここで「品質管理」について考えてみます。品質管理は、実は「品質」を上げるための手法というよりは、結果を「安定」させる方法です。そして、(5)の継続性が寄与するのが「安定」であり、だからこそ重要なのです

品質の安定性

「品質の安定」とひとことで言っても分かりにくいので、例えば、入試や資格試験などにおける合格点と平均点を例に、図1で考えてみます。

1▲図1: 品質と安定

例えば、同じ平均点でも、左図のように合格点以上の点数と落第点の点数を交互に取ってしまう場合と、右図のように常に合格点以上の点数を取れる場合があります。当然ながら、結果である合格率は、左図が50%、右図が100%と大きな差が生じます。

品質管理の大きな目的の一つは、常に合格点を超える平均点を取れるようにすることです。ここで特に注意すべきなのは、安定すると同時に最高得点数も下がってしまう場合があることです。再び、以下に図を示します。

2▲図2: 品質管理がうまくいかない場合の例

上記図2のような場合には「品質管理」を高度に行い、結果をあえて安定させない方が良いこともあります。例えば、左図では平均点が合格点を下回っていて、結果が安定していなくとも、50%の確率で合格しています。しかし、右図では結果は安定していますが、常に不合格になってしまっています。

工業製品のように同じものを大量に作る場合を想像してみてください。製造工程でいくつかの不良品が混じった状態(結果に幅がある状態)であっても、ビジネスは遂行可能でしょう。しかし、品質は安定していても全てが不良品、という状態ではビジネスは成立しません。こう考えると、手法やツールを駆使して品質管理を行うことが、必ずしも最良の結果に結びつくわけではないとイメージしやすいと思います。

しかし、具体的な点数や価値を定量化しにくく、まったく同じ要件は二度とないようなWeb開発のプロジェクトでは、どこまでを管理し、どこから管理しないかなどの判断は非常に難しいものです。だからこそ、管理の手法やツールに注目が集まり、運用に多大なコストが投じられることになります。コストを投じるからには、運用を工夫し、チームに便利さを提供せねばなりません。

ここからは、実際に私が管理手法やツールを導入・経験した際に生じた問題や、その解決のためにどうしたかなどを紹介していきます。

ソース管理での作業領域の明確化とコミュニケーション

Git機能ブランチを使った開発では作業途中でもマスターブランチにマージ

図3のように、開発者がGitで機能ごとにブランチを作り、開発を進めます。

3▲図3: Git機能ブランチを使った開発フロー

プロジェクトの初期段階に、以下のような問題が発生しました。

  • (1) 頻繁にコンフリクトが発生する。
  • (2) 各修正ブランチでは正常に動作するが、マージしてみるとうまく動かない。
  • (3) 似たような機能を複数の人が作っている。
  • (4) これらの結果、開発スケジュールが遅れる。
解決案

ここでの問題の原因として考えられるのは、各開発者が分担する領域が明確に決まっていないことです。しかし、開発初期には仕様が明確に洗い出されていない、また、共通する機能が多い、といった状況が多々あり、作業領域を明確にすることができません。そこで、以下のような運用ルールに変更しました。

  • (1) 機能ブランチを使わなくてもOKとする。
  • (2) 機能ブランチを使う場合、1日の開発終了時には開発途中であってもマスターブランチにマージする。
結果

新ルールを運用し始めた際には大きなストレスがあったことは事実です。頻繁にコンフリクトが発生する状況もすぐには改善しません。しかし、他の開発者の変更が作業途中であっても毎日取り込まれることで、以前よりはコードに与える影響が小さくなり、その分コンフリクトも小さくなったのです。

小さいコンフリクトの存在から、他の開発者が何をやっているのかに対し積極的に興味を持つ必要が出てきます。それぞれの作業内容がそれぞれに理解されることで、共通部分では役割が自然と決まり、同じような機能を作ることもなくなります。新たな運用ルールでしばらく開発が進むとコンフリクトも生じなくなり、機能ブランチを使っての開発を再開しても同様の問題は生じなくなったのです。

Gitマージリクエストと承認フローの見直し

Gitではまた他の問題にも直面しました。以下図4のように開発者が修正後、マージリクエストを行い、その内容に問題がないことを確認した管理者が承認してマージします。GitHubのようなツールを使って管理する場合によく利用される管理手法だと思います。

4▲図4: Gitマージリクエストと承認フロー

各機能を共通の開発環境に適用させつつ動作検証をするフェーズで、以下の問題が発生しました。

  • (1) 修正した内容が本当に正しいのか、管理者がコードを見ただけでは判断がつかない。
  • (2) 管理者がコードをマージせず、マージリクエストがたまってしまい開発が遅れてしまった。
  • (3) マージ後に問題が発生すると、その問題の原因把握と解決に非常に時間がかかってしまっていた。
解決案

開発が進み機能が複雑になってくると、ある修正の中に、要件上必要な修正と、データベースやネットワークなどの技術的制約の解決のために必要な修正が混在するようになってきます。

こうした状況では、要件上必要な機能について把握する立場の管理者では、是非を判断できない修正も増えてしまいます。そこで、以下のような運用ルールに変更しました。

  • (1) マージリクエストと承認フローをやめ、修正した開発者自身がマージする。
  • (2) マスターブランチで動作する確認環境を用意する。
  • (3) 開発者、管理者は(2)の環境を使い、動作が問題ないか確認する。
  • (4) 全体的な動作確認をマイルストーンごとにチェックし、問題は別途不具合として管理する。
結果

このプロジェクトは、開発フェーズ、テストフェーズのようにマイルストーンが分かれていたため、マージリクエストごとに動作が正しいのかを検証しなくても、プロジェクト管理上は問題ないと判断し、修正箇所は開発者自らマージをするように変更したのです。不備が生じないための最低限の動作確認は開発者が担い、機能面での確認は管理者が実際に環境を見てチェックしていく方法です。開発者と管理者が共通の環境をもとに会話できるようになったために、コミュニケーション面での誤解が少なくなり、マージ後の問題切り分けもしやすくなります。

一方で、コミュニケーションが多くなったことにより、改善や実装上の小さな不備などが頻繁にタスクとして積まれてしまう問題も生じました。それらの問題は、不具合タスクとして管理し、別途スケジューリングするという対処を行っています。

コードの品質管理で直面する問題と解決策

コーディング規約の運用で共通理解を深める

プロジェクトに参加する開発者が多くなってくると、チーム内でのコードの記述から統一感が失われ、コードが分かりにくくなってきた、と問題提起がされました。そこで問題提起した開発者を中心に別途チームを作り、コーディング規約を作成することにしました。

しかし、こうしたアプローチは次のような別の問題を生みました。コーディング規約を運用し始めてすぐに、それらのコーディング規約に対する不満や反対意見などが出てしまったのです。

  • (1) クラス名や変数名についてコーディング規約だけではよく分からない。
  • (2) インデントやスコープなどのコーディング規約があまり守られない。
  • (3) コーディング規約を守るための時間が必要なので、スケジュールを増やしてほしい。
解決案

それまで使ってきた言語も所属していた業界も異なる開発者同士では、「全員にとって分かりやすいこと」の尺度が合いません。これが原因となり、コーディング規約が機能しにくくなっていたのです。また、広い範囲をカバーするために多くのルールを作ってしまったことで、むしろ心理面での障壁ができてしまいました。

そこで、コーディング規約の目的を「より良いコードを目指すため」ではなく、「最低減、守るべきこと」に変え、以下のような運用方針へと変更しました。

  • (1) クラス名の命名ルールではなく、システムの「用語集」を作り、その用語集にないものは自由とする。
  • (2) コーディングスタイルの統一は、自動でできる範囲とし、IDE向けの設定を共有する。
結果

変更前、命名ルールがどの程度守られるか、という悩みもありました。例えば、「クラス名」のルールで、複数データを扱う場合には英語の複数形を使うというルールや、名称の後に「List」や「Map」をつけるなどのルールは、多くの方になじみがあるでしょう。

しかし、複数形というルールであれば、複数形の集合はどういうルールにするのかという疑問が生じます。また、「List」をつけるよりも、重複データを含まない場合には「Set」の方が適切ではないかという意見もあるでしょう。

これらはもっともだと感じる一方で、全てを網羅してルール化することはできず、また、意見の提起を禁止することも建設的ではないと感じます。だからこそ、クラス名は命名ルールで制限するのではなく、「用語集」の形にして、仕様の一部としたのです。

例えば、以下の表のようなものです。

名称 システム名 説明
アカウント Account ログイン時に利用するID/パスワードを管理する単位
アカウントグループ AccountGroup 同じ顧客内のアカウント。同じデータ参照権があるアカウント群。

このようにすれば、AccountListやAccountsなどのクラス名が使われることはなくなります。また、用語集を作ったことで、開発上のコミュニケーション時に共通理解が生まれ分かりやすくなる、という一石二鳥の結果となりました。

次に、(2)のコーディングスタイルは、IDEでのコーディングスタイルの設定でエクスポートしたものを共有し、その設定で対応できる範囲のみとしました。IDEなどが共通でない場合には、EditorConfigなどのツールを使用してもいいでしょう。とにかく、各開発者の心理的障壁を下げることを優先し、「ルールを守る」ではなく、「守れるルールのみにする」という方針に変更したのです。

なお、用語集は、他のプロジェクトでも再利用され、仕様書や設計書などでも同じ用語が使われるようになっていき、結果としてコードの再利用にもつながるという副産物も生み出されています。

コードレビューでは図を書くことで理解度を把握する

コーディング規約だけではカバーできない部分や、新しく参加する開発者のコードを既存のシステムに取り込む前に、当該プロジェクトでの経験がより豊富な開発者がコードレビューをしようということになりました。

しかし、いざコードレビューを始めてみると、以下のような問題が生じました。

  • (1) レビュー時には分かりやすいコードだと思ったが、後から見返すと何をしているのか分かりにくい。
  • (2) レビューをしているのに、コードを書いた人のみが修正しなければならない、もしくは修正するのが当たり前のようになってしまっている。
  • (3) 最初のレビュー時にはきれいなコードだったのに、修正のたびに汚いコードになってしまい困っている。
解決案

コードレビューに期待した効果には、以下が挙げられます。

  • 分かりやすいコードを記述しているか
  • 間違いやすいコードを記述していないか
  • 開発チームの中での仕様と実装の共有

コードレビューの導入当初は期待した効果が得られませんでした。まず「分かりやすいコード」とは、コードレビューを実施する人、実施するフェーズによって判断基準が異なる、という課題が浮き彫りになりました。例えば、新規のコードでは、処理が分かりやすい「方法」にレビューの重点が置かれています。しかし、プロダクトの運用開始後の修正では、処理の「目的」が分かりやすいかが重視されます。

「レビューで重視すべき点」が安定を欠いたことで、レビューで一度「良い」とされていたコードが、その後「悪い」と判断されてしまうケースが続いたのです。また、こうした問題が影響し、新しく参加してきた開発者にとってコードレビューは好意的に受け止められず、まるで検閲のように捉えられてしまいます。

このようなコードレビューの不全を改善すべく「評価方法の平準化」「コードを書いた開発者が自分のコードの意味を理解しているか、の把握」という、2つの方針を定めたのです。両方針は、以下の2ルールとして具体化されます。

  • (1) コードを書いた人に1枚の図を書いて説明してもらい、説明できれば問題なしとする。
  • (2) 設計スタイルの良し悪し、特に各エンジニア間の好みでは判断しない。
結果

(1)は、記述した自身のコードの評価方法に一貫性を持たせるためのルールです。コードの「良い」「悪い」の判断には、各開発者の価値観やその時々の関心事が影響しがちです。こうした変動要素を排除するための手法が、「図を書いて説明する」なのです。ここで、大事なのは図を本人が説明できることであり、図自体の良し悪しはもちろん不問です。そして、図の説明通りにコードが記述されていること自体を重視するために、実際のコードの記述方法や設計スタイルへ話がそれないように、(2)のルールを設けます。

間違いやすいコードが生まれる要因として、コードを記述した人自身が、自分のコードをあまり理解できていない、という点が挙げられます。しかし、コードが果たす役割を図にすることで、理解の境界が明確になり、同時にデータがどのようなインターフェースを持つべきかが明確になります。特にAPI設計においては後者の意味合いは大きく、インターフェースがきちんと理解できていれば、仕様もある程度は把握可能です。説明しやすい図が描ければ、同時にコードも分かりやすく、仕様の共有もしやすくなるのです。

また、一見きれいで分かりやすいコードであっても、図で説明できない、図が分かりにくい場合があります。こうした場合は、コードを記述する人がまだ十分に仕様を整理できていない、といった状況を客観的に把握するための材料としても活用できるのです。

仕様整理が不十分な箇所に修正が入ると、コードはどんどん汚くなっていってしまう傾向があります。図によって各開発者の仕様理解を促進することで、その後のコードがきれいになる、という効果も期待できます。

テストのセオリーと目的を見定める

エンジニアHubに会員登録すると
続きをお読みいただけます(無料)。
登録のメリット
  • すべての過去記事を読める
  • 過去のウェビナー動画を
    視聴できる
  • 企業やエージェントから
    スカウトが届く