はじめに
米田です。
先日、1年務めた欠陥対応現場から異動し、バッチ設計案件に参画することになりました。
今回は、異動してからの1か月について、ゆるく振り返ってみようと思います。
私について
・21歳、2年目の駆け出しエンジニア
・Javaの業務系システムの欠陥対応チームで実装・テストを担当
・実務での設計経験なし
業務内容
主な担当業務は、バッチ機能の設計見直しです。
STフェーズで見つかった根本的な不具合に対し、既存の実装をなるべく保ったままで再設計することが今回の方針でした。
スポット参戦だったため、問題のヒアリングや仕様の理解、仕事の進め方を短期間で決めていく必要がありました。
大変だったこと
・そもそも用語を知らない
ヒアリングや方針会議において、「外部API」や「REST通信」、「ジョブ・ジョブネット」など、今まで触れてこなかった技術用語がたくさん飛び交いました。
現行仕様や不具合原因の理解には、上記技術への理解が前提となるため、短時間でキャッチアップする必要がありました。
関連技術を一通り学んだうえで、不具合原因を理解し、設計方針に納得するところまでを数日で終えなければいけなかったため、ひたすら脳をフル回転させていました。
・設計もやったことない
先述した通り、設計工程自体が初挑戦でした。
しかし、スケジュールが過酷で、設計の進め方を教わる時間が取れない状況でした。そのため、上司の成果物から進め方を読み取り、担当バッチの設計をこなさなければなりませんでした。
「設計の進め方の理解」と「現行仕様の理解」を同時に行うのは本当に大変で、帰りの電車ではSNSを見る余力も残っていませんでした。
(余談ですが、自分が担当したバッチは設計書が古く実装と大きく乖離していたため、ソースを読みながら仕様理解を進める必要がありました…)
・プレッシャーがすごい
上記の状況の中で、担当分のバッチの設計を納期内に終わらせる必要がありました。
ベテランに交じり、担当分を自走してこなさなければならないというプレッシャーは、社会人生活で一番大きなものでした。今回は実装担当の方が別にいたこともあり、感じる責任は想像以上でした、、
最初の1週間は、家に帰ってからも不安でいっぱいだったことを覚えています。笑
よかったこと
・設計の進め方を学ぶことができた
実際に設計工程を担当してみて、考慮しなければいけないことの多さに驚きました。特に今回は、仕様を保ったままで不具合を解消できる方法を考えなければならず、常に頭がいっぱいでした。
そこで、脳内を全てアウトプットして整理し、対処法を明確にしてから順番に処理する 進め方に変えてみました。
具体的には、
・「整合性が保てるか不安」くらいのざっくりとした懸念を書く
・書き出したものは頭から消し、「どうして整合性が保てないと思うのか」にスポットを当てて書き出す
・再びリセットし、上記で洗い出したもの(DBの相互利用など)の調査を行う
といった感じです。
これが、思考効率に大きく影響しました。
脳内でぼんやり絡まっていたものがほどけ、一つ一つに脳のリソースを集中できるようになった のが大きいかなと思っています。
この手法は、今後の仕事や私生活でも活かせそうだなと感じています。
・社会人として成長できた
片道1.5時間のオフィスにフル出社し、初めてのことに挑戦し、責任を背負う。
今までとは真逆のハードな環境下での仕事は、精神的にも肉体的にもきつかったです。
ただ、今振り返ってみると、SEを続けていくうえで必要な経験だったのかなと感じます。
まだ2年目ですが、いずれは下につく人が増え、裁量も増えていくと思います。
プレッシャーとうまく向き合いながら乗りこなしていく経験を通して、社会人として大きく成長できたと実感しています。
現場で学んだ技術
用語編
-バッチ処理
大量のデータを一時的に蓄積し、後からまとめて処理する方式を「バッチ処理」と呼びます。
対になる言葉として、データをリアルタイムに処理する「オンライン処理」があります。
例えばPOSシステム。
店頭での商品購入時の代金計算や在庫反映は、リアルタイムなオンライン処理で処理。
一方、商品の大量発注があった場合には、いったん発注データを処理せずに蓄積し、バッチ処理でまとめて計算や反映を行うといった使い分けです。
バッチ処理は 「システム稼働中にサーバ負荷をかけない・性能影響を与えないこと」 が目的のため、リアルタイムでなくてよい処理は基本バッチ処理に回します。
また、上記理由から、バッチ処理は日中のシステム本稼働時間以外の時間に実施することが求められます。
そのため、システム稼働時間外に確実に処理を終了できるよう、ジョブの多重化・並列化による処理時間の短縮も考慮する必要があります。
-ジョブ
バッチ処理を構成する個々の処理単位を「ジョブ」と呼びます。
例えば、「商品受注バッチ」は、次のようなジョブで構成します。
・注文の合計金額を計算する「代金計算ジョブ」
・商品の在庫を確認する「在庫確認ジョブ」
・受注データをDBに登録する「受注登録ジョブ」
このように、バッチ処理は通常複数のジョブで構成され、設定された実行順序や条件で実行されます。
この実行順序や条件を工夫することで、バッチ単位での実行時間の短縮につながります。
-JP1
JP1は、バッチ処理などの運用を管理できるソフトウェアです。
バッチの実行タイミングや実行順序、条件などを設定し、処理を自動化できます。
ノウハウ編
バッチ設計時に検討すべきこと
-ジョブ間のデータ連携方法
ジョブの処理結果を後続ジョブで利用する場合、何らかの方法で後続連携する必要があります。代表的な連携方法として、「DB連携」と「ファイル連携」があります。
DB連携
後続に渡したい情報を記録するためのエンティティを用意し、そこに処理結果を書き込むことで後続で参照できるようにする連携方法です。
ファイル連携
ジョブ終了時に連携したい情報を外部ファイル(csvやjson)として出力し、後続で読み込むことで情報を連携する方法です。
どちらの方法でも、連係情報構成の設計、保持期間・削除方針に関してすり合わせるといった作業が必要です。
-エラーハンドリング
バッチ設計では、ジョブ処理中の例外発生時の対方針応も検討が必要です。自動再実行、処理の中断・終了、対象データのスキップによる後続ジョブの継続実行など、関係者と要件をすり合わせて方針を決定します。
-ログ構成
バッチ処理で何か不具合が起こった際の調査に使用するのが出力ログです。
出力ログ構成の設計では、不具合箇所やレコードの特定に必要な項目を検討し、性能とのバランスを考慮しながら十分な情報を盛り込むなど、「何を」「どの単位で」出力するか を意識して設計します。
-ジョブ構成(リカバリ可能、性能意識(多重化・並列化))
バッチ処理は、正確かつ短い時間での処理完了が必須です。
そのためには、バッチを構成するジョブの適切な切り分けや、実行順序の適切な設定が欠かせません。
特に意識すべき点は、ジョブ同士の依存関係です。
例えば、userエンティティを参照するAジョブと、userエンティティを更新するBジョブがあった場合、この2ジョブの実行順序を入れ替えることはできません。
一方、masterエンティティを参照するCエンティティは、Aジョブ・Bジョブとは独立しているため、並列で実行することが可能です(ただし、処理の依存関係がない場合に限ります)。
このように、仕様を保ったままで適切に並列化できるようなジョブ分割・構成を意識することが重要です。
また、データリカバリについても考慮が必要です。
例えば、API A、Bを利用するジョブCがあるとします。
A,Bがそれぞれ内部でDB更新とコミットを行うAPIだった場合、ジョブCの実行中に2回コミットが行われることになります。
この設計だと、仮にAPI Aが正常終了してAPI Bが処理失敗した場合、ジョブC全体としては失敗ですがAPI Aによる更新はすでにコミットされています。
この状態でジョブCを再実行すると、既に成功しているAPI Aを再実行することになり、データ不整合となってしまいます。
これを回避するためには、1ジョブ内でのコミットを1回に限定し、1ジョブ1トランザクションで完結できるような設計とすることが重要です。
おわりに
ということで、激動の5月を振り返ってみました。
なかなか大変でしたが、これを乗り越えた経験は、自分にとって大きな自信になりました。
引き続き、いろいろなことに挑戦していきたいと思います!