データレコードの種類を増やして拡張性を持たせる

以前に書いた「ヘッダレコード・データレコード・トレーラレコードとは」の続きです。


企業間でやりとりするファイルでよく見かけるフォーマットとして、レコードが「ヘッダレコード」「データレコード」「トレーラレコード」に分かれているフォーマットがあります。
簡単に言うと、それぞれのレコードの説明は以下のようになります。

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

・ヘッダレコード

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

・データレコード

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

・トレーラレコード

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


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

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

【フォーマット例】

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

・ヘッダレコード

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

・食品データレコード

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

・玩具データレコード

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

・トレーラレコード

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

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

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

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

・ファイル区分が1の時

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

・ファイル区分が2の時

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

・ファイル区分が3の時

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

・ファイル区分が9の時

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


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

このテクニックは、レガシーなシステムでは良く使われるテクニックです。
レガシーなシステムの設計をする場合に、もしかしたら役に立つことがあるかもしれません。

システムの概要を示す設計書が本当に必要な設計書である

表題の通りですが、システム開発で本当に必要な設計書は、システムの概要を示す設計書です。
そのような設計書があれば、実装を知らない立場の人(例えば要件定義担当や上位の設計者)との意思疎通がスムーズになりますし、開発者を新たに向かい入れる時にも実装の内容をスムーズに理解してもらえるようになります。


例として、在庫確認モジュールを開発しているとします。
具体的な実装としては以下のイメージとします。
実際には、「:」の箇所に数行~数十行のコードが書かれているイメージです。

【実装イメージ】


良くない設計書の例としては、以下のようなものがあります。
(残念ながら、実務でも見かけることがあります)

・ソースコードと1対1対応の設計書

ソースコードを1行1行日本語に訳したような設計書は良くありません。
そのような設計書は記述量が多くなり、作成するのも大変ですし、それを読んで内容を理解するのも大変です。
また、日本語(自然言語)は意味が曖昧になりがちなので内容も不正確になります。
更に、ソースコードに些末な変更を行う度に、設計書の更新も必要になるという問題もあります。
(設計書の更新を忘れると、設計書を信用できなくなる)

・見た目だけで内容に乏しい設計書

経験が浅く見様見真似で設計業務に当たっている場合、以下の絵のような見た目だけで内容に乏しい設計書を作成しがちです。
(この例の絵は少し誇張しすぎですが)

しかし、設計書はかっこ良く見せる資料ではなく、実装に直接的・間接的に関わる人と意思疎通を取るための資料なので、実装内容が早く正確に伝わればそれで良いです。
どのような設計書を作れば良いかイメージが付きにくい場合は、現現場の既存の設計書や他現場の設計書を参考にしたり、先輩社員に聞いたりすると良いでしょう。


システムの概要が早く正確に伝わる設計書が良い設計書です。
例えば、以下のような処理概要を掴めるフローチャートは良い設計書です。

このような設計書があれば、要件定義担当や上位の設計者が全体像をつかみやすくなり、レビュー(要件や全体の設計の観点から見て問題がないことの確認)が捗ります。
また、新たに開発者を向かい入れる場合にも、モジュールの全体像を掴んでもらってから、必要に応じて細かい箇所を確認してもらうことができるようになります。


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

良い設計書を書けるようになることが、PGからSEへのステップアップの鍵です。
システムの概要を示すことを意識することが重要で、それを意識しながら実務にあたると、自ずと良い設計書が書けるようになるでしょう。

JavaScript:オブジェクト型の定数値にはObject.freeze()を使う

プリミティブ型(Number型やString型等)の変数は、constで定義することで変更不可にできます。
これを利用して、定数値を定義することができます。

【サンプルコード】

【ChromeのデベロッパーツールのConsoleで実行】


しかし、オブジェクト型の場合、constで保持されるのは変数が指し示すアドレスであり、値は変更可能です。
そのため、定数値を定義するには適していません。

【サンプルコード】

【ChromeのデベロッパーツールのConsoleで実行】


オブジェクト型で定数値を定義したい場合は、Object.freeze()を使う必要があります。
これを使うことで、オブジェクト型の変数が指し示す値を変更不可にすることができます。

【サンプルコード】

【ChromeのデベロッパーツールのConsoleで実行】


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

コーディングミスがない限りは定数値を書き変えることはないためお作法的なものに近いのですが、覚えておいて損はない内容でしょう。

来週以降は、コーディングからは一旦離れて、暗黙知的なものや経験則的なものを記事にしていきたいと思います!

JavaScript:未宣言・var・letの変数の挙動の違い

JavaScriptにおける変数の宣言方法は、constを除くと以下の4つがあります。

・未宣言

のように、値が代入された時点で変数が宣言されたものとみなされる。

・var

のように、var句により変数を宣言する。

・var(巻き上げ)

のように値が代入された後にvarにより変数が宣言された場合、変数が宣言された後に値が代入されたものとみなされる。
この例では、以下と同価とみなされる。

・let

のように、var句により変数を宣言する。
ES6のバージョン以降でサポートされている。

これらの宣言方法の違いにより、非Strictモードの場合に以下の挙動の違いが生じます。
(varの巻き上げについては、巻き上げしなかった場合と同じです)

なお、Strictモードの場合は、varやletやconstを用いて宣言をせずに変数に値を代入した場合にReferenceErrorで異常終了するようになります。


以下、挙動を確認するためのサンプルコードです。
(Node.jsで確認します)

それぞれの変数で以下を確認します。

・var1

ブロック外で宣言した変数をブロック内でも宣言。
ブロック内の変更がブロック外に影響するなら、ブロックを出た時点で変数が書き変わる。

・var2

ブロック内でのみ変数を宣言。
ブロック内の変更がブロック外に影響するなら、ブロックを出た時点で参照不可になる。

・var3

関数内でのみ変数を宣言。 関数内の変更が関数外に影響するなら、関数を出た時点で参照不可になる。

【テストコード(未宣言)】

・test.js

【実行結果(未宣言)】

【テストコード(var)】

・test.js

【実行結果(var)】

【テストコード(var巻き上げ)】

・test.js

【実行結果(var巻き上げ)】

【テストコード(let)】

・test.js

【実行結果(let)】


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

この記事では、JavaScriptの変数宣言の違いによる挙動の違いをまとめてみました。
色々と書きましたが、現在の実務ではletを使うのが無難です。
letであれば、Javaの変数と同じような感覚で使うことができます。

JavaScript:String型かNumber型かわからない変数をNumber型に置き換えるコード

JavaScriptは動的型付けを採用した言語であるため、実行するまで変数の型が分からない状態になります。
この特徴により、数値計算を行う時を以下のような問題を引き起こすことがあります。

・加算を行うつもりが文字列結合になってしまう

(例えば、100 + “100” は “100100”になる)

・計算結果がNaNになってしまう

(例えば、カンマ等を含むString型をNumber()でNumber型に変換しようとした場合)

・桁が途中で落ちてしまう

(例えば、カンマ等を含むString型をparseInt()でNumber型に変換しようとした場合)

これらの問題は、計算に使おうと思っていた変数がString型であり、そのString型を正しくNumber型に変換できていないことに起因します。

これらの問題は、以下のようなコードにより変数をNumber型に正しく変換することで、回避することができます。

【コード】

【サンプルの実行結果】

・inputが整数のNumber型

・inputが小数のNumber型

・inputが整数のString型

・inputが小数のString型

・inputがカンマを含むのString型

【解説】

・Number型に含まれる文字は”0-9″と”.”のみなので、それ以外の文字はreplace関数により削除する。
・replace関数は変数がString型でないと使用できないので、変数を事前にtoString関数によりString型に変換する(変換する代わりに型を判定する分岐を入れて処理を分けても良い)。


今回も、実務の中で問題になったケースを記事にしました。
JavaScriptは動的型付けを採用した言語であるがゆえに、Javaのような静的型付けでは気を付ける必要がない点にも気を付けてコーディングする必要があります。