1. 導入:なぜ「データ定義」が重要なのか
プログラミングをしていて、「データの形を定義するコード」と「APIから送られてきたデータを解析するコード」の二重管理に疲れたことはありませんか?実は、Haskellなどの関数型言語が持つ「ADT(代数的データ型)」を活用すれば、この二重管理という手間をゼロにできます。データ構造を定義した瞬間、それがそのまま通信プロトコルとして機能する。このシームレスな体験こそが、型安全かつ高速な開発の秘訣です。
2. 基礎知識:ADTとシリアライズの仕組み
まず、ADTとは「和型(Sum Types)」と「積型(Product Types)」を組み合わせて作るデータ構造のことです。
和型は「AまたはB」という選択肢、積型は「AとBとCを保持する」という情報の集合体です。
なぜこれが重要かというと、JSONやXMLといった階層構造を持つデータ形式と、ADTの木構造が驚くほど綺麗に一致するからです。
・和型:JSONの「タグ付きオブジェクト(種類を識別するフィールドを持つもの)」
・積型:JSONの「フィールドリスト(キーと値のペア)」
この対応関係があるため、型を定義するだけで、データの変換ルール(シリアライズ/デシリアライズ)が自動的に導き出されます。
3. 実装:型から自動的にデータを導く
具体的には、言語のライブラリ(HaskellならAesonなど)を利用して、データ型に「JSON変換ルール」を紐付けます。一度型を定義してしまえば、あとはライブラリが「この型はこうやってJSONにする」と判断してくれるため、変換用の複雑なロジックを自分で書く必要がなくなります。
4. サンプルプログラム
ここでは、Haskellの考え方をベースにした擬似的なコードで、データ定義がどのようにシリアライズと直結するかを示します。
// ユーザー情報を表現するデータ型(積型)
// 名前と年齢を保持する
type User = {
name: string,
age: number
}
// 支払い方法を表現するデータ型(和型)
// クレジットカードか、銀行振込のどちらかであることを示す
type PaymentMethod =
| { type: “credit_card”, number: string }
| { type: “bank_transfer”, account: string }
// このように定義すると、以下のJSONと1対1で対応します
// { “type”: “credit_card”, “number”: “1234-5678” }
// 実際に利用する際は、ライブラリの関数を呼ぶだけです
// const json = serialize(myUser); // データからJSON文字列へ
// const user = deserialize(json); // JSON文字列からデータ型へ
// ポイント:型定義を変更すれば、自動的にシリアライズのルールも追従します。
// 手動でパース処理を書く必要がないので、バグが混入する隙がありません。
5. 応用・注意点:現場で陥りやすい罠
非常に便利なADTですが、一点だけ注意が必要です。それは「外部システムとの連携」です。
外部のAPIが提供するJSONの構造が、自分の定義したADTと微妙に一致しない(フィールド名が違う、階層が深いなど)ケースが多々あります。
そんな時は、「外部のデータ形式を直接ADTにするのではなく、一度中間形式(DTO)を通す」のが鉄則です。
1. 外部APIから来たJSONを、そのまま受け取る小さな型を作る
2. その型を、自分のプログラムで扱いやすいADTに変換する
この「変換レイヤー」を一枚挟むだけで、外部仕様の変更に強い、堅牢なシステムを構築することができます。ぜひ、データ定義から始まる型安全な開発を楽しんでください!

コメント