ふつーのプログラマです。主に企業内Webシステムの要件定義から保守まで何でもやってる、ふつーのプログラマです。

人形つかい(20) 深夜プラス1

»

 「例外出ました!」

 橋本さんがうわずった声で告げた。

 「細川」対象的に落ち着き払った声で、東海林さんがぼくを呼んだ。「場所は?」

Exception

 「A01F003の193行目です。やっぱりヌルポです」

 東海林さんは素早くソースを開いた。

 「日付計算だな。おい、申請ID出てるか?」

 ぼくはコンソールを見た。スタックトレースの前に、出力されている。

 「出てます」

 「その申請データをselectしてみろ」

 ぼくはSQLコンソールを開くと、select文を叩いた。結果が表示される。

 「申請日付、何になってる?」

 「200x0431です」言い終えてから、異常に気付いた。「え? 4月31日? これ、データ不備じゃ……」

 背後で高杉さんがハッと息を呑む気配があった。

 「やっぱり」東海林さんは猛然とキーを叩き始めた。「その直前で文字列を日付に変換してるが、変換に失敗して、値がnull になってるんだな」

 「変換の時点で例外が出るんじゃないんですか?」

 「いや、例外キャッチしたら、そのままnull を返すようになってるから出ない」

 「なんだそりゃ」呆れたものだ。例外の使い方を完全に間違っている。

 そのとき、それまで黙って聞いていた高杉さんが割り込んだ。

 「そんなふざけた仕様にするとは、どういうつもりですか」声に怒りがにじんでいる。「この責任をどう……」

 「変換してるのは、Aフレの共通メソッドです」

 東海林さんの言葉に、高杉さんは沈黙した。ぼくは、それを横目で見ながら聞いた。

 「どうしますか?」

 「とりあえず申請データはどうしようもないからな。とりあえず、変換後にnull だったら、ログに申請ID出しておいて、そいつはスキップするようにする。処理を継続しないと」

 「今、4月30日に修正してしまったらダメですか?」

 「ダメだ。それが本当は4月30日なのか、4月13日なのか、今は確かめようがないだろ」

 「……そうですね」ぼくは自分の浅はかさを心の中で罵った。「スキップした申請データは?」

 「後でデータを修正してから再度実行だな」東海林さんは高杉さんを無視して、橋本さんを見た。「それでいいでしょうか?」

 高杉さんを無視できない橋本さんは、上司の表情を確認してから同意した。

 「それでやりましょう」橋本さんは時計を見た。「4分ロスしてます。ロジックの修正はできましたか?」

 「今、できました。そっちの共有に置いたので、『承認くん』を再起動して、プロセス3を再実行させてください」

 「すでに何件か動いてしまったんじゃないですか?」ぼくは疑問を呈した。「再実行だと二重に承認データが作成されてしまうんじゃ……」

 「いい質問だな。大丈夫。申請データ1件ごとにcommitされてるから、処理が成功したデータには承認完了フラグが立ってる。processMain は、それを無視するようになってるよ」

 「へえ……」

 「再実行します……」橋本さんが宣言した。「……しました」

 ぼくたちは息を詰めて、コンソールを見守った。実行ログが表示されているが、先ほどは気を緩めた途端に例外が飛び出したのだから、うかつに安心するのが怖い気がする。

 1分ほど無言で注視した後、東海林さんが立ち上がった。

 「しばらくは大丈夫そうですね。ちょっと一服してきます。喫煙室はどこでしょう?」

 高杉さんは「こんな時に」とでも言いたそうに顔をしかめたが、橋本さんが立ち上がった。

 「案内します」

 2人は連れ立って出ていった。高杉さんと2人で残されたぼくは、居心地の悪さをどうやったら表に出さずにいられるか、そればかりを考えながら、ひたすらコンソールを見つめていた。

  INFO  201x-02-01 00:10:36,546 checking count = 2100
  INFO  201x-02-01 00:10:41,610 checking count = 2200
  INFO  201x-02-01 00:10:50,044 checking count = 2300
  INFO  201x-02-01 00:10:51,774 スキップ.shinseiId=410041
  INFO  201x-02-01 00:10:55,125 checking count = 2400

 たまにスキップされているのは、日付が不正なデータだ。ぼくは以前、11月に行われた情報共有ミーティングのことを思い出した。東海林さんが、日付データを文字として扱っていることに懸念を示したにもかかわらず、高杉さんは歯牙にも掛けなかったのだ。

 高杉さんはどう思っているのか少し気になり、さりげなく様子をうかがうと、イライラと時計を見ているだけだった。たぶん、都合の悪いことは記憶に留めないようにしているのだろう。

 東海林さんたちは10分ほどで戻ってきた。東海林さんはバッチの実行状況を確認すると、満足そうにうなずいて元の席に座った。

 次に問題が発生したのは、0時32分だった。

 手持ちぶさたでぼんやりしていたぼくは、橋本さんの「あ!」という叫び声に飛び上がった。

 「また例外です!」

 ぼくはコンソールをのぞき込んだ。

  INFO  201x-02-01 00:32:17,055 checking count = 4812640
  ERROR NullPointer ...

 「内容は?」東海林さんが冷静に訊いた。

 ぼくは例外内容を読み上げた。

 「insertで数値の精度エラーです。nebiki_ritu……値引率ですね」ぼくはSQLコンソールで、エラーが出ているデータを検索してみた。「えーと、原価8000で売値が7500なので、0.9375。これをそのままセットしてますね」

 「ああ、なるほど。確か値引率は小数点3桁だったな」

 「どうします?」

 「そうだな」東海林さんは少し考えた。「小数点4桁にするのは簡単なんだが……影響範囲はどうかな……」

 そのとき、ドアが開き、若い男性が入室してきた。首からかけているのは、ゲストの入館証ではなく、K自動車の社員証だ。真っ先に反応したのは高杉さんだった。

 「大河内さん、お疲れさまです」

 そういえば、以前、K自動車の人たちがエースシステムに来ていたとき、開発室をのぞいていった顔ぶれの中に、この人がいたような気がする。

 「どんな感じですか?」大河内さんは、こいつら誰だっけ?みたいな顔でぼくたちを見た後、高杉さんに視線を戻した。「何か問題でもありましたか?」

 「ええ、若干トラブルが」高杉さんは、内心、感じているに違いない焦燥感を見事に押し隠して微笑んだ。「でも、心配いりません。すぐに解決しますので」

 「そうですか」大河内さんの視線が、またぼくたちに向けられた。「ええと、協力会社の人たちでしたか?」

 「そうです。念のために来てもらいました」高杉さんはそう言うと、東海林さんに聞いた。「それで、どう対処しますか?」

 「そうですね……」

 考えながら答えようとした東海林さんに、高杉さんがかぶせた。

 「テーブルのカラムの定義を変更したらどうですか?」

 ぼくは、そして橋本さんも、思わず高杉さんの顔を凝視した。さきほど東海林さんが言いかけた対応方法だ。

 「この際、それが一番簡単でしょう」高杉さんは、さぞ自分が思いついたような顔で続けた。「影響範囲も少ないでしょうしね。そう思いませんか?」

 東海林さんも、しばしあっけにとられていたが、やがて肩をすくめて、この芝居に付き合った。

 「そうですね。それがいいと思います」

 「では、そのように進めてください」明らかに大河内さんを意識しながら、高杉さんは指示した。

 「わかりました。ところで桁数は何桁に設定しておきますか?」そう聞いたのは、東海林さんのちょっとした意地悪だったのだろう。

 絶句した高杉さんに、東海林さんはすぐ助け船を出した。

 「念のために5桁にしておきますか」

 「ええ、それがいいでしょうね。念のために」

 声が乱れたりしなかったのは、さすがに上級SE様だ。

 「分かりました」

 大河内さんは、そのやりとりを見守っていたが、東海林さんが作業を始めると、納得したようにうなずいた。

 「では、よろしくお願いします。自分の席にいますので、何かあったら連絡してください。また、たまに様子を見に来ますが」

 「おつかれさまです」

 大河内さんが出ていった後、ぼくは懸念していたことを口にした。

 「ひょっとして5桁でも足りなくなるかもしれないんじゃ……」

 「わかってる。急いで値引率チェック用のロジック作ってくれ」

 「わかりました……だけど、その間、バッチは止めたままにしとくんですか?」

 「そうじゃない。ちょっと待て」東海林さんはALTER TABLE文を実行すると、橋本さんに呼びかけた。「再実行してください」

 橋本さんがバッチを再実行し、再び、実行ログが表示されていくのを確認して、東海林さんはぼくに注意を戻した。

 「お前に作ってほしいのは、全申請データに対して、値引率のチェックだけをひたすら行う独立したロジックだよ。データベースへの更新はしないから、トランザクション制御もいらない。申請データを1件読んで、値引率チェックを行って、小数点以下の桁数だけチェックする。もし5桁を超えるような申請データがあれば、ログに出しておく」

 「なるほど」

 「できたら、そっちのPCで実行してくれ。次の年度からでいいからな」

 「つまり先行してチェックだけするわけですか」

 「そういうこと」

 それぐらいなら、すぐに作成できるだろう。ぼくは新しいユニットテストを作成し、言われた通りのチェック用ロジックを作り始めた。

 「そろそろプロセス3が終わりますね」橋本さんがつぶやいた。「以降のプロセスは何事もないといいんですが」

 もちろん、何事もなく終わるはずがなかった。

 (続く)

 この物語はフィクションです。実在する団体名、個人とは一切関係ありません。似たような行動や言動があったとすれば偶然の一致でしかありません。また、特定の技術・製品の優位性などを主張するものではありません。

Comment(21)

コメント

ヤミ

うーん、エラーの2点とも最低限本番前にチェックすべき内容なのに、チェックしていなかったんですね^^;
はたして何を元に大丈夫と思って当日を迎えたんでしょうか?
まあ、高杉さんならしょうがないのかな・・

ほまらら

明確になっていない何かを放置すると、
絶対にそこでバグが起こるんですよね。
天網恢恢疎にして漏らさずというのか。
プログラマは、目を逸らした物から必ず報いを受ける・・・。

elseorand

このフレームワーク側の日付処理という根本的な障害なら、
フレームワーク自体を直さないことには、
「本番稼働後にフレームワークの修正」という地獄が待っているのに、
高杉はそこいらへん見えてないのでしょうかね?
またフレームワークの放置をすると、
今後も実装する際には常に気をつけなければならない楔にもなるのに。

今のままにしても日付処理にバグを抱えたフレームワークに、
それをカバーするパッチを処理側に当てた形で、
これから運用していくわけですね。
しかも小数の端数処理についてルールが決まっていないと。

保守・運用フェーズが地獄ですね。
そうなると主人公二人も、このシステムからそうそう抜け出せなくなりそうですが・・・・

レモンT

この展開は予想していませんでした!……タイトルが(笑)。いや、東海林さんがすっかり『プロフェッショナル』(ライアル的な)になってしまいましたね。そのうち『リアリストは金のために闘う』とかつぶやきだしそうです。もしかして最初の頃は、細川君に経験を積ませるためにわざと最小限しか介入しなかったのか知らん。でもまあ、次回タイトルが『最も危険なゲーム』とかじゃないことを祈っております(にしてもハヤカワは、何時になったらランクリン大尉シリーズの2~4巻を文庫に落してくれるんでしょうねえ)。

 しかしまあ、日付を文字列型で扱うこと自体を全面的に否定はしませんが(実際業務によっては必要になるケースもありますし……電子申請システムでは無用の長物ですが)、だったら想定される穴くらいちゃんと事前に塞いでおけというかなんというか。普通有識者レビューで指摘出るだろうに。

BEL

おおお、10話目の会議の「なぜ日付をstringで」のくだりはここへの伏線だったのか!

エラー出力画像とかリアルすぎますw

>「なんだそりゃ」呆れたものだ。例外の使い方を完全に間違っている。
これは激しく同意というやつです。例外を勝手に握りつぶさないでほしい。
共通のモジュールに限ってこういうことやってる場合が多いから困る。

第一、元のフレームワーク(javaならjava,.NETなら.NETの)の劣化コピー作っても意味がない。そいうのが多いこと多いこと。

しかし、東海林さん、怒りっぽい人だなと思ってたら急に神がかったようなキャラになっちゃった。

kyutyan

「この責任をどう……」って、
高杉さん、障害が発生したら誰かに即座に責任転嫁させる気満々ですね・・
東海林さんはそこらへん読んで、できる限りのことはやったというポーズを見せるために、かなり踏み込んだところまで作業をやろうとしているのですかね。

Jitta

>  「この際、それが一番簡単でしょう」高杉さんは、さぞ自分が思いついたような顔で続けた。「影響範囲も少ないでしょうしね。そう思いませんか?」

 伏線?プログラム ロジック的には何もないけど、ワークフローとして何かありそうな...

takachan

東海林ってバカじゃないのか?
おまえらって初期値作成バッチの担当じゃねーんだろ?
そこまでやる必要ないだろ。
こういう奴は一生人から使われる存在だな。

sakuya

うーん。値引率が循環小数とかになっちゃったらどうするんですかね…。

まりも

日付を文字列で受け取って、オブジェクトで返すメソッドで。
変換文字列の場合はnullを返すってそんなにおかしな挙動でしょうか?

それを例外を握りつぶすってのはちょっと言いすぎなような。
それで握りつぶすと言われたら、ライブラリでは全く例外処理ができないことになる。

Javaはあつかったことがないのですが。
検査例外とかあると聞くので特殊なのだろうか。

仕様にnullを返すと書いてなかったのが問題というなら、
それはそうですけどね。
握りつぶすのとは話が別。

hiro

>>変換してるのは、Aフレの共通メソッドです
共通メソッドならば素直にエラーを吐いて止めるか、最悪nullにするにしてもアラートログを出して欲しい所です。
こいつが例外をスルーしたがために、別の箇所でエラーが出て余計な原因調査が必要になりました。
もし登録側がnullも受け入れる仕様だったら、日付データは勝手に削除されたまま最後までエラーも出ないことになります。
運用開始後にそのnullのせいでコンソールでエラーが出るかも知れませんし
それすらも無く、随分後までデータが消えていることに気が付かないかも知れません。

まりも

文字列を日付に変換するときに、
変換できない変な文字列がある可能性というのは、
そんなにありえない話ではないですよね?

画面入力の値を変換したいかもしれませんし、
データベースの値にしても、
日付が文字列で登録されている以上、
変な値が入ってないかのチェックは普通は必須でしょう。

データベース投入時に、
日付じゃないデータは絶対に入らない仕様になっている場合もあるでしょうが、
そうとは限りませんし、
実際今回は変なデータが入っていたのですからそういう場合じゃないわけです。

つまり、たいていの場合は、
ifで分岐して文字列が変な値な時の処理を書く必要があるわけで、
そういう場合に使う共通メソッドの仕様としては、
nullを返すのがよいのではないでしょうか。

例外を「握りつぶ」さないメソッドだと、
メソッド呼び出しをいちいちtry-catchで囲まないといけなくなります。
Javaではそれが普通なのだろうか、とググってみたら、そうでもないみたいですし。

ひまひま

>>まりも

Batchだから、間違った日付入れたらダメ。(当然、可能性としても許してはダメ)
まず、Batch処理は基本データをまとめて一括で処理するから、通常のシステムでは処理の最後にやる。
つまり、Batchが動くとシステムの要件が変わることになる。
例としては、受注システム→発注システムに業務が切り替わるときとかに動く。
受注の際に、4/31の受注に関して商品なんて発注できないでしょ。
だから、Batchが動くシステムではデータに不整合が存在しないことが大前提。
今回のケースだとデータを扱うDBに不整合が起きやすい状態にしていること自体が間違い。
当然、不整合がおきたデータは調査がいるし、お客さんの確認もいる。
最悪、高杉さんやエースシステムはお客さんに4/31のデータを見せて確認をしなくちゃならない。
俺なら、怖くてやれない。

まりも

>ひまひまさん

いやその辺はある程度分かっているのですが。

ただ、Aフレの共通メソッドがバッチ専用でない限りは、
そういうバッチの常識に特化した設計にしておくわけにはいきませんよね?
という話です。

へろへろ

まあ確かに、Aフレの手引書なりJava Docなりなんなりに、「できなかったらnullを返すよ」とかいてあるなら、そんなにおかしくはないと、私も思いますね。
メソッドに渡す値の妥当性は渡す側の責任、リターンの検証は呼び出し元の責任と考えれば、呼び出すごとにtry catchでもif elseもありかと。
あと、つくり次第ではありますけど、フレームワーク側でダウンされると常用しているログにエラーが出ず、さらにフレームワーク側のログを見ることを思いつかないと原因が思いつかずに復旧が遅れるということも……。(経験談)

BEL

仕様書なり設計書なりに「日付に変換できない場合はnullを返す」と書いてあれば
nullを返して全く問題ないです。というかそうしないとだめですよね。

私がダメだと思ってるのはもっと一般的な話で
「例外キャッチしたら、そのままnull を返すようになってる」ことです。
細川君の(著者の)感想「例外の使い方を完全に間違っている。」そのままです。

もしこのメソッドの戻り値がvoidだったらどうしてたんだろう。

実際にメソッド丸ごとtryで囲んでcatchしたらログだけ書いてそのまま実行を
続けるという実装を目にしたことがありますが、それでは困ります。

nullを返す場合でも、それをオブジェクトに入れるだけではエラーにならないので
そのインスタンスメソッドを実行したときなどに初めてエラーになる。
本来なら有益なエラーログが書けたはずなのに実際に書かれるのはnull参照例外のみ。
みたいな感じで不具合の特定が難しくなることがあります。

まいった

上級者気取りの何でも例外で返すバカをどうにかして

K

私はどちらかというと高杉さんに近い立場の人でして、物語なので高杉さんはちょっとすごすぎですが、主人公とは違う立場から見た事情なども想像したりして毎週楽しく読んでいます。といっても、私は外国企業で海外勤務なので若干どまどっているところもあります。
高杉さんが東海林さんのことあんまりよく思っていないという設定を置いとけば、土壇場でこういう活躍ができるサードアイは発注側にとって非常にありがたい存在。サードアイは当面受注に困ることないだろうし(私なら相当高い単価でも発注したい!)、言わば東海林さん個人能力が買われて受注されるのならサードアイは本来東海林さんに高待遇をすべきところ。(私の感覚では年収800万は堅い) 
でも現実にはきっと東海林さんはこれからも低待遇できつい仕事をつづけるのしょう。(そのうち家庭からはうらまれ、体にもがたがきたりして。。) やっぱり東海林さんのような存在が、細川さんほか大多数の従業員の分を支えてあげないと日本企業は成り立たないのでしょうか??

BEL

ありがたい存在というか、K自動車のような会社が
「次からあの会社(この場合はサードアイ)と直接契約した方がいいじゃん」て
思ったらマージンとって仕事してる会社(この場合エースシステム)としては
脅威ですよね。実際1社多く通すより安いだろうし。
サードアイなら営業もいて、要件定義・仕様策定くらいちゃんとできそうだし。
(実際高杉さんの会社はそこらへんに不備があったわけで、、)
なので次回の高杉さんのように「あくまでも技術面含めてウチが指揮・決定
してます」的な態度を強調せざるを得なくなる

K

その通りだと思います。

ただ現実的には、K自動車規模の会社だと多少のコスト軽減よりもリスク回避を重視するでしょうから、規模の大きなプロジェクトでK自動車が無名企業のサードアイに直接発注するのは難しいと思います。大手企業の場合、新規業者に発注するには社内審査が必要なこともありますし、承認権限のある上長(現場の状況をあまり理解していないことが多い)に、無名のサードアイへの発注の安全性を説得するのは骨の折れる割に担当には見返りの少ない提案です。いざとなったときの企業体力や過去の実績も重要です。加えてサードアイ躍進のためには、少なくとも大河内さんにエースの無能ぶりとサードアイの優秀さを理解しれもらわなければなりません。大河内さんと接触できる非常に少ないチャンスのなか、エースとの関係にも配慮しつつこのようなアピールができるようなしたたかさを持っているようなら、東海林さんは高杉さんにも嫌われていないと思います。

それはさておき、私の関心事としては、もしサードアイがK自動車や大規模な案件を直接発注を受けるような立場になった場合、東海林さんは高杉さん同様年収1000万(私の感覚では年収1000万はむしろ少ないと思いますが)もらえるのかどうかです。実力のある方が、相応の報酬とポジションをもらって、顧客を満足させ、会社に利益をもたらし、プロジェクトチームにゆとりをもたらし、ご家族も円満なんて状況になることを切に望みます。もしそうならないならば、なにが問題なのでしょうか?

まりも

ひょっとして、変換できない以外の理由で例外が出ても、
いっしょくたにnullを返すロジックなのでしょうか。

それならまずいですね。

コメントを投稿する