モグラたたき開発を卒業しようの対策部分がそれなりの記述量になってきたので、別記事にいたします。
モグラたたき開発の現場を作り出してしまっているのは、その組織のマネジメント自体、組織の運営者(開発者自身も含みます)の意識です。この対策編に書いている作業に特別なことは何も記載されていません。地味な作業の積み重ねだと言って差し支えないでしょう。モグラたたき開発の最中にあって苦労している人は、自分の担当の作業に影響する前段の部分の作業が適切に反映できているのかどうか、前段の作業の担当者に確認を取ることです。確認を怠ると、実行したデータがまったくの無駄になるばかりか、ひどい場合にはトラブルを引き起こすことになってしまいます。
対策編
失敗しうる要因についてチェック項目を作っておいて事前に適切なチェックを積み重ねておくことが、トラブルを減らすポイントです。
以下の例では、機器を制御するプログラムを開発する場合、しかも結合テストを想定した対策案です。
自分自身の意識を変えよう
- 目的を理解しているか
- 動作がうまくいかなくなる要因をリストアップしたか
- 動作がうまくいかなくなる要因への対策をうったか
- 生じやすい課題が生じたときに、問題を切り分けるにはどうしたらよいか考えたか
- 問題を切り分けられるだけの仕組みを実験の中に仕組んだか
- 何が起こりうる最悪かを考えよう
チームの意識を変えよう
- 各人の開発したコード(あるいは機器の部品)がうまく動作するとうれしい。
- 品質が向上しているのをみるとうれしい。
- 一緒に仕事する中で、自分の成長が感じられてうれしい。
- トラブルを未然に防止することができるとうれしい。
- 工夫をしていくことで必ずよくなると信じられる。
- 仕事の品質を高める工夫は、職業人としての自分の成長につながると信じられる。
ソースコード
- ソースコードの単体テストの枠組みが用意されているか
- ソースコードで単体テストを増やしているか
- テストをするうえでtraceabilityが確保できるソースコード管理、データ管理になっているか
- 動作中に不具合が生じたときに、どの関数でどういう不具合が生じたかが分かるように作ってあるか?
-
テストするに値するコードになっているか?
- DRY原則を満たしているか?
- 単一責務の原理を実現してあるか?
- 関数の外部仕様は十分に明確になっていて、正しい動作と間違った動作を区別できるようになっているか?
ハードウェアと密接なソフトウェアの場合
- ハードウェア由来のパラメータに責任を持っているのはだれか
- ハードウェア由来のパラメータの妥当性はどうやって確かめているか
- その値が間違っているとどういう影響が及ぶのか
- 複数のハードウェアがあるとき、その値はばらつくのか
- 品質を作りこむための仕組みはできているか?
- バージョンのつじつまがあっていなかったらチェックができるか?
- 機器固有の情報がある場合、その設定が別の機器の情報だったら違っているとチェックできるか?
実験の準備
- 一連の手順の中でバージョン管理が必要なものは管理されていて、トレーサビリティが確保できる実験になっているか。
- 実験のときに結果を記録する手順(あるいは、ログの自動化)はできているか
- そのログは、トレーサビリティを確認できるものになっているか。
- 失敗しうる要因に何があるかを事前に把握できているか
- 失敗しうる要因になるかもしれない要因に対して、計測して記録できるようになっているか
- 何か実験中にトラブルを生じたときに、原因の切りわけを可能にするログになっているか
実験手順のドキュメント化
- 実験を行うための手順は明確にできているか
- 手順の執筆者以外の人がその手順書で実行できるものになっているか
- 執筆者以外の人が実際に操作した結果をふまえて、改版されているか
- ドキュメントはバージョン管理されていると同時に、ユーザーには常に最新版が届いているか
### テスト不十分な状況での実機動作は機器を破壊する
ソフトウエアはちょっと間違っていたとしても何度でもやり直しができるのですが、ハードウエアはそうはいきません。回路が間違っていたら部品が壊れてしまいます。
ハードとソフトの開発文化は異なっている
-
適切な接続でないと機器を壊す。
- 異なる配線に同じケーブルをつないでいる場合には、誤配線をしてしまえる。
- ケーブルにかかる電圧は、基板によってまちまち。
-
不具合が発生したときに、それを検知しなければ、機器は壊すことがある。
- 異音の発生
- 異常な発熱
- 電源を入れる前に確かめるべきことは確かめきったか?
- 特に自作ボードならば慎重にチェックを
-
そのシステムは断線したとき、ケーブルが抜けたときにどうふるまうのか。
- 異常が発生したときにonになるシステムでは、ケーブルが抜けていると異常を検知できない。
-
そのシステムはいきなり電源をきったらどうなるか?
- 壊れる?、壊れない。
ビルド前のチェック
-
buildの仕方を書いた手順書は最新版を読んだか
- 環境変数の設定によって、buildされるプログラムが微妙に異なるような仕組みは避けるべき。
-
ソースコードは最新版か
- レポジトリでのバージョン番号を記録しておこう
-
関連するデータファイルは最新版か
- レポジトリでのバージョン番号を記録しておこう
-
buildするための設定は適切か
- preprocessor の defineの値の設定を確認する。
ビルド後のチェック
- 実行形式のプログラムは、どのバージョンで、どういう条件でbuildされたものか確認できるようになっているか。
事前チェック項目
- 機器の位置あわせは適切か
- ケーブル類の接続のつなぎ方は正しいか、機械的な接続は十分か(抜けやすくなっていないか)
- 各部品に電気は入っているか
- 各部品のモジュールと組み込み用のボードと通信はOKか
- 組み込み用のボードから各モジュールへのコマンドと応答はOKか(例 LED on/off)
- プログラムのバージョン、データのバージョンはあっているか
パソコン側の事前設定のチェック項目
- 設定ファイルの記述の確認
- パソコンの周辺機器の接続の確認(デバイスマネジャー回り)
- USBポートの確認(USBポートに複数のデバイスを接続していると、目的の接続になっているとは限らない)
- ネットワークの設定
自己診断機能
プログラムには自己診断機能を設定しておくのが無難です。
- プログラムのバージョンと設定ファイルのチェック
- プログラムで必要とするデータファイルの読み込みチェック
- プログラムで必要とする出力ディレクトリの存在先があることがチェック
- プログラムで使用するデバイスが準備できているかのチェック
- プログラムで使用する接続先のデバイスの自己診断用の動作が正常に動作したかのチェック
- プログラムが必要とするライブラリはインストールしてあるか、そのバージョンは必要な条件を満たしているかを、早めにチェックできるようになっているか?
一連動作のテスト
- 初期化動作の確認
- 動作1の確認
- 動作2の確認
- 終了動作の確認
トラブル報告の手順
-
トラブル発生時に、そのトラブル報告・バグレポートの報告の仕方は標準化されていて、守られているか。
- Redmineのようなシステムを使って管理しているか
- 実験結果のログの保存場所
- 保存されているデータの再解析手順
トラブルへの対応
- 発見されたバグを見つけることのできる方法を単体テスト化できたか
- 再発防止のための対策はできたか
- 似たようなトラブルで生じうる内容を思いついたか
- 似たようなトラブルの予防方法を思いついたか
フォルトツリー解析(FTA)の用意
一連動作の中で発生する個々の不具合の要因を予め調べておき、どの要因によってその問題が生じうるのか切り分けしよう。
そのような準備をしておくことで、一連動作を乗り切ることができる。
バージョン管理されているコードに問題が見つけられないとき
- 現場で使用しているコードが、バージョン管理されているコードと違っているということはないか?
担当モジュールの開発の場合
単体テストを導入する(例:GoogleTest)
- 最初はだれか詳しい人に1つ例題のテストを作ってもらう。
- それを自分の環境でも動作させてみる。
- 一つだけテストを追加してみる。
- 加えたテストを含めてビルドが通れば成功。
- テストを実行し、成功か失敗かのどちらかが返ってくれば、単体テストの導入に成功です。
実装済みのライブラリに対して、単体テストを少しずつ増やしていく。
- テストがしにくい項目については、回帰テストでよいから、自動化テストとして導入していく。
- 正常系のテストを増やしていく
- 正常系のうまくいっている内容を、うまくいっていることが確認できる自動化テストを増やしていく。
- 正常系の動作で問題を生じたときには、その再現テストができるように、テストを登録する。
(この時点では、正常系の動作に生じた問題そのものがテストで失敗することは問題ではない。それは後々解決すればよいこと。)
失敗事例のデータをテストデータとして収集しよう
アルゴリズムの開発では、そのアルゴリズムが期待通りの動作をするのか、実際のデータで評価する必要があります。そのため、失敗事例のデータを収集して、それが現在のアルゴリズムでどうであるのかを実行できるようにしていきます。
集めた失敗事例が、このテストの枠組みで評価できることが重要です。すぐには改変したアルゴリズムでも成功しないことはあるかと思います。それでもテストを実行できることの方がはるかに重要です。
正常系のテストを充実させた後は
正常系のテストを充実させた後は、異常系のテストを記述していきましょう。
異常系のテストは簡単ではありませんが、完成度を高めるために必須の作業です。
異常系の場合には、それぞれの関数・メソッドがどういう動作をすべきかと設計から見直す必要があるかもしれません。
追記
動作環境をそろえよう。
Dockerが使える場合にはDockerを使うことが、環境をそろえてくれるので、人によって動く・動かないのトラブルを減らすことができます。
使っているライブラリにはさまざまなバージョンがあります。
古いバージョンのライブラリを使い続けていることによって生じる不具合や
新しいバージョンによってライブラリのインタフェースが変更になることなどにともなって
ある時点では動作していたソフトウェアが動作しなくなることを防ぐことができます。
Dockerについては、あなたの近くのDocker使いの力をかりて、
その動いている状況を見せてもらうこと、
Dockerfileが書かれているアプリケーションを自力で動かせるようになること
最後にDockerfileを書けるようになること。
モグラたたき開発は高くつく
モグラたたき開発をしていると、品質の向上を実感できない。いつどのような不具合に出くわすのか予想がつかない。開発スケジュールに遅延を生じさせ続けてしまう。そのためビジネスパートナーの信頼を失いかねない。「そのバグは枯れたんじゃなかったの?」と再発したバグによって同僚の信頼も失いかねない。モグラたたき開発の現場では、埋め込んでしまったバグが発覚するまでに時間があることも多く、バグを修正するときには、相当むかしのrevisionに戻ってどこでバグを埋め込んでしまったのかを解析することになる。
そのようなモグラたたき開発は、開発組織の運営費用にも影響してくる。モグラたたき開発は高くつく。リーダーはそのことに気づいて欲しい。
実験の種類によっては、それにふさわしい意識を自分の中に作り上げないと絶対に成功しないものがあります。
例:水分を嫌う合成反応
例:絶縁性が高い物質の電気特性の精度の高い測定
例:有効精度の桁数の高い実験
例:μg単位での合成や分析
自分が行おうとしていることは何なのか、そのことを実現するためには何が必須なのかをいやでも自覚しなければなりません。漫然と実験するかぎり、いつになっても(できることがわかっているはずのことを)達成できません。
このようなことは、ソフトウェア開発の現場でもあると私は思います。必要なことは何であって、それをどうやって実現するのかを考えて対策を積み重ねていくことです。チームとして行っている開発では、開発メンバーすべてが目標の実現のために、何をどう改善していく作業を積み重ねていくのかを共有していくことです。
付記:
あなたがテスト駆動開発を実践していても、関連するモジュールの作成に責任を負っているリーダーが、テストの自動化についての理解が欠けていると、あなたのモジュールが本来の性能を出しえなくなることがあります。開発にあたって何度も似たような失敗を繰り返しているのならば、何らかの組織的な問題を抱えている可能性が高くなります。そのような組織的な問題を多数抱え込んだままだと、優秀な人員が離れていくことを引き起こします。だれだって成功する仕事をしたいのです。仕事に課題があれば解決するように提案をします。しかしその改善提案が無視され続ければ、その技術者にとっての選択肢は限られてしまいます。そのような事態を引き起こさないためにも、モグラたたき開発を卒業させましょう。
「とりあえず動かしてみる」は危険
http://toyokeizai.net/articles/-/177313
現場でもあると私は思います。必要なことは何であって、それをどうやって実現するのかを考えて対策を積み重ねていくことです。チームとして行っている開発では、開発メンバーすべてが目標の実現のために、何をどう改善していく作業を積み重ねていくのかを共有していくことです。
失敗の事例集や、対策をうつためのガイドを紹介する記事は、次の記事に独立させました。
付記
自動ビルドと自動テストを行うサービスを利用しよう。
そうすれば、ここに書いた対策のいくつかは、自動で対応ができるようになる。
- 担当するソフトウェアのコードを書いている人が多忙のあまり、テストを省略してしまったとしても、自動ビルドと自動テストを行うサービスは、問題点を必ず指摘してくれる。
- 必ず最新のコードでビルドしてくれる。
- どのバージョンでテストが正常にとおって、どのバージョンでテストが通らなくなったのかが必ずわかる。
- プログラムのバージョン、データのバージョンなどが適切に管理される。