効率性はアーキテクチャの設計で作りこまれる
"非機能"と言うと、とかく機能やプログラムの「性能」面ばかり気にしてしまいますが、実際には性能は非機能のごくごく一部でしかありません。
とはいえ、利用者にとっては目に見えてわかる品質だけに、ほかの非機能に比べるとややプライオリティが高いのも事実です。なにせ、
「遅い=イラっとくる」
は切っても切れない縁にありますから。
では、性能面を考慮するにあたって、まずどこに着目するかと言ったとき、大抵みなさんは「情報リソースへのアクセス」部分に着目することでしょう。
データベースがあるなら、DBアクセス。
ファイル操作があるなら、ファイルアクセス。
通信があるなら、通信アクセス。
他システムとの連携があるなら、他システムアクセス。
制御機器があるなら、機器アクセス。
もちろん、これらの考え方は間違ってはいません。確かにボトルネックとなりやすい部分ではあります。特にデータベースは、接続(open/close)でもそれなりに時間がかかりますが、その後のSQL文も大きな障害となることはままあります。
たとえば、
「索引(index)を設定しているにもかかわらず、SQLの実行速度が遅い」
「ヒント句を記述しているにもかかわらず、
実行計画では索引(index)が使用された形跡がない」
と言うことを経験した方もいらっしゃるかもしれません(まぁ、ヒント句は必ずしも索引とセットと言うわけではなく、オプティマイザに「SQLをいじらず」直接指示できる文…ですが)。この手の経験をされた方は、オプティマイザ(操作の最適化を行ってくれるDBの頭脳ともいうべき機能)の性質や、カーディナリティ(データの分布、濃度)をご存じないのかもしれません。
それらの観点も重要ですが、それ以上に見落としている部分があります。
それは、
プログラムの実行量(行数)
※記述行のことではありません
です。つまるところ、人間が作業するのと同じで、
プログラムを実行する量が多ければ多いほど、性能は劣化する
という基本原則は変わりません。10行しか実行しないプログラムと、100行実行するプログラムでは、後者の方が実行時間が長くなるのは当然です。仮に見た目10行にまとまっていたとしても、プログラムが実際に実行する行数が100行あれば100行分の時間がかかるのです。
人間の活動は、実際に身体(頭脳を含む)を動かす作業量が多ければ多いほど、時間はかかる…といえばいいでしょうか。これは性能面における最上位の本質であり、原則です。このことを失念していては、性能向上は図れません。
先の例でいうと、
「なぜデータベースに対するフルアクセスは遅いのか?」
↓
格納されているデータを1件1件チェックしながら操作しているから
プログラムでいえば、拡張For文で、全件走査しているのと同じです。
ファイル操作の例でいうと、
「なぜファイルアクセスは遅いのか?」
↓
ファイルのopen/closeもさることながら、行ごとやサイズごとに繰り返し操作しているから。
結局、プログラムの作成規模ではなく、プログラムの実行行の規模によって、性能劣化は起こるのです。
当然、それは私たちが作り上げるプログラムも同様です。forやwhileなどの繰り返し制御文は、機能的には非常に便利ですが、性能を劣化させる原因にしかなりません。そのデメリットを考慮したうえで、
極力繰り返さなくてもいい"設計"
というものを、普段から考えたことはあるでしょうか。「繰り返し文を書かないプログラム」ではなく「実際に繰り返さなくていいプログラム」です。あるいは「同じ繰り返すとしても、より処理が重くならなくていいプログラム」でもいいかもしれません。
たとえば、ファイルアクセスなどは「1行ずつ読み込むか」「まともて読み込んでから1行ずつに分割するか」で、処理速度は大きく変わります(どちらに実効性があるかは、規模次第ですが)。
元来、性能要件と言うのは、要件定義の時点である程度決まっています。言ってみれば、当社に発注していただいた時点で、お客さまの頭の片隅には「一般的な常識の範囲内で」性能を求めています。ゆえに、私たちは
と言った流れで、ITシステムの性能品質に対し、開発ライフサイクル全体を通して作り込まなくてはなりません。性能品質を作り込んでいくには、開発工程の早い段階からその工程に応じた対策を打っていくことが必要です。
つまり、終盤のテスト工程になって初めて性能をチェックするのではなく、「実装までに性能を見極めておき、性能テストで想定の性能に収まっていることを確認するだけ」という姿勢で臨むべきなのです。でなければ、最後の最後になって1から作り直し…と言うことにもなりかねません。
Webシステムの例でいうと、以下のようなイメージを持っていなければ、局所的な対応しか思いつきもしません。
これは一般的なWebシステムへのアクセス(問い合わせや登録など)を行う際に要する処理時間の内訳(主な部分のみ)となります。
こういう観点で考えるのは、単純に「機能仕様さえ満たせばいい」と思っているエンジニアには難しいでしょう。要するに
「何を作ればいいのか」
さえわかればモノづくりができると思ってしまっているエンジニアのことです。実際、機能として「何を作ればいいのか」がわかれば、「どう作るのか」はあまり誰も介入してきません。比較的、エンジニアやプログラマーと言った人たちに自由度が与えられたりもします。
だからこそ属人的になりやすく、先述のような考え方を持たない人たちにとっては、致命的ともなりやすい部分と言えるでしょう。
こうした問題は、根本的なアーキテクチャの定義が疎かになっているせいで起こってしまっている可能性が高く、もしそうであった場合は、仮にテストで問題を検知できたとしても、"手戻り"の工数がとんでもないことになりかねません。
仮に、です。
仮に、「効率性が悪い」そして、その原因は「処理速度を考慮した設計および実装になっていなかったから」という問題が起こったとしましょう。
確かに対策すれば、品質は1つ向上します。他にも類似点があれば、品質的には大いに前進したといえるでしょう。しかしこれ、1機能修正し、テストをし直すごとにどれくらいの工数が必要になりますかね?
最悪、1機能あたりで2~3日かかってしまうかもしれませんね。作り直す幅が大きいと言うことは、論理的に機能性に問題が無かったとしても、テストは実施しなおしです。テスト工程の品質に必要なのは、「論理的な類推」ではなく「実績による証明」ですから、作業は大きく後退させなければなりません。
たったこれだけのことでも、仮にプロダクト上の品質が保証されたところで、マネジメント品質を大きく損ねるような大惨事を招きかねないと言うことを理解したうえで、あらかじめ考慮された設計ができるといいですね。