EOL対応はシステム見直しを行うベストタイミングである

こんにちは。モノタロウで開発担当している竹原です。

皆さんは、EOL対応についてどのようなイメージをお持ちでしょうか?

EOL(End Of Life)とは、ハードウェアやソフトウェア製品の販売や生産、ベンダーのサポートや修正・更新プログラムの提供終了を意味します。EOLを放っておくと脆弱性や不具合を抱えたまま運用することになりかねないため、基本的には対応必須です。

とは言いつつも、不具合を出すリスクもあり作業内容としては広範囲のテスト作業となるため、入れ替えるハードウェアやソフトウェアに劇的な機能向上が無ければ、コストに見合う価値が得られません。しかし、確認範囲が広いという点を逆手にとるとシステム全体を見直す良い機会でもあります。

今回、私のチームでPythonのEOL対応を進めるうえでも同様のことが想定されました。そこで、テスト方針に何個かのルールを追加することで、業務視点から現在の問題点や全体最適な正解に気づけ、システムを見直すと共に開発者のスキルアップもできたお話しをします。

今回のミッションと問題

モノタロウでは多くのプログラムがPythonで書かれています。サイトのプログラムは既にPython3にバージョンアップしていましたが、バッチがまだPython2で動いていました。それをPython3で動くようにする事、更にファイルのエンコーディングをUTF-8に変更するという事が私のチームのミッションでした。バッチと言っても様々な機能が存在しており、コードのCopyrightに記述された一番古い日付は2003年。古いコードというのは数々の問題を抱えているものです。例えば、スタートアップの企業では成長速度を優先するあまりドキュメントが残されていなかったり、保守ベンダーが変わった際に内部仕様の引継ぎがうまくできていなかったり、という事をよく聞きます。モノタロウにも下記の様な部分がありました。

  • 継ぎ足し継ぎ足しのリファクタリングされていない「秘伝のタレ」
  • 動いているのだが中身を良く知る者はもういない「パンドラの箱」
  • ドキュメントが存在していない「ソースコードが仕様書」

今回のようなEOL対応案件においてはインプットのデータパターンが判っていれば、アウトプットの新旧比較を行い、ロジックの中身は把握せずとも完了できますが、そのインプットのデータパターンも判らないところからの出発でした。

テスト環境

テストする環境として一般的には下記のものがあります。

  • 開発環境
    • データを自由に作成でき、プログラムを動かしながら動作確認できる本番系に影響しない環境で主に単体テストを行う。
  • ステージング環境
    • 本番と同等のデータやシステム構成となっており連携テストやパフォーマンステストを行う。
  • 本番環境
    • 通常は本番環境をテスト環境として使う事はありませんが、リリース案件を確認する場合やどうしても開発環境やステージング環境と異なる部分がある場合は本番環境でアクセスを制限する等の状態を作り、テストを実施しなければなりません。

テストの方針

特に今回のPython3化においては、プログラムを修正しなければならない点もありましたが、殆どは自動変換で修正可能でした。考慮すべき点としては、サイト側の対応の際によく問題になっていた下記の2つでした

 1.文字列型の変更についての不具合

 2.異なる型の比較が厳密になった事についての不具合

1.はつまりバージョン2系では文字列型はstr、unicodeと2つあったのですが、バージョン3系ではstrのみとなりそれはunicodeを示す、そして各文字エンコーデイング(UTF-8等)にエンコードした文字列はbytes型となりました。元々文字列はstrで扱っていたため、ファイルエンコーディングをUTF-8に変更する修正も相俟って修正には混乱する場合がありました。これについては処理の結果(DB,ファイル,ログ,メール,エラー出力,中間ファイル等のアウトプット)について新旧比較するという事を決めました。

2.は例えば下記のような事です。

バージョン2系

Python 2.7.16
Type "help", "copyright", "credits" or "license" for more information.
>>> None < 1
True

バージョン3系

Python 3.6.6
Type "help", "copyright", "credits" or "license" for more information.
>>> None < 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'NoneType' and 'int'

Pythonは型宣言がなく同じ変数に別の型を設定できます。そして上記はバージョン2系の動きがおかしい、という意見もあるかもしれませんがこれが便利という事でそれを期待して書いてあるロジックが多数ありました。

そのためテストについてはインプット側のデータパターンについてのドキュメントがない以上ブラックボックス的にテストする事はできず、ロジックの全てのIF文について型が異なるパターンになるか調査しそこを通るテストをする事にしました。

それぞれの環境においてのテスト内容をまとめると下記となります。

  • 開発環境
    • 全パステストと文字コードに関する新旧比較テスト
  • ステージング環境
    • 連携テストと本番相当データでの新旧比較テストとパフォーマンステスト
  • 本番環境
    • リリース後稼働確認

開発環境の全パステストと新旧比較テスト、そしてステージング環境の連携テストを実施する為に、現ロジックの調査とバッチが対象とするデータが何処から来てどのようなパターンがあるのか、そして結果がその後どのシステムで使われいているのかを調査する必要がありました。さらに、ルール1として下記についてしっかり時間をかけて理解するよう実施しました。

  • 全体における担当部分
    • どのような運用業務のどこに位置しているのか
  • 個別の処理内容
    • どのような処理でデータはどのように利用されるか
  • それらの必要性
    • なぜそこでその処理が必要なのか

これらを理解することで業務的な視点からその機能を見る事ができるようになります。そのため時間をかけてでも実施することが重要です。

ステージング環境では連携テストに加え新旧比較も実施しました。本番相当のデータ量・データ種類でテストが可能ですのでデータ量を多く試す事でパターンの見落としをフォローできると考え、重要なバッチは1週間から1ヵ月分、最低でも1日分のデータを対象に実施しました。

本番リリース後はできる限り稼働確認を行いました。これはスケジュールされた日時(深夜や月に1回等のタイミング)にならないと動かないバッチがありますが、その時になって不具合になると保守担当の人に迷惑を掛けるためです。

また、ロジック調査やシステムの前後調査において気づいた点は修正提案としてリストを作って案件終了後に実施することにしました。今回のような案件では一括請負的な仕事の仕方になりがちです。Python3で今まで通り動くようテスト完了さえすれば良い為、それ以上のタスクを増やしたくない事から、意見は出づらくなる傾向があります。しかし、今回は業務視点で理解したうえで作業している為、気づく点はありそうでした。そこで、ルール2として、その作業肥大化リスクを警戒して意見が出づらくならないよう、修正提案リスト作成のみに留めると、作業スコープを明確化しました。

全体像を知ったからできたこと

前後システムの調査を経てテストの準備と実施には時間がかかりましたが、ルールに基づいて実施したからできた事がありました。

  • 不要なバッチや不要な処理の把握
    • 案件着手時に何個かは廃止可能なバッチを認識していましたが、実は数時間掛けて出力した結果は現在誰も使用しておらず廃止可能だったというバッチや、結果の一部は使われているがその大部分を削除できるバッチがありました。
  • 内在していたバグを発見
    • 作成当時は正しかった仕様も前後のシステムが変更されていき、対応漏れや今となっては不具合になる処理を発見できました。
  • 処理時間が伸びてきていて後続に影響しそうなバッチ
    • 初期構築時にパフォーマンス要件のテストはしますが、その後のデータ量が初期構築時の想定を超えている事は多々あるかと思います。一部の古いバッチではプロセスが繋がっておらず起動時刻で前後関係を担保しようとしていました。
  • ドキュメントの作成
    • 内部の処理だけでなく前後のバッチや他システム、業務との関係についても記載したドキュメントを作成する事ができました。
  • 不具合なく完了
    • 何かシステムを変更すれば不具合は出るものです。しかし、今回は各メンバーが全体を把握し、テスト項目としても押さえるべき要所を漏れなく認識できたことでテスト精度が上がったと考えられます。

これらはプログラムロジック調査だけでは難しく、運用業務の何処に位置しているバッチなのか、どのような役割があるのかという業務視点での理解ができたからこそ気づけたことでした。

テストを通じてあるべき姿を知る

各バッチの作成された目的や時期はバラバラです。各バッチが作成される時、優先されるのはその機能要件であり、下記の事には気づかないか後回しにされる傾向があります。今回全てのバッチについて共通の環境・観点でテストする事であるべき姿についても知る事ができました。

  • 共通の設計
    • プログラム構成やログの出力場所、ファイル名、記載内容等が異なっていると運用・保守においての障害となってしまいます。作成ガイドやフレームワークが必要とわかりました。
  • 備わっているべき機能
    • ドライランや冪等性、本番時の稼働確認やリカバリー、調査するために必要なログの出力などバッチに備わっているべき機能が何かを認識できました。

これらも修正提案としてリストアップし今後修正していく事になりました。

まとめ

今回はバッチのPython3対応において各環境でのテスト実施方法を設定していく中で、前後のシステムについても“調査しなければならない“というところから始まりましたが、ルールを決めたことで、様々な気づきと共に不具合を一つも出す事なく案件を完了できました。なにより以降の案件において、チームメンバーから将来や全体を見据えた提案が多く出るようになりました。それは今回の経験から全体を意識するようになり視野が広がった(視座が高くなった)と言えます。既存システムのバージョンアップ作業という一見退屈な作業でしたが、チームメンバー全員のスキルアップを実感できた案件となりました。

仕事を与えられたときに、“なぜその処理が必要なのか前後のシステムや運用も改めて認識する“とはよく言われる事ではありますが、これをする事で問題や全体最適な正解に気づけるようになります。今回その効果を身をもって実感できました。