人形つかい(19) 夜の途中
K自動車港北工場の正門前には、橋本さんが待ち構えていた。K自動車のビルや工場に部外者が入るには通常、事前入館登録も含めて面倒な手続きがいろいろあるが、橋本さんが臨時の入館証を用意しておいてくれたおかげで、ぼくたちはスムーズに正門を通過できた。
エースシステムの人たちが作業しているのは、サーバルームに隣接したオペレーションルームで、10台ほどのPCやワークステーション端末が並んでいる。電源が入っているのは奥の方の3台。うち1台の前にエースシステムのエンジニアらしい人が頭を抱えて座っていた。
その後ろの壁に、高杉さんが腕を組んで、害虫でも見るような険悪な視線を、部下の背中に照射している。ぼくたちが入っていくと、高杉さんは露骨に安堵した表情を浮かべた。
「わざわざすみません」
「いえ」
東海林さんは高杉さんには短く一礼しただけで、すぐに空いているPCに座った。ぼくも隣に座る。21インチのワイドモニターにはEclipseが起動していた。
「バッチのプロジェクトはどれですか?」
「これです」橋本さんが手を伸ばしてマウスを操作した。「『承認くん』の方はその下です」
ぼくは横からのぞきこんだ。どっちのプロジェクトにも、コンパイルエラーを示す赤い×マークのアイコンが表示されている。「承認くん」のプロジェクトの方は、数え切れないほどのパッケージにまたがっているようだ。
「よくも、ここまで被害を広げたもんですね」東海林さんは思わず苦笑した。「プロセス2の実行は何時でしたか?」
「23時です」橋本さんが時計を見た。「あと10分ちょっとです」
「実行にかかる予測は?」
「30分弱の予定です。その後、チェックの時間が30分」
「プロセス2は問題ないんですね?」東海林さんは画面を指して確認した。「これの影響は」
「はい。ただ、プロセス3は必ず24時に実行する必要があります。後のプロセスがずれてくるので」
あと70分だ。
「分かりました。とりあえず『承認くん』のソースを元に戻しましょうか」
「それが……」
「分かってます。このプロジェクトは捨てましょう。今、APサーバにデプロイされているモジュールのソースは?」
「今、ないんです」橋本さんは唇を噛んだ。「warファイルで持ってきたので」
「warファイルの生成時にjavaソースを含める、って指定しなかったんですね?」
東海林さんは確認しただけで、責めている口調ではなかったが、橋本さんはまたもや唇を噛んだ。血がにじんでくるんじゃないかと心配になってくる。
「ああ、わかりました」東海林さんはカバンの中を探って、USBメモリを取り出した。「これに今日の午後時点の最新版のソースが入ってます」
「ちょ、ちょっと待ってください!」高杉さんが甲高い声で割り込んだ。「そういう外部メディアの持ち込みは、事前に申請がいるんですよ」
東海林さんは高杉さんに冷たい視線を送った。
「そうですか。じゃあ、申請方法を教えていただけますか?」
高杉さんはためらった。当たり前のことだが、悠長にそんなことをやっている時間はない。
「ウイルスチェックはしてありますね?」
「もちろんです」
「分かりました。後で許可をもらっておきます」
「そうしてください」
東海林さんは、USBメモリを差し込むと、「承認くん」のプロジェクトを丸ごと圧縮したファイルを読み込み始めた。
ぼくが聞いていたところによると、イニシャルデータ作成バッチは、それ自体は独立したプロジェクトになっているが、ほとんどの処理の実体は「承認くん」の各ロジックを決められた順番でコールする仕組みにすぎないようだった。「承認くん」にはコール用のサーブレットが1つ準備されていて、バッチからはHTTPで実行できる仕組みになっている。
コンパイルエラーだらけになったプロジェクトを、東海林さんは惜しげもなくフォルダごとバッサリ削除すると、ファイルを解凍して、フォルダを再作成した。Eclipse上でプロジェクトを更新すると、数秒でプロジェクトが再ビルド、きれいなプロジェクトが再現された。
「さて、次はバッチの方か」東海林さんはぼくの方を見て、引き抜いたUSBメモリを渡してきた。「おい、お前もそっちのPCでソースを開いておいてくれ」
ぼくはうなずくと、目の前のPCでEclipseを起動した。橋本さんに確認しながら同じ環境を作る。エースシステムのエンジニアが座っているPCに共有フォルダがあり、バッチ処理のソースは、そこがオリジナルになっているらしい。
バッチ処理は、process1、process2、processMain の3つのプロジェクトで構成されていた。
「22時57分です」橋本さんが高杉さんを見た。「プロセス2の準備をします」
高杉さんは不安そうな顔でうなずいた。橋本さんはうなだれている同僚に何か話しかけたが、高杉さんが冷たい声で命令した。
「橋本くん、あなたがやりなさい。宮下は帰っていいわ。明日までに、いえ、今日の9時までに報告書を出しておきなさい」
宮下と呼ばれたエースシステムのエンジニアは、むしろほっとしたような表情で立ち上がり、無言で一礼すると上着を着て部屋を出て行った。
――あの人、どうなるんだろ。
ぼくは退場させられたエンジニアに同情した。正社員を簡単にクビにはできないだろうが、適当な理由をつけた減俸ぐらいは、高杉さんなら平気でやりそうだ。
橋本さんは、明日は我が身か、と思ったのかどうか、気の毒そうに同僚の背中を見送っていたが、高杉さんに促されて、プロセス2の実行準備を始めた。バッチ処理はJUnitで実行する形式になっているようで、橋本さんは引数などを確認していた。
「実行します」橋本さんは宣言し、実行ボタンをクリックした。
たちまちコンソールにLOG4Jの実行ログが表示された。橋本さんは1分ほど見ていたが、電卓を出して何か計算した後、報告した。
「問題ないようです。予定通り、27分ぐらいで終わりそうです」
高杉さんはちらりと時計を見て、ひとつうなずくと、東海林さんに呼びかけた。
「プロセス3の方はどうですか?」
「そうですね……」東海林さんは左手でソースをスクロールしながら、右手でメモを取っている。「……とりあえず業務コードの追加ロジック部分は何とかなりそうですね」
「そうですか。それは良かった」
「ただ、やはり『承認くん』のロジックも、一部修正する必要がありますね」東海林さんは橋本さんを見た。「プロセス2は申請データとマスタのコードとの整合性チェックで、更新や削除の処理はしてませんね?」
ぼくは少し驚いた。東海林さんは何でこんな細かいことを知っているんだろうか。
「そうです」橋本さんは驚く様子もなく答えた。「整合性エラーがあれば、ログに出すだけです」
「細川、テスト環境に申請データのコピーを作ってくれ」
「分かりました」答えたものの、ぼくは躊躇った。「でも、4000万件だと、コピーだけで相当時間がかかるんじゃ……」
「分かってる。だから、1カ月分だけでいい。予備参照年度の4月分だけな」
予備参照年度というのは、「承認くん」に移行するデータの最初の1年分のことだ。正式な申請データとしては、今年度も含めて5年分が有効だが、その1年前も予備として移行することになっていた。
「1カ月分だけなら……」東海林さんはSQLコンソールを出して、素早くselect文を叩いた。「……55万件ちょっとだ。時間はそれほどかからない。ああ、コピーを開始したら教えろ。まだまだやって欲しいことがたくさんあるからな」
ぼくはコピーを始めた。といっても、本番環境とテスト環境のデータベースは、ネットワーク的に直接つながっていないので、少し面倒だった。まず、本番環境の方でcreate table ~ as select ~ で対象範囲の申請データのテーブルを作成する。次にそのテーブルだけをエクスポートし、ダンプファイルを作成。共有フォルダ経由でコピーし、テスト環境の方にインポートする。
「インポート開始しました」
「よし、processMain のプロジェクトを開いてるか?」
「待ってください、今……」ぼくはprocessMain のツリーを展開した。「……開きました」
「batchLogicパッケージの中だ」東海林さんは、自分でも忙しくキーを叩きながら、ぼくに指示した。「BatchMainLogicってのがあるな?」
ぼくは、コンテキストルートから、jp.co.kmotor.shouninkun.batchLogicパッケージの、BatchMainLogic.java を開いた。
「『承認くん』ロジックをコールしている部分が分かるか?」
ソースをスクロールしてみる。「承認くん」のサーブレットを呼んでいるということは、たぶんHttpClient を使っているはずだ。ソース内を検索してみると、callShouninkunLogic() というメソッドの中でHttpClient を使用している。
「ありました」
「よし、いいぞ。じゃあ、そのメソッドを使ってる行を、全部、テキストファイルか何かにコピーしてくれ。Excelがあればそっちの方がいいな」
秀丸エディタか何かあると楽なのに、と思いつつ、メソッド名で検索をかけながら、対象行を地道にコピーすることにした。幸い、Officeは一式インストールされていたので、Excelを起動してコピーした行をセルにペーストしていく。
意外に量があり、やたらとコメントアウト行が多いので、手間取ってしまう。シート上には、
callShouninkunLogic("A01F001", "checkCoverAcceptor", "1,1,1,300,null,null");
callShouninkunLogic("A01F003", "createAcceptRecord", "1,K1,null,null");;
callShouninkunLogic("A01F003", "sendNotificationMail", "300,null,null");
のような一覧がずらりと並んでいった。
全部抽出し終わったのは、橋本さんが「プロセス2終了です。チェックに入ります」と宣言した直後だった。
「できました」
「重複は除いて、共有フォルダに置いてくれ」
ぼくは一度ソートしてから、重複を除き、共有フォルダに保存した。東海林さんは、それを開いた。
「28行か。意外と少ないな。よかった。よし、これからおれが、こいつらを順番に修正していく。たぶん、ほとんどは修正しなくていいか、引数にnullを渡すだけでいいはずだけどな」東海林さんは、そう言いながら、ぼくが作った一覧をプリントアウトした。「そこでお前は、おれが直したモジュールのユニットテストを修正して、さっきコピーしたテストデータでテストしていけ」
ぼくは流しっぱなしだったインポートを確認した。とっくに終わっている。
「分かりました。いつでもどうぞ」
時刻は23時35分。
東海林さんの指がキーボードの上を、ピアニストのように駆け回り、迷う様子もなく修正を開始した。最初の3つを修正するのに2分とかかっていない。ぼくは、共有フォルダに置かれたソースを、自分の環境にコピーしてコンパイルする。コンパイルが終わると、対応するユニットテストにエラーマークが表示されるので、それを修正し、即座に実行する。JUnitのゲージがグリーンで終了したのを確認したら、1つ完了である。
こんな芸当ができるのは、全体を熟知している東海林さんしかいなかった。もしぼくだけだったら、最初から修正を諦めて、新しい業務コードで何も問題が起こらないことを祈る方を選んでしまっただろう。
「チェック完了です」橋本さんが控えめな声で注意を喚起した。「プロセス3の実行予定まで、あと12分です」
「間に合うのですか?」高杉さんの声も焦っている。
東海林さんは2人を無視して、黙々と修正を続けた。すでに始めてしまった以上、後戻りはできない。ぼくも東海林さんにならってユニットテストに専念した。
24個目、ユニットテストが失敗した。
「A04F012失敗です!」自分の声がうわずっているのに気付いたのは、発声した後だった。
東海林さんは小さく舌打ちすると、再度、A04F012のソースを開いた。
「場所は?」
「461行め、ヌルポです」
エラー箇所を確認した東海林さんの指がめまぐるしく動いた。10秒もかからず修正は完了した。
「もう一度頼む」
ぼくは急いで再テストした。今度はグリーンで終了した。
28個目が修正が完了したとき、ぼくは時計を見た。真夜中まであと2分を残していた。
まだ修正したモジュールを、バッチを実行しているPCにコピーし、コンパイルしなければならない。「承認くん」は再起動が必要だ。24:00には間に合わない。
だが、東海林さんは慌てずに訊いた。
「プロセス3終了後のチェック時間は15分でしたか?」
「そうです」焦っているにちがいないが、橋本さんは何とか平常通りの声で答えた。「プロセス3以降は、45分実行、15分チェックのサイクルになります」
「今、そっちに修正版をコピーしたので、プロジェクトを更新してください」東海林さんは冷静に指示した。「更新したらバッチを実行してください。最初の3分ぐらいは件数チェックなので、その間に『承認くん』を再起動してください」
「わ、分かりました」橋本さんは、もう高杉さんの了解を得ようとはしなかった。「プロセス3実行します」
ぼくは固唾をのんで、橋本さんのPCのコンソールを見つめた。もし東海林さんの修正に問題があれば、例外が出るだろう。高杉さんも橋本さんも、爆発するのを怖れているような表情で、モニタを凝視している。
INFO 201x-01-31 23:59:46,546 start process [3]
INFO 201x-01-31 23:59:46,881 checking request count...
実行ログがコンソールに出力された。
ぼくはいつの間にか止めていた呼吸を再開した。とりあえず動き出したようだ。高杉さんも橋本さんも、思わず表情を緩めた。
その途端、コンソールに大量の例外メッセージが表示された。
時計の針がちょうど真夜中を告げていた。
(続く)
この物語はフィクションです。実在する団体名、個人とは一切関係ありません。似たような行動や言動があったとすれば偶然の一致でしかありません。また、特定の技術・製品の優位性などを主張するものではありません。
コメント
プログラマー
>その途端、コンソールに大量の例外メッセージが表示された。
www
こわいこわいこわい。
ヤミ
自分がこの場にいたら、きっと帰りたくてしょうがないでしょうね><
しかし、東海林さん、やっぱり事前にバッチ処理の情報を全部ではないでしょうが、ある程度知っていましたか・・
余裕があったのも納得です・・
elseorand
ん~「大量の例外メッセージ」この正体次第で、深刻度が変わり過ぎるのでちょっと読んでいて反応に困りました。
「ハラハラドキドキ」というよりは、「さ~てユニットテストOKなのに出てくるのは、どんな例外かな~?」という気分でして。
また「大量」がスタックトレースでよく見る数十行程度なのか、ループの中でどんどん例外が生み出されて青天井なのか?
そもそも件数チェック時の例外ということは、
先ほどのデータ移行に問題があったのかな~?と予想しておきます。
旧SE
業務データを私有USBに勝手に入れて相手先PCに言質だけで差すとか後の罠としか思えない・・・
しかもデータ持っていかなければ自社側の責にはならないのにわざわざ悪い方へ飛び込んでいるようにしか見えないんですが
自宅警備兼療養中
本番環境に対して不許可プログラム・データの持ち込み防止するガード対策が人的規則オンリーな貧弱な金額しか掛けられないからできる技かも。
本来の開発環境では取り決められた認証機構つき(+暗号化込みかも)なUSBストレージを取り決めどおり方法で使用するしかない、そのアタッチ/デタッチも管理サーバに記録されているのだろうなと経験に照らして想像する。連載過去回にいちいちその辺は書いていないけど入退室も最低でも一人ずつカード式に管理されているんだろうなあ。基本不許可なメール添付の成果物(プログラムほか)の開発現場宛て転送も特定の運用方法で承認することで切り抜けているはずとかいうのも思い当たるし。
BEL
こないだからメールでソース送ったりUSB使ったりしてたから
情報漏えいでもするのかと思ったらそうではないのかな?
しかし秀逸な文章能力だほんとに
fl
この場合、ソースだけなので、高杉さんも緊急性を考慮して容認したのでしょうね。
もしくは、USBデバイスは、リードオンリーになっているとか。
でも、本番環境で発生したトラブル解決のために、ログを持ち帰ったりすることもあるだろうから、書き込みもできないと困るかな。
miww
なんかUSBメモリの利用規則とか気にしてる人が多いけど、
そもそも当日に修正が必要になったことが発覚したからって
状態確保も無しに修正してる時点で規則とかとっくにぶっちぎられてる。
むしろこの期に及んで申請するとか言ってるだけ頑張ってる方。
だいたい規則を問題にするなら、当日に修正が発生して、バッチ開始までに
修正&テストが間に合わなかった時点で、移行を延期する以外の選択はない。
KCC
> 東海林さんは惜しげもなくフォルダごとバッサリ削除すると
実は消してはいけないものがあったというのが次回への伏線だったりして。
傀儡廻し
少なくとも生体認証は使っていないようだ。
lucy
みなさん細かいところを推測したり議論したりするの好きですよね。
そういう正確があるからシステム屋としてやっていけるのかなと思ったりします。
そのわりに「値引率じゃなくて原価率じゃないの?だとしても原価と売値逆だし」という点の突っ込みがないのはみなさんがここはちょっと書き間違いされただけとしてスルーしているからでしょうか?
前の作品でも考え方についてはいろいろ議論がありましたよね。今回の例外にしても思想の問題でしょうし、あんまりそこに突っ込むと物語が楽しめないかと。
しかし、この東海林さんっていうのはほんとにお人よしですね。火中の栗を好んで拾いにいってるようにしか見えません。高杉さんへの意地もあるんでしょうけどそれにしてはリスクの大きいことやりすぎです。
FIRE
既に次の物語が掲載されていますが・・・
正式な納品(契約に基づいた納品)をしたのか否かは別として、
プログラムソースを勝手に変更して、
ぶっ壊れたから何とかしろ!というのがまかり通っているのは、
なぜなんだろ?と思ってしまいました。
まぁ・・・そんなことを言ってられない状況というのは重々分かるのですが・・・
安定稼動後の金銭のやり取りが物語に含まれるといいなぁ・・・。