今更の議論

まさか仕事中に、検査例外と非検査例外の議論が出るとは思わなかった。
監視用ログに出力されていないエラーが存在し、エラーログのみに出力される例外が存在し、それがRuntimeExceptionを継承した例外クラスだったから、RuntimeExceptionがいけないんだと。
いや、それ、単に例外のキャッチ方針と監視用ログへの出し方の問題でしょ。いくら監視用ログへ出力する内容を精査したいからって、業務APで細やかにハンドリングした結果、Catchが漏れたルート存在したから、RuntimeExceptionが悪いって、短絡過ぎる議論だったので、検査例外がJava言語の失敗の一つという結論は10年前には出ましたし、事実、Java以外では検査例外は実装されていません、と一言(嘘、二言)で一蹴しておいた。(もちろん、本心ではそんなことは思っていないが、まま仕方なし。)

ところで、11月から上司が変わったのだが、エンタープライズな開発にJavaは向いていないという点で、その上司と意気投合してしまった。かと言って、新しい言語を作っても、会社から爪弾きにされる(過去事例あり)し、どうしたものかねと会話をしていた。システム開発って、複雑なようでシンプルで、一部の機能を除いて、複雑な機能は必要ない。
例えばコレクションに関して言うと、ぶっちゃけ、ListとMap、さらにはArrayListとHashMapばかりで、それ以外は利用してなくね?さらに、全体の半分はBean系ではないかと思わせるぐらい、無駄にBean系クラスが多い。なので、最近は、開発規模が500KSと言われても、実際に意味のあるビジネスロジックは200KS相当と考えるようにしている。
と考えれば、ビジネスロジックを抽象化して記述する方法と、それらが利用するライブラリ群やそれらを利用するフレームワーク群をJavaで書くみたいな感じができると嬉しい。

突貫マネジメント

はたまたトラブルシュート案件です。

先週中旬ごろより、第三者という立場で問題PJに監査的に関わっていたのですが、クリスマス休暇3日間を対策検討に費やしていたら、なぜか今週の月曜日のお客様説明資料内の体制図でチームを持つことになっており、その担当範囲が、1月中旬までに通信ライブラリ(6KS)を仕上げるというモノでした。

さらに、チームはまだ結成されておらず、26日時点では、自分の部下1名だけを連れて、参戦です。他のチームメンバは、1月4日〜5日に合流するという形です。
全員集まると、私を含めて8名体制。部下1名以外は全員初対面。
突貫でチームビルドを行い、6KSを仕上げ、単体試験、結合試験を乗りきって、1月中旬の業務結合試験に間に合わせる必要があるという。。。

さて、こんな突貫マネジメントの経験は初めてで、何をどうしたら良いのやらということで、1月4日初日から設計・製造に入れるよう、いま、準備をしています。

  • 社内説明用開発方針資料
  • チーム向けキックオフ資料
  • スケジュール策定と成果物定義、タスク別の工数見積もり
  • メンバに対するタスクアサイ
  • 設計実施方針、製造実施方針、試験実施方針、品質評価・判定方針
  • 成果物管理ルール
  • チーム内のコミュニケーションルール
  • 各種課題の事前検討と他チームへの依頼
  • 居室と座席とPCの手配、入用な備品の手配、生活空間の改善
  • 1機能限定でのプロトタイプ開発と工数の妥当性検証

と、1/4までに準備して、PM層に説明し、何かあっても責任を取ってもらえる準備を行う必要があります。
(まだクビにはなりたくないので、最優先事項です。)

いや〜 この突貫マネジメントをやりきれたら、アーキテクト止めて、PMでもご飯食べていけるんじゃね?と思ってみたり、みなかったり。

なお、昨今の長時間労働等の労務管理に対する風当たりの強さもあり、当然、営業日オンリー&1日6時間(2時間はバッファ)で作業見積もりしたスケジュールを組んでますよ。そのために、かなりお高くつきましたが、エース級PG1名、準エース級PG2名を、さらに自由に動かせて瞬発力の高い若手3名、最も信頼できる部下1名を1ヵ月限定で他PJから引き抜いてきました。(上位マネジメント層には感謝。)

さらに、労務管理の緩い管理職2名(部長)の協力を取り付け、休みの日にも関わらず、準備ができた所から順次RVを頂いている状態です。今日はWBSを見てもらいましたが、凄い五月雨線表に、マネジメント層が全員絶句してました。そりゃそうですよ。1月4日からの2週間分を全て時間単位でスケジュールを立ててますから。しかも、全タスクについて、想定作業量を想定項目数をベースに算出しているので、なんかやれそうな気がしてくるというWBSです。

とは言え、初めての突貫マネジメントなので、とにかく怖い。。。

最後は、私と部長×2名の3名で、往年の突貫プログラミングを行わないといけないかもと、冗談交じりに話はしていましたが、とにかく突貫ばかりです。とりあえず、部長には正月明けの3連休は空けておいてくださいとお願いしておきました。

あと1ヵ月早く開発を決定できていたら、どんだけ楽だったか。。。

ちなみに、私は明日が仕事納めの予定です。一応、管理職も連続勤務だけは意識しろと言われており、明日30日で12日目なので、31日はお休みを貰おうかと。

Java + Windows の Socket 通信

Java + WindowsにてSocket通信を行うAPの開発が必要となったので、実験メモ。

要件

  1. サーバとクライアントは同一サーバで、windowsである
  2. プログラムは、Javaで開発する
サーバ側要件
  1. 待ち行列を制御したい
  2. タイムアウト済みのクライアントとの通信は、即時に無効を検知したい。
  3. 待ち行列の制御をAPで行いたくないので、待ち行列バックログだけで管理するためにサーバ側はシングルスレッドで処理したい
クライアント側要件
  1. 一定時間待ち行列上に存在した場合は、クライアントは依頼を送信せずに、処理を諦めたい
  2. クライアントにて異常と判断した場合は、可能な限りサーバ側にて処理が行われないようにしたい
  3. サーバに依頼した処理が仕掛ってしまった場合は、処理の中断はあきらめるものの、サーバ側に諦めたことを伝えたい

普通はほとんどありえない要件ですが、今回ばかりは特別な事情ということで…

プロトコル(1)

  1. 接続: クライアント#connect -> サーバ#accept
  2. 要求: クライアント#send -> サーバ#recv
  3. 結果: クライアント#recv <- サーバ#send
  4. 切断: クライアント#close , サーバ#close

なお、recvのタイムアウトを5秒とする。以降、xx秒経過を(xx)と表現。

検討/実験(1−A)

backlogに滞留しているケース。

<クライアント側の状況>

  1. 接続(00): クライアント#connect -> OK
  2. 要求(00): クライアント#send -> OK
  3. 結果(05): クライアント#recv -> Timeoutエラー
  4. 切断(05): クライアント#close -> OK

これでは、送信した依頼はまだ実行されずにタイムアウトしたのか、それともサーバ側の処理時間が長くてタイムアウトしたのかが分からない。
というのも、syn ⇒ syn/ack ⇒ ackの流れは、ServerSocket#bind(listen)すると、OS側で自動で行われるため、クライアント側のconnectタイムアウトでは、サーバ側のaccept前でのタイムアウトか、accept後でのタイムアウトかを判定できない。
しかも、send/flushは成功している以上、サーバ側に依頼を受け取って貰えたように見える。
だが、処理結果は受信できなかったため、依頼は失敗したとして、クライアント側の処理を継続する必要がある。

<サーバ側の状況>

  1. 接続(10): サーバ#accept -> OK
  2. 要求(10): サーバ#recv -> OK
  3. 結果(10): サーバ#send -> OK
  4. 切断(10): サーバ#close -> OK

クライアントからのacceptに成功し、依頼を受信したので、処理を実行し、結果を応答できた。すばらしい。

<結果>
クライアントは処理を失敗として扱い、さらに、サーバ側で処理してしまったかどうかが判断できない。サーバ側は処理を成功として扱った。結果、クライアントとサーバ間では、状態の不整合が発生する。これでは、よろしくない。

プロトコル(2)

  1. 接続: クライアント#connect -> サーバ#accept
  2. 確認: クライアント#recv <- サーバ#send
  3. 要求: クライアント#send -> サーバ#recv
  4. 結果: クライアント#recv <- サーバ#send
  5. 切断: クライアント#close , サーバ#close
検討/実験(2−A)

backlogに滞留しているケース。

<クライアント側の状況>

  1. 接続(00): クライアント#connect -> OK
  2. 確認(05): クライアント#recv -> Timeoutエラー
  3. 要求(--): クライアント#send -> skip
  4. 結果(--): クライアント#recv -> skip
  5. 切断(05): クライアント#close -> OK

とりあえず、要求を送信していないので、サーバ側で処理していないということは確実に判定できる。すばらしい。

<サーバ側の状況>

  1. 接続(10): サーバ#accept -> OK
  2. 確認(10): サーバ#send -> OK
  3. 要求(10): サーバ#recv -> 即時エラー
  4. 結果(--): サーバ#send -> skip
  5. 切断(10): サーバ#close -> OK

要求を受信できなかったので、とりあえず、クライアント側は諦めたと考えてよいだろう。すばらしい。

<結果>
クライアント側も、サーバ側も、お互いに処理を実行していないと判断できるため、状態の不整合は発生しない。すばらしい。

検討/実験(2−B)

処理遅延が発生したケース。

<クライアント側の状況>

  1. 接続(00): クライアント#connect -> OK
  2. 確認(00): クライアント#recv -> OK
  3. 要求(00): クライアント#send -> OK
  4. 結果(05): クライアント#recv -> Timeoutエラー
  5. 切断(05): クライアント#close -> OK

要求は送信できたが、結果受信をタイムアウトしてしまった。

<サーバ側の状況>

  1. 接続(00): サーバ#accept -> OK
  2. 確認(00): サーバ#send -> OK
  3. 要求(00): サーバ#recv -> OK
  4. 結果(10): サーバ#send -> OK
  5. 切断(10): サーバ#close -> OK

要求を受信できなかったし、結果を返すこともできたので、きっと、クライアントは正常に処理できたのだろう。すばらしい。

<結果>
クライアントは処理を失敗として扱い、サーバ側は処理を成功として暑かった。結果、クライアントとサーバ間では、状態の不整合が発生する。これでは、よろしくない。

プロトコル(3)

  1. 設定: クライアント#Linger(true, 0s)
  2. 接続: クライアント#connect -> サーバ#accept
  3. 確認: クライアント#recv <- サーバ#send
  4. 要求: クライアント#send -> サーバ#recv
  5. 結果: クライアント#recv <- サーバ#send
  6. 切断: クライアント#close , サーバ#close
検討/実験(3−A)

backlogに滞留しているケース。

<クライアント側の状況>

  1. 設定(00): クライアント#Linger(true, 0) -> OK
  2. 接続(00): クライアント#connect -> OK
  3. 確認(05): クライアント#recv -> Timeoutエラー
  4. 要求(--): クライアント#send -> skip
  5. 結果(--): クライアント#recv -> skip
  6. 切断(05): クライアント#close -> OK

とりあえず、要求を送信していないので、サーバ側で処理していないということは確実に判定できる。すばらしい。

<サーバ側の状況>

  1. 接続(10): サーバ#accept -> OK
  2. 確認(10): サーバ#send -> 即時エラー
  3. 要求(10): サーバ#recv -> skip
  4. 結果(--): サーバ#send -> skip
  5. 切断(10): サーバ#close -> OK

確認の送信に失敗したので、とりあえず、クライアント側は諦めたと考えてよいだろう。すばらしい。

<結果>
クライアント側も、サーバ側も、お互いに処理を実行していないと判断できるため、状態の不整合は発生しない。すばらしい。

検討/実験(3−B)

処理遅延が発生したケース。

<クライアント側の状況>

  1. 設定(00): クライアント#Linger(true, 0) -> OK
  2. 接続(00): クライアント#connect -> OK
  3. 確認(00): クライアント#recv -> OK
  4. 要求(00): クライアント#send -> OK
  5. 結果(05): クライアント#recv -> Timeoutエラー
  6. 切断(05): クライアント#close -> OK

要求は送信できたが、結果受信をタイムアウトしてしまった。

<サーバ側の状況>

  1. 接続(00): サーバ#accept -> OK
  2. 確認(00): サーバ#send -> OK
  3. 要求(00): サーバ#recv -> OK
  4. 結果(10): サーバ#send -> 即時エラー
  5. 切断(10): サーバ#close -> OK

結果の送信に失敗したので、とりあえず、クライアント側は諦めたと考えてよいだろう。だが、処理は行ってしまった。

<結果>
クライアント側はサーバ側にて処理が行われたかどうかは分からないものの、サーバ側もクライアントに結果を通知できなかったため、お互いが依頼をなかったことに(ロールバック)できれば、状態に相違は発生しない。まあ、良いかな。

まとめ

今回の条件である、同一サーバ内でのソケットを利用したプロセス間通信であり、サーバがwindowsであり、APがJavaで書かれているようなケースにおいては、リスクを最小限にするために、SoLinger(true,0)をしつつ、サーバからの接続確認の送信から始めるようにすれば、そこそこのプロトコルができそうである。
ただ、絶妙なタイミングでの障害の場合の検証は行えていないのと、検証そのものが難しいので、とりあえず、今回はこの設計で頑張ってみましょう。

禁酒(7日目)

よし、1週間乗り切った。
次の難関は、7月11日の祝賀会。
その次は、7月20日の定期集会。
さらにその次は、7月22日の壮行会。
さらにまたその次は、8月3日の長岡花火。
絶対に乗り切るぜ。

38.5度の発熱中

昨日軽く飲んだところ、目が覚めたら二日酔いで体調が悪い。
昼過ぎても体調が戻らず、打ち合わせのために別ビルに行く途中で一時帰宅。体温を測ると38.5と出る。

体の節々も痛いことから、お休みをいただきつつ、病院へ。今までは会社近くの大学病院付属のクリニックに通ってたが、そこがなくなってしまったので、家の近くの内科に行く。受付を済ませて問診票を書くが、体温測定がない。自己申告である。その後、医師による問診となるが、下痢の症状に着目し、胃腸炎と診断しようとするも、おなかをトントンしても痛みはなく、腫れも少なく、医師は首を傾げるばかり。ただ、それでも多少腫れていることから、胃腸炎と診断しようとしていたので、インフルエンザのチェックだけお願いしますと伝えると、症状的にありえないと言われる。発熱・悪寒・節々の痛みが出ているのに、下痢の症状だけをピックアップして、ありえないと言う。職場ではまだときどき発症者が出ていることを伝え、チェックだけするも陰性。さすがに発熱して半日経過していないので、結局分からんと言われ、分かりましたとだけ伝えて、お金払って出てきた。

インターネットを見ると、病気と症状の情報はいくらでも出てくる。それらをしっかりと吟味することで、ある程度、患者側でも病気の推測は可能な時代だ。とは言え、素人判断に過ぎないのも事実であるため、そういう情報を頭に入れた状態で、病院に行く。これまでは、大学病院付属クリニックということで、診察の時間こそ短いものの、診断結果は的確だったと思っている。(と言っても、年に1〜2回ぐらいしかお世話にならなかったけど。)また、二日酔い以外で体調不良になることは少ないので、本当に体調が悪い時は、産業医とかにも相談したりしている。正直、風邪とかそういうどうでも良い病気以外の少し深刻な体調不良は、会社側には入社してから10年以上の健康診断の結果が残っているので、下手な医師にかかるより、産業医に相談した方が、的確な結論が得られやすい。結果、人間ドッグは問題なしの判定なのに、禁酒をさせられたことも。これも、時系列でデータをしっかりとチェックできる産業医のなせる判断なのだと思う。

で、今日の体たらくである。大学病院付属のクリニックが無くなってしまった以上、風邪等については、どこかの内科・呼吸器科あたりの病院に定住したいのだが、少なくとも、今後、今日の病院に通うことはもうないかなと思った。