2015年6月2日
ソフトウェア開発で得た教訓22箇条
(2015-04-16)by Henrik Warne
本記事は、原著者の許諾のもとに翻訳・掲載しております。
これは私が長年ソフトウェア開発をする中で役に立つと思った教訓と経験則のリストです。
開発
1. 小規模なものから徐々に拡張していく。 私は日頃、新たなシステムを作るにせよ既存のシステムに機能を追加するにせよ、必要な機能すら殆ど持たないようなとてもシンプルなバージョンを作るところから始めるようにしています。そこから当初予定していた機能まで、段階的にソリューションを拡張していきます。私は初めから細部にわたって計画をできたことはありませんが、代わりに開発を進めていく中で新しく見つけた情報をソリューションに役立たせます。
私はJohn Gallの、この言葉が好きです。 “複雑なシステムというのは、往々にしてシンプルなシステムから発展したものだ。”
2. 同時に複数のものを変えない。 開発中にテストが失敗したとき、あるいは機能がうまく動作しなかったとき、1つだけ変更すれば、問題発見が格段に容易になるでしょう。言い換えるなら、短いイテレーションを行いなさいということです。1つずつ変更を行い、動作を確認し、反復する。これをコミットのレベルまで対応していきます。もし新しい機能を加える前にコードをリファクタリングする必要があるなら、まずリファクタリングをコミットして、それから(新しいコミットで)新たな機能を付け加えましょう。
3. ログを取り、エラーハンドリングを素早くする。 新しいシステムを開発する際、まず初めに私がすることは、ログを取り、エラーハンドリングをすることです。というのも、この2つは開発の初期段階から非常に有効だからです。大規模なコード量のシステムになると、プログラムで何が起こっているか把握する何らかの方法をいくつか用意する必要があります。予期せぬ動作が起こったときや動作しなかったときには、直ちに何が起きたのかを把握できなくてはなりません。エラーハンドリングにも同じことが言えます。エラーと例外はどちらも初期の段階で起こります。そのため、体系的な方法で素早く対処できればできるほど、状況は好ましくなります。
4. 新しく追加した行は少なくとも1回は実行すること。 機能を実装する前に、テストを行う必要があります。テストなしにどうして機能がうまく動作すると分かるでしょうか? 大抵は自動でテストを行うのがベストですが、常に行う必要はありません。何にせよ、 全ての行を少なくとも1回は実行させておくことです。
時には、適切な状態で起動させるには難しい場合もあるでしょう。ただ幸いなことに、ちょっとしたズルをすることは簡単です。例えば、データベース呼び出しに関するエラーハンドリングは、暫定的にカラム名を誤ってつづっておけば、チェックが可能です。または、めったに起こらない事象を引き起こすためや、単にコードが正常に動作するかどうか確認するために、(”if error”を”if not error”にするなど)if文を一時的に逆にすることもできます。
たまに開発者によって一度も実行されていないと思われるコードにバグを見つけることがあります。レビューでは問題なさそうに見えますが、実際には動作しません。自分の書いた行を常に実行することを心がけておけば、こんな恥をかくことも避けられます。
5. 全体より先に部分を検証する。 各部分が十分に検証されていれば、時間を節約できます。多くの場合、部分同士を統合する際に問題が起こります。例えばモジュール間のインターフェースに関する不整合や誤解などです。部分別に動作が信頼できていれば、統合した際に発生した問題を追跡することははるかに容易になります。
6. 何事も予測より時間がかかる。 特にプログラミングに関して当てはまります。たとえ万事がうまくいっていたとしても、1つの機能に費やされる作業時間を見積もるのは困難です。ソフトウェアの開発中に、予期していなかった問題にぶつかることは日常茶飯事です。単純なマージが些細なバグを引き起こしたり、フレームワークのアップグレードにより機能の変更が必要になったり、APIコールが正しい動作をしなかったりします。
ホフスタッターの法則は真理をついています。 “たとえホフスタッターの法則を計算に入れていたとしても、物事には常に予測以上の時間がかかるものである。”
7. まずは既存のコードを理解する。 コーディングする場合、大抵は既存のコードを何らかの形で変更することになります。たとえ新規の機能追加であっても、既存のプログラムに適合させなければなりません。そして、新しいものを適合させる前に、その時点で行っているソリューションを理解する必要があります。そうしなければ、うっかり既存の機能を壊してしまうかもしれません。これは、コードを 読む ことが、コードを 書く ことと同じくらい必要とされるスキルであることを意味します。また、これが理由で、一見些細に見える変更であっても、時間がかかることもあります。自分が変更を加える箇所のコンテキストは必ず理解しなければいけません。
8. 読み、そして実行する。 幸いにも、コードを理解するための補完的な方法が2つあります。コードは読めますし、実行できるのです。コードを実行すれば、その動作を理解するのに大いに役立ちます。必ず、両方を行ってください。
トラブルシューティング
9. バグは必ず存在する。 私は、ソフトウェア開発に際して”最初から完全なものを作る”というアプローチは好きではありません。どんなに努力をしたところで、バグは必ず存在するのです(バグとは大抵の場合、”それは考えていなかった”というものが当てはまります)。すぐにトラブルシューティングをして、バグを修正し、修正版をデプロイできるようにシステム環境を整えるのが、断然良いアプローチです。
10. 障害レポートを解決する。 いかなる開発者も、顧客からの障害レポートに対応し、バグを修正することにそれなりの時間を費やすべきです。そうすることで、顧客が行おうとする処理や、システムの使われ方、トラブルシューティングの難易度、そしてシステムがどのように設計されているかをもっと理解できます。また、自分が開発したものに責任をもつという意味で、これは素晴らしい方法です。これらの利点を見逃さないでください。
11. 問題を再現する。 バグ修正の最初のステップは、問題を再現することです。そして、修正を加えたら、その問題が起こらなくなったことを確かめます。これは、不具合が起きるもののみを問題として捉え、またソリューションが想定どおりに動作することを確かめるシンプルなルールです。
12. 既知のエラーを修正してから残っていることに目を向ける。 既に分かっている問題が複数現れていることがあります。別々のバグがお互いに影響しあって、妙なことが起こったりします。このような場合、起きていることを解決しようとするのではなく、既知の問題を全て修正してから、残った現象に取り掛かることにしましょう。
13. 偶然と思わない。 テストやトラブルシューティングを行う際、偶然が起こるとは決して思わないでください。タイマー値を変更したら、システムが頻繁に再起動するようになった。偶然ではありません。新しい機能を追加したら、それとは関係のない機能の動作が遅くなった。これも偶然ではありません。原因を調査してください。
14. タイムスタンプを関連づける。 トラブルシューティングを行う際は、サポートとしてイベントのタイムスタンプを活用し、更に値を確認してみましょう。例えば、システムが再起動し、その3000ミリ秒前にリクエストが送信されていたのだとしたら、タイマーが再起動の原因となるアクションを引き起こしていたのかもしれません。
連携
15. Face to faceは効率を高める。 ある問題に対して解決策を議論する際は、ビデオ会議や電話会議、またはチャットやEメールでのやりとりよりもフェースツーフェースで話をする方が効果的です。同僚と面と向かって議論をしたことで導き出される解決策が、いかに素晴らしいかということに私はよく驚かされます。
- ラバーダッキング。 行き詰まった時はいつでも、同僚にその問題を話してみてください。多くの場合、例え同僚から答えが得られなかったとしても、話すことで何が問題だったかに気づきます。魔法のように聞こえるかもしれませんが、驚くことによくあることなのです。
17. 尋ねる。 コードを読んだり、実行したりしていると、そのコードが何をし、どう機能するのかを見極めるのがうまくなります。しかし、より知識が豊富な人(例えば、元のコード作成者)に聞くチャンスがあるのであれば、その選択肢も活用してください。特定のことに関する質問をしたり、その質問に対する追加の質問をしたりできるということは、情報を数分で得ることができ、時間を無駄にせずに済みます。
18. 成果を分かち合う。 良いものは良いと認めましょう。「私たちが試したのは・・・」と言うのではなく、「Marcusが思いついたアイデアは・・・」(もし彼が思いついたのであれば)と言いましょう。誰が協力してくれたのか、誰が貢献してくれたのか、名前を挙げて伝えるようにするのです。
その他
19. 試す。 ある言語の機能がどう動くか確証がない場合、簡単なプログラムを書いてどう機能するかどうかを試してみましょう。構築しているシステムをテストする時にも同じことが言えます。パラメータを-1に設定したらどうなるのか、システムを再起動した時にサービスが停止したらどうなるのかなど、動作を検証してみます。色々と試してみることでバグを見つけられることもあります。また同時に、システムがどのように動作するかの理解を深めることもできます。
20. 一晩寝かせてみる。 解決が困難な問題に取り組んでいる時は、決断を下す前に一晩寝かせてみましょう。そうすることで、問題そのものを積極的に考えていなくても潜在意識が働き、結果的に、次の日に明確な解決策を見出すことができるでしょう。
21. 変更する。 仕事の役割を時折変えてみることを恐れないようにしましょう。普段とは違う製品を扱う異なる人と仕事をしてみたり、別の会社で仕事をしてみたりすることが刺激になります。私が思うに、強制的に言われない限り、多くの人は何年も同じ仕事に就いているはずです。
22. 学び続ける。 ソフトウェア開発の素晴らしさの1つは、多くを学び、知る機会が常にあるということです。異なるプログラミング言語やツールを試してみたり、ソフトウェア開発の本を読んでみたり、MOOC(大規模オープンオンライン講座)を受講してみたり。ちょっとした改善は、すぐにあなたの知識や能力に大きな違いとして現れてきます。
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa