はじめに
長年勤めたソフト開発の会社を、退職した。
次もソフト開発の仕事に就くかは未定のため、いまここで、これまでの開発者としての人生を振り返ってみることにする。
コードリーディング
新人の頃、先輩から「コードをいじる前にまず考えを文章でまとめてみなさい」とよく言われた。
しかし、まだ経験の浅い段階でこれを実行するのは難しい。
なぜなら、コードを書くパターンに関する知識が、圧倒的に足りないからである。
知識不足により、頭の中でイメージすることができず、結果、コードを書きながら、あーでもない、こーでもないと試行錯誤するしかない。
コードの書き方の様々なパターンを知識として獲得するには、既に存在する、他人の書いたコードを読みまくるのが最も効果的である。
当時、DDJ(Dr. Dobb's Journal)という月刊誌があり、技術解説と共に様々なサンプルコードが掲載されていた。
自分の知らない言語のサンプルもたくさんあったが、私はこれをひたすら読みまくり、自分なりに意味が理解できるまで考え抜いた。
この変数は何のためのものなんだろう。最初はわからなくても、「そうか!」と、徐々に理解できるようになっていった。
コードを読んで理解するだけでなく、もっとこう書いた方がいいのでは、と自分なりの考えも出てくるようになった。
また、業務では、他人のバグをつぶす作業も、コードの読み方、理解力に役に立った。
業務で扱うOSSのコードを、休日に読んだりもした。
このような経験を積むことで、年を追うごとに、頭の中で事前にプログラムの流れを「イメージ」できるようになっていった。
設計はシンプルイズベスト
オブジェクト指向プログラミングが登場、普及し始めた。
オブジェクト指向的な考え方は、自分はとても納得感があり、素直に受け入れられた。
プログラム中の登場人物(オブジェクト)ごとに、きちんと機能分割しましょう、というだけで、基本的には、特段難しいことではない。
雑誌のコラムで特に印象深かったのは、SOLID原則の1つでもある「Open Closed Principle」である。
機能拡張しやすい内部構造を持ち、修正する場合でも範囲が限定的で済むこと。
このような形を維持するには、余計なぜい肉を落としたシンプルな設計を心掛ける必要があると思う。
複雑な機能も、単純な小機能を組み合わせることで実現できる。そう考えるよう心掛けた。
少しでも実装に無理があると感じたら、立ち止まって、設計の見直しをするようにした。
また、業務で単体テストを初めて本格的に導入することになった際に、つくづく実感した。
自分は、後でテストすることを前提にコードを書いていない、と。
関数内のロジックで分岐が増えたり、なんちゃらフラグとかいう変数が増えたりすると、
テストパターンの数も、パターンを考える時間も、どんどん増えてしまうし、バグも混入しやすいコードになってしまう。
テストがしづらいなぁと感じたら、サブクラス化、サブ関数化を検討すること。
ロジックがシンプルであると、他人が読んでも理解しやすいコードとなる。つまり、継続的なメンテもしやすい。
理解しやすいコードは、機能追加や仕様変更の検討に要する時間も短くなる。コスト削減に貢献。
思考の軌跡をメモに残す
仕様検討や設計作業では、検討用のテキストファイルを用意して、考えた内容を全てメモに残しながら作業を進めた。
というか、メモしながら考えていく、という感じ。
作業の目的、前提条件、注意点、調査で役に立ったURL。思い浮かんだ複数の案を列挙し、不採用のものも理由と共にメモに残す。
人間の脳は、誰かに話しかけられたり、トイレに離席しただけで、さっき思いついたアイデアもすぐに忘れる。
頭の中で考えたことを全てメモに記録していくことで、自分の思考の軌跡を見返すことができる。
メモを読み返すことで検討作業の全体像を俯瞰すると、思考が整理される。
詳細設計では、作業の洗い出しを階層構造としてメモ。
各項目の行頭に、□■のマークで未完/済みを把握。やり残し作業を目視で確認できるようにした。
メモの内容は、タスク管理システムの作業チケットに貼り付けて、チームで共有したりもした。
上流工程にこそ、時間をかける
詳細設計の段階で、より詳細に作業項目を洗い出しできると、頭の中で事前に、変更後のプログラムが動作する様子をイメージできるようになる。
こうなると、コーディングでは、メモした内容をそのままコードに落とし込むだけで済むので、作業時間が圧倒的に短縮されるようになった。
コーディングを開始してから考え込む、ということが減ったためである。
同様に、詳細設計よりも基本設計に時間をかけることで、仕様バグの発生を減らせることが体感できるようになってきた。
基本設計よりも仕様検討、仕様検討よりも見積段階に力を入れることで、トラブルの発生を「未然に防ぐ」ことを心掛けた。
後々になってバグの存在に気付いた場合、限られた時間の中では、対処方法の選択も限られてしまう。
バグの数が多いほど、1つ1つのバグにかけられる時間は限られてしまう。
時間が足りなければ、対処も付け焼刃なものになりがちだが、きちんと時間を用意できれば、より望ましい対処法を採用できる。
その方が顧客からの信頼も得られ、満足度も向上させることができる。
コーディングでの習慣
コンパイルはこまめに実行する。
コンパイルエラーを貯めない。
ワーニングは全部消す。
ワーニングにも2種類がある。改善が必要なものとそうでないもの。
改善の必要があるかどうか、考える時間がもったいないので、ワーニングは出さないに限る。
面倒でも全部消す。一度習慣化すれば、それが当たり前になる。
小機能を書いたらすぐ動作確認する。
新規のコードは、必ずデバッガで変数の値の変化を追い、コード中の計算結果が自分の想定通りであることを確かめる。
正しく動作していることを自分の目で見るまでは、自分のコードを信じるな。駅員の指さし確認然り、目視が確実。
また、正常に動作することを確認出来たら、重複コードがないか等、すぐにリファクタリングする。
関数の入出力をもっと慎重に決定しよう。
単体テストすることを想定して、「データ型は適切か?」「取りうる引数の値は?」など具体的に考えてみる。
余談だが、関数ヘッダに引数の想定値(最小値、最大値、境界値、特殊な値など)を記述しておくと、単体テストのコードを自動生成してくれるようなツールがあったらなぁと思ったことがある。
そんなツールを、自分で開発できたら最高なんだが。
レビュー観点と優先度
ドキュメントにしろ、コードにしろ、事前にどのような観点でレビューを行うか、優先度と共にチームで共有しておくとよい。
上位の設計書で明記されている内容はすべて網羅できているか、機能はすべて実装されているか、排他制御は必要十分か、などは優先度が高く、
コーディング規約に沿っているか、誤字脱字がないか、などは優先度は低め、といった具合に。
限られた時間の中で、効率よく問題点を見つけ出すことを目指す。
おわりに
ソフトウェア業界ではこれまで、継続的インテグレーションや自動テストツール、静的解析ツールなど、品質管理の為の様々な技術が生まれた。
しかし、バグを直してくれるツールまでは存在せず、人間が修正するしかない。
よって、バグを生み出さないエンジニアの育成が最重要課題と思ってきた。
将来的には、開発手法やプログラミング言語の、もう一段階の発展によって、部品の組み合わせだけでソフトウェアが開発できるような世界が来ることを願う。
コードを書けば、バグは必ず生まれる。テスト済みで、品質が担保された既存部品の再利用が、ソフトウェアの品質と生産性を劇的に向上させる。
最後まで読んでいただき、有難うございます。