hidekatsu-izuno 日々の記録

プログラミング、経済政策など伊津野英克が興味あることについて適当に語ります(旧サイト:A.R.N [日記])

ソフトウェア・テストを再考する

私が SI という業務システム中心の受託開発業界にいることも多分に関係していると思うのだけど、ソフトウェア・テストに関する各種の方法論に対してどうしても懐疑的な考えを持ってしまう。端的に言ってしまうと「それは私(あるいはSI業界)がテストに関して抱えている問題を解決してくれる」ようには思えないからだ。

 

ここで言う一般的なソフトウェアテストの文脈での方法論というのは具体的には次のようなものを指している。

 

もちろん、これらの方法論は使っていないわけではなく、単体テストケースのケースを考えたり、網羅度を上げるために使うわけだけれど、ある意味テストをするなら誰しもが考えることをより確実に実施するためのものであって、それ以上のものではないように思える。

 

「私(あるいはSI業界)がテストで困っていること」と「ソフトウェアテストの専門家が解決したいと思っていること」の間には大きな開きがあるのではないか。最近話題となった COCOA の不具合や東証の障害にも関係する部分なので、まずはどういう問題に困っているのか具体的に書いてみようと思う。解決策も書きたいところだが、なかなか決定打がなく意見があれば Twitter などで聞かせてほしい。

1. 多様すぎる環境

覚えている人も多いだろうが、業務システムといえば Windows XP + IE6 という牧歌的な時代が長くあった。IE6 には様々な問題があったとはいえ、環境がひとつしかないというのはテストする立場からすれば大変ありがたいものだ。

 

スマホが一般的な時代となり、ビジネスにおいても iPadmacOS を兼用する会社も増えてきた。この流れを受け、業務システムと言えども動作環境を縛るということが難しくなってきた。OS だけでも Windows, macOS, iOS, Android の四種類、ブラウザも IE, Edge, Chrome, Safari, Firefox に対応が必要となる。バージョンやデバイスの違いも含めるとその組み合わせは膨大なものとなる。

 

業務システムで意外とハマるのが、IE や Edge の互換性表示(あるいはエンタープライズモード)問題だ。インストールされているのは IE11 や Edge なので利用者はそのつもりになっているのだが、旧システムのドメインを引き継いだ結果、IE7 や IE8 相当で表示され動作しないというクレームに繋がることがある。意外な盲点として RPA ツールもある。IE のCOMコンポーネントWebKit の古いバージョンを使っていたりするため、今までできていた業務ができなくなったというクレームが来ることがある。

 

また、ブラウザの自動更新も便利な一方で扱いが難しい。発注側がエンドユーザーに提供する際には、サポート環境として「各ブラウザの最新2バージョン」などと書くのが一般的だと思われるが、請負で開発する側には存在しないバージョンでの動作保証はできない。*1

 

請負側で動作保証できる最後のタイミングはシステムテストなのだが、システムテスト時点のバージョンで動作保証したところで、ユーザーテストからリリースまでの期間で動かなくなったり、状況が変わったらどう対応するのが正解なのだろうか。最終的には契約で決まるといはいえ、「良きに計らえ」を旨とする日本の SI 業界ではそう割り切れないのが現実だ。

2. 複雑すぎるライブラリの依存関係

Java にしろ Node.js にしろ、現代の業務システムはオープンソースソフトウェアなしには何もできない。たとえ外部のライブラリを使わなくとも、言語に含まれる標準 API には依存せざるを得ない。

 

数画面しかない業務システムであっても、数百~数千のライブラリが依存関係に含まれるのが当たり前の時代にあって、それらのライブラリにどのような不具合や脆弱性が含まれるか、利用者がすべてのソースコードを理解することは不可能だ。もはや祈りを捧げるしかない。

 

テストしてみたら動かない、のであれば一般的なテスト技法で事前に回避できるのだが、次のように特定の条件、状態でないと再現しないものは、原理的に解決は難しい。

  • レースコンディションに伴う不具合
  • まれにしか発生しないシステムエラーに伴う不具合
  • EXCELや画像など多様な可能性がありえるファイル形式の読み込みに伴う不具合
  • 言語ランタイムの細かいバージョン差異に伴う不具合

ライブラリのあるバージョンで見つかった不具合を解消するためにパッチバージョンを上げたら別の場所でエンバグしていたということもあり得る。実際にはそんなにないから大きな問題になっていないだけで、起こらないという保証はどこにもない。

3. 誰も知らない旧システム仕様

私がシステム開発の業界に入った20年前にはシステム化されていない業務をシステム化するという仕事も結構あったが、現在では多くの業務はすでにシステム化されており、さらにもはや3代目、4代目などということが当たり前になってきた。

 

動いているのだから変えなくてもいいのではないかと言う人もいるのだが、前述のように業務システムの利用環境は多様化しており、機能性が十分だから変えなくてもいいという状況にはない。モバイルだと一画面に表示できる項目数も限られるため、UI も大幅に見直しが求められる。

 

この時問題になるのは、もはや誰も旧システムの機能や細かい仕様をすべて把握していないということだ。発注側であっても、表面的な知識はあっても、夜間バッチジョブでどのような処理が行われているかや、離れた機能が実は関連しているなど、知らないことはたくさんある。

 

特に業務システムにおいてはひとつのシステムで完結することはめったになく、数十のシステムが有機的に紐付いている。そのシステムの仕様は知っていても、仕様を変更した結果、連携先システムのどこにどういう影響が及ぶかを確実に掴むことは至難の技だ。

 

仕様を誰も知らない以上、設計も実装もテストもすべて通り抜け、ユーザーテストやリリース後に発覚することになる。特に旧システムや連携先システムにテスト環境がない場合、本当に祈るしかないという状況になる。テストできないのに障害を起こすなとはこれ如何にという話だが、現実にはしばしば発生する。

 

これに関しては、ある程度解決策があると考えている。それは旧システムのソースコードをきちんと読むということだ。SI開発あるあるなのだが、業務システム開発の上流工程にはソースコードを読めない人が多く、設計書や発注元へのヒアリングだけで設計を進める人も多い。しかしながら、発注元も確実ではなく、設計書はしばしばメンテナンスが不十分である以上、ソースコードをきちんと読む以外に回避に繋がる道はないのではと思う。

4. 実施したことになっているテスト

前述のような状況なので、現在の業務システム開発は、仕様を整理して新システムを設計するだけでものすごく時間がかかる。日本のシステム開発はお金がかかる、人月商売の弊害だ、という意見を見聞きするが、一般論としてプロジェクト費用の60%ほどは実装以外の部分で発生しているし、システム開発失敗の原因の50%は要件定義フェーズにあるとされている。実際問題、要件定義がばっちりうまく言っているのに、ソフトウェアの製造で失敗する、というケースはめったに見ない(無いとは言わない)。

 

こんな状況なので、設計作業は遅れに遅れ、結果として製造が遅れ、単体テストは簡素化され、結合テストで単体レベルのバグつぶしをし、システムテストの終わりでなんとか間に合わせるということになりがちだ。しばしば、単体レベルの品質が低い、プログラマの能力がうんたらという話になりがちだが、個人的な経験から言えば、その前工程の失敗が尾を引いているだけのことが多いように思える。

 

単体テストをする時間がなくなったときに「実施したことになっているテスト」が発生する。単体テストをやったことにするのは簡単だ。単に結果報告書に○を付ければいい。JUnit が必要とされているなら、絶対に通過するテストをそれっぽく書き連ねておけばいい。実装者が追い詰められてそうすることもあれば、チームリーダーが進捗を誤魔化すためにそのように指示することもある。

 

なぜ、レビューで弾かないのか、と思われるかもしれないが、実装の完了すら危ぶまれる状況でレビューをして品質を上げることに何の意味があるというのだろうか。レビューをしている暇があるなら、まずは完成させる必要がある。「分岐網羅の組み合わせテストに基づくテストケースはすべて完成しています。いつでもテストできます。レビュー項目も完璧です。実装はできていませんが」では意味がないのだ。

 

実のところ、ここで問題としたいのは、テストが行われなかったことでも担当者を責めることでもない。スケジュールが押した以上、何かを捨てトリアージするしかない。問題は、未テストを検出して、リリース前にどうやって解消するのかということにある。予期できないトラブルすらたくさんあるのだから、予期できるトラブルは可能な限り解消しておきたい。

 

ただ、これに関しては工夫すれば解決できるのではないかと考えている。統計の検定やクロスバリデーションのように、違う観点を入れることで品質を改善できるのではないか。

 

例えば、各機能の単体テストにおいて、組み合わせパターンの偶数列、奇数列を違うチームで担当させてみてはどうだろうか。まったく単体テストが行われないというケースは減るだろうし、チームの進捗差によって発生するタスクの不均衡を平準化することもできるかもしれない。

 


 

今回、書いた内容について、アジャイルスクラムテスト駆動開発については特に触れなかった。理由としてはあまり詳しくないし実践したこともないため語る立場にないからだ。もし、それらの手法を使えば今回の問題(の一部)は解決するのであれば、その理由を公開してもらえるとありがたく思う。*2

*1:Edge をサポートしますと書いたら Android 版 Edge でアクセスしてきたり、Safari の最新2バージョンをサポートしますと書いたらすでに更新されていない WindowsSafari でアクセスしてきたりする可能性もあるので、環境の条件を考えるのもなかなかひと苦労する。

*2:私自身は、ウォーターフォールでしか開発経験はなく(ただし規模はそれなりに大きい)、少なくとも業務システム開発という領域においてそれらの手法が有効だろうと思ったことはなかったりしますが。