ヘッダレコード・データレコード・トレーラレコードとは

企業間でやりとりするファイルで見かけることがあるフォーマットとして、レコードが「ヘッダレコード」「データレコード」「トレーラレコード」に分かれているフォーマットがあります。
ファイルの中間部分にあたる「データレコード」に取り扱うデータを格納し、ファイルの冒頭と終了にあたる「ヘッダーレコード」「トレーラレコード」で日付や件数といった付加情報を与える、というのが特徴です。

以下で、「ヘッダレコード」「データレコード」「トレーラレコード」の簡単な説明と使用例を記載します。

【それぞれのレコードの説明】

・ヘッダレコード

ファイルの1レコード目のレコード。
一般的には、そのファイルが何日のデータなのかが記載される。

・データレコード

ファイルの中間レコード。
実際にやりとりするデータの中身が記載される。

・トレーラレコード

ファイルの最終レコード。
一般的には、そのファイルのデータレコード件数が記載される。

【フォーマット例】

取扱商品ファイルを想定した例を記載します。
可変長のCSVファイルを想定します。
(固定長の場合も多いです。固定長の場合は、カンマ区切りではなくバイト数で区切ることになります。)

・ヘッダレコード

1項目目:ファイル区分(1がセットされる)
2項目目:ファイル作成日付(YYYYMMDD)

・データレコード

1項目目:ファイル区分(2がセットされる)
 ※5がセットされることも多いです
2項目目:商品コード(7桁の数値)
3項目目:商品名(全角文字)
4項目目:値段(数値)

・トレーラレコード

1項目目:ファイル区分(9がセットされる)
2項目目:データレコードの件数(数値)

【ファイルのレコード例】

【ファイル受信時の処理例】

ヘッダレコードやトレーラレコードは、受信側のチェック処理に利用できます。
以下、ファイルを1レコード目から順番に読む場合の処理例について記載します。

・ファイル区分が1の時

1レコード目がファイル区分1でなければ異常終了。
(送信側が中間ファイル等誤ったファイルを送信することを想定)
バッチ日付と比較し一致しなければ異常終了。
(送信側が誤って過去ファイルを送信することを想定)

・ファイル区分が2の時

業務上必要な処理を実行。

・ファイル区分が9の時

最終レコードのファイル区分が9でなければ異常終了。
(ファイルを全件受信できていないことを想定)
件数がファイル区分2のレコード数と一致しなければ異常終了。
(ファイルを全件受信できていないことを想定)


ここからは応用です。

拡張性を確保するために、データレコードの種類を増やすという手段が有効になることがあります。
種類が異なるデータレコードをファイルに含める場合、データレコードのフォーマットを変えてしまうと、フォーマットが複雑になることで書き込み・読み込み処理が複雑になったり、フォーマット変更時の影響が全種類のデータレコードに出てしまったりします。
しかし、種類毎にデータレコードを用意することで、1つ1つのフォーマットが複雑になることを防いだり、フォーマット変更の影響が当該種類内のデータレコードに限定させることができます。

フォーマットと処理の例としては以下の通りです。
商品の種類毎にデータレコードの種類を変えることで、データ体系の違いを吸収している所がポイントです。
(1つのデータレコードにしてしまうと、1つのデータレコードに「食品商品コード」と「玩具商品コード」が含まれることになり、どちらを書き込むか・読みこむかの判断が必要になってしまいます。また、食品若しくは玩具にだけ新たな項目を追加する時に、追加が必要無い方の種類の商品の考慮も必要になってしまいます。)

【フォーマット例】

・ヘッダレコード

1項目目:ファイル区分(1がセットされる)
2項目目:ファイル作成日付(YYYYMMDD)

・食品データレコード

1項目目:ファイル区分(2がセットされる)
2項目目:食品商品コード(7桁の数値)
3項目目:商品名(全角文字)
4項目目:値段(数値)

・玩具データレコード

1項目目:ファイル区分(2がセットされる)
2項目目:玩具商品コード(6桁の数値)
3項目目:商品名(全角文字)
4項目目:値段(数値)

・トレーラレコード

1項目目:ファイル区分(9がセットされる)
2項目目:データレコードの件数(数値)

【ファイルのレコード例】

【ファイル受信時の処理例】

・ファイル区分が1の時

1レコード目がファイル区分1でなければ異常終了。
(送信側が中間ファイル等誤ったファイルを送信することを想定)
バッチ日付と比較し一致しなければ異常終了。
(送信側が誤って過去ファイルを送信することを想定)

・ファイル区分が2の時

業務上必要な食品向けの処理を実行。

・ファイル区分が3の時

業務上必要な玩具向けの処理を実行。

・ファイル区分が9の時

最終レコードのファイル区分が9でなければ異常終了。
(ファイルを全件受信できていないことを想定)
件数がファイル区分2~3のレコード数と一致しなければ異常終了。
(ファイルを全件受信できていないことを想定)


いかがでしたでしょうか。

モダンなシステムではあまり使われることが少ないファイルフォーマットかもしれませんが、レガシーなシステムでは使われることが多いフォーマットです。
レガシーなシステムとの連携では頻出なので、このファイルフォーマットの特徴を覚えておくと会話や理解がスムーズになるでしょう。

ハッシュ化(暗号化)におけるソルトとは

この記事では、ハッシュ化で使われる「ソルト」について、説明していきます。
どちらかと言うと初心者向けです。


【ハッシュ化とは】

ハッシュ化とは、与えられた文字列を特定の方式(アルゴリズム)に従って変換することです。
変換後の文字列から変換前の文字列に戻すことは困難であるため、変換前の文字列を知られたくない場合に用いられます。
具体的には、パスワードを使用した認証処理(ログイン処理)で使われることが多いです。

例えば、「SHA-512」と呼ばれる方式では、「password」という文字列は以下のように変換されます。

【認証処理におけるハッシュ化の使い方】

認証処理においては、パスワードを管理するファイルやデータベースに、ハッシュ化された形でパスワードが保持されます。
認証を行う際には、ユーザーから入力されたパスワードをハッシュ化し、ファイルやデータベースに保持されているハッシュ化された文字列と一致することを確認することで妥当性を確認します。

なお、システムの管理者もパスワードの平文を知ることができないので、ユーザーがパスワードを忘れてしまった場合はパスワードを再作成する運用を行います。

【レインボーテーブルによる攻撃】

不正ログインを試みる攻撃者は、何らかの方法でハッシュ化されたパスワードの一覧を入手した後、レインボーテーブルによる攻撃を試みることがあります。
レインボーテーブルとは、平文とハッシュ化後文字列の対応表のことを指し、この対応表を用いることでハッシュ化後文字列から平文を推測することができます。
例えば、以下のような対応表がレインボーテーブルです。全ての平文について対応表を作ることは困難ですが、良く使われる平文はこれで突破されてしまいます。

【ソルトによる対策】

ここでソルトの登場です。
ソルトとは、平文からハッシュ化を行う前に、平文に付加される文字列のことを指します。
ソルトは、平文の前に付加されても後に付加されても構いません。
ソルトを付加することにより、レインボーテーブルによる攻撃で平文のパスワードを推測されることを防ぎやすくなります。

以下は、「password」という平文の後ろに「LdCTFPMk」という平文を追加する例です。
ハッシュ化後文字列が全く違うものになり、レインボーテーブルで逆引きすることが困難になります。

なお、ソルトに用いる文字列は、複雑で長い文字列(例えばランダムで生成された文字列)、かつユーザー毎で使い分ける(ログイン時に入力されたユーザーから対応するソルトを取得する処理を別途作成する)ことが望ましいです。


いかがでしたでしょうか。

ソルトは良く出てくる技術ですが、その意味はあまり知られていないように思うので、今回の記事が参考になれば幸いです。

プログラム上の変数やロジックの意味を現実のビジネスルールと合わせることの重要性

通常、初回リリースの時点では、ソースコードは現実のビジネスルールを反映したものになっています。
(なっているべきです)

そして、障害対応や保守開発でソースコードを修正する際は、将来の保守性を犠牲にしないために、ビジネスルールに沿った修正を行うべきです。
ビジネスルールに沿わない修正を行ってしまうと、ソースコードの解読が困難になったり、後々新たなバグが生まれやすくなったりします。


例えば、麺・スープが入った器に具材を入れて料理を完成させるシステムを開発しているとします。
取り扱う料理は以下の通りとします。

また、

という処理が存在するとします。

ある日、「みそラーメンにはこしょうではなく七味を入れたい」という要望が入り、システムを改修するとします。

ここで、「みそラーメンの分類をうどんにする」という修正を行うべきではありません。
この修正でも要望に応えることはできますが、ビジネスルール上はみそラーメンはうどんに分類するべきではないので、このような修正を行うと保守性が低下します。
システムの実装を良く知らない人がソースコードを読んだ場合、「みそラーメンはラーメンである」という予想を立ててソースコードを読むことになるので、「実装上はみそラーメンはうどんである」となっていると、ソースコードの読解を誤るリスクが高まります。
また、将来、「うどんには揚げ玉を入れたい(ラーメンには入れたくない)」という要望が入り、「分類がうどんの場合は揚げ玉を入れる」という処理を追加してしまうと、みそラーメンにも揚げ玉が入るというバグを埋め込んでしまいます。

ここは、処理を以下のように修正し、ビジネスルールを崩さないようにすることが望ましいです。


いかがでしたでしょうか。

プログラムの改修は直せば良いというものではなく、その後の保守のしやすさも考えて直す必要があります。
今回は、実務で目にしたケースを元に、記事を書いてみました。

ソースコード中に顧客情報を記述してはいけない

特定の顧客用に特別なビジネスロジックを用意している場合、以下のようにソースコード中に顧客情報を記述することで実装することはできます。
(顧客番号が’1111111’である場合に特別なビジネスロジックを実行するとします)


しかし、この実装方法には以下の問題があり、望ましくありません。
特別なビジネスロジックを適用する対象の顧客の情報は、(データの管理にDBを使用しているシステムであれば)DBに持たせるべきです。

・頻繁なソースコード修正が必要になる

対象となる顧客が追加されたり削除されたりする度にソースコード修正が必要になる。
コンパイルやデプロイも必要となり、対応工数や対応のリスクが増加する。
→DBで管理すればDB内の情報の補正だけで済む。

・データを一元管理できなくなる

対象となる顧客を調べるためにはソースコードを見なくてはならなくなる。
→DBで一元管理すれば情報の検索が容易になる。

・セキュリティを確保するのが難しくなる

ソースコードが流出した場合に顧客情報も同時に流出してしまう。
→DBで一元管理すれば、顧客情報の流出のリスクを減らすことができる。


対象となる顧客の情報をDBに持たせる場合、以下のような実装になります。

1.特定処理対象顧客テーブルを別途作る場合

※特定処理対象顧客テーブルには、特定処理の対象となる顧客番号を格納する。

2.既存のテーブルにフラグを持たせる場合

※「特定処理対象フラグ」のカラムを追加し、処理対象なら’1’、処理対象外なら’0’をセットする。

いかがでしたでしょうか。

ソースコード中に顧客情報を記述してしまい保守性が低下するという話は良く聞きますし、私自身もそのようなソースを保守開発して苦労したことがあります。
また、最近ではソースコードと共に顧客情報が流出したという事故もニュースになっています。
そのような背景があり、今回の記事を書いてみました。

顧客情報が記述されたソースコードを目にする機会は珍しくないと思いますが、それはアンチパターンであるというのは認識しておくべきでしょう。

システム改修で発生するデータ移行とは

通常のシステムでは、データベースやファイル等にデータを蓄積します。
そして、システムの改修の際に、そのデータのフォーマットを変更することがあります。

データのフォーマットの変更には、「これまでに蓄積されたデータをどのように扱うのか」という問題が付きまといます。
開発者は、データを移行するのかしないのか、移行するのであればどのように移行するのか、ということを判断する必要があります。
ここでは、データ移行について、具体的な例を用いて見て行こうと思います。

【例】

商品購入履歴テーブルにて、清算番号をキーとし、いつ誰が何をどれだけ購入したのかを管理しているとします。
システム稼働開始時は、商品コードから単価は一意に求まるとします。
また、当該テーブルを見て、各々の顧客が過去に商品を購入したことがあるかどうかを見る必要があるとします。

ここで、各々の清算において値引きを可能にするシステム改修を行うとします。
また、売り上げを正しく求めるため、清算毎の単価を新たに管理する必要が出てきたとします。

この場合、商品購入履歴テーブルのフォーマットを以下のように変更する必要が出てきます。

ここで、過去に蓄積されたデータの扱いについて、以下のような方針を考える必要が出てきます。

【対応方針】

1.データ移行せず、旧商品購入履歴テーブルをそのまま残す

データ移行が困難であり、プログラムの改修箇所が少ないのであれば、データ移行しないという選択肢があります。
データ移行が困難な状況としては、データ量が多く時間がかかる、システムを停止できる時間が少ない、といった要因があります。

この方針の場合、過去の購入履歴を参照するプログラムに対して改修が必要になります。
新商品購入履歴テーブルと旧商品購入履歴テーブルの両方を見る、という改修を行う必要があります。
例えば、顧客コード”0000001″の顧客が過去に商品を購入したかどうかを見たい場合、新商品購入履歴テーブルになければ旧商品購入履歴テーブルを見る、とする必要があります。

この方針のデメリットとしては、プログラムロジックが複雑になり、保守性が低下することが挙げられます。
もし、自動化されていない運用作業で商品購入履歴テーブルを見る必要がある場合、その作業が煩雑になることにも注意する必要があります。運用ミスの原因にもなり得ます。

2.データ移行する

データ移行する場合、旧商品購入履歴テーブルのデータを、新商品購入履歴テーブルに移し替える必要があります。
システムを一時的に停止し、移行用のプログラムを実行させ、旧商品購入履歴テーブルのデータを新商品購入履歴テーブルのフォーマットに合わせた形で移行します。
(失敗に備えてバックアップを取得することも重要です)

データ移行する際には、フォーマットをどのように合わせるのかを考える必要があります。
今回の例で言うと、移行したデータの単価に何をセットするのか、ということを考える必要があります。
移行日以前の単価を見る必要が無いのであれば、nullで問題ありません。
見る可能性があるのであれば、現在の単価(過去に単価が変動しているのであれば当時の単価)をセットする必要があります。


いかがでしたでしょうか。

今回の記事の通り、データフォーマットを変更する場合は、変更後に追加されるデータのことだけでなく、それまでに蓄積されたデータをどうするのかということも考える必要があり、その分の工数やリスクを考慮する必要があります。

今回書いたようなことは記事として書かれることが少なく、経験則に近いものがあります。
経験則を記事に起こして共有可能とすることは重要だと思うので、今後も経験則を記事にしていきたいと思います。