シリアライズフォーマットとは何か。JSON,XML,YAML,CSV,Protobufの比較。

# この記事を書くきっかけ
Webアプリケーションを作成する際、環境構築の段階でJSONファイルにいろいろ記入することがありました。Pythonでコーディングするときも、JSON形式のデータをやり取りするコードを書いたりしていました。

最近、Docker Composeの設定をしたとき、docker-compose.ymlというYAML形式の書き方にはじめて出会いました。そのとき、「そもそもJSONとかYAMLとかってなんだろう」、「こういう形式のものってなんて言うんだろう」、「どんな場面で出てくるんだろう」と疑問を持ちました。

CSVは聞いたことはあるけど、XMLやProtobufは未だによく知りません。でも、この機会に学んでおこうと思い、記事にしました。

# シリアライズフォーマットとは

## シリアライズとは？ 
シリアライズとは、プログラム内で使用しているデータ（オブジェクトやデータ構造）を、保存したり送信したりするために、一連のバイト（または文字列）に変換するプロセスのことです。逆に、このバイト列を元のデータに戻すことをデシリアライズと言います。

### シリアライズをもっとわかりやすく説明すると・・・

① プログラムの中では、データはいろいろな形をしていて、オブジェクトやリストなどの形で保存されています。いろんなデータがバラバラの場所に存在しています。

② このプログラムがデータの保存先や通信先を通るためには、データが一列になってドアを通り抜ける必要があります。人間や車も普段はバラバラに動いていても、トンネルの中に入るときは一列に整列しないと通れないという状態と似ています。

これがシリアライズです。シリアライズは日本語で言うと「直列化」です。バラバラの状態を一列（シリアル）に並べるということです。

プログラム内のデータも、保存したり送信したりするためには、一連のバイトや文字列として一列に並べられる必要があります。これがシリアライズ（直列化）のプロセスです。

③ 保存されたり送信されたデータを元のオブジェクトに戻すことをデシリアライズと言います。


## シリアライズフォーマットとは？
シリアライズフォーマットは、データをシリアライズするときに使う特定の形式やルールのことです。これにより、データが一貫した方法で保存されたり、送信されたりします。

## なぜシリアライズフォーマットが必要なのか？

### データの保存
プログラムが扱うデータは、メモリ上に一時的に存在します。しかし、プログラムが終了するとメモリのデータは消えてしまいます。そのため、データを長期的に保存するために、ファイルやデータベースにデータを保存する必要があります。このとき、プログラムのデータを保存可能な形式に変換するシリアライズを行います。

**利点**
1. プログラムが終了すると、そのプログラムが使用していたメモリ上のデータはすべて失われます。プログラムの実行中に作成されたデータや情報を後で再利用したい場合、シリアライズによってデータを永続的に保存することができます。
1. プログラムが生成するデータは、後で再利用したり、他のプログラムやシステムと共有したりすることがあります。例えば、ユーザーの設定やデータを保存しておけば、次回プログラムを実行したときにそのデータを再利用することができます。また、異なるシステム間でデータを交換する場合にも、共通の保存形式を使用することでデータのやり取りがスムーズになります。これをシリアライズによって行います。
1. データを特定の形式に変換して保存することで、データの一貫性や信頼性を保つことができます。データが一貫した形式で保存されていれば、プログラムがそのデータを読み取る際にエラーが発生しにくくなり、データの整合性が保たれます。

### データの送信
異なるコンピュータやシステム間でデータをやり取りする場合、データを送信する必要があります。例えば、Webアプリケーションがサーバーにデータを送るとき、データはネットワークを通じて送信されます。このときも、データを送信可能な形式に変換します(シリアライズ)。

**利点**
1. 異なるシステムやプログラムは、それぞれ異なるデータ形式やデータ構造を使用している場合があります。そのため、データを送信する際に、共通の理解可能な形式に変換することで、一貫性と互換性を保つことができます。
1. データを送信する際に、共通の形式に変換することで、データの正確性と信頼性を保つことができます。これで、データが送信中に正しく解釈され、誤って変更されないようになります。
1. データを特定の形式に変換することで、送信中のデータのセキュリティと効率を向上させることができます。例えば、バイナリ形式に変換することでデータ量を減らし、ネットワーク帯域を効率的に使用できます。また、データが暗号化されていれば、送信中にデータが盗まれたり改ざんされたりするリスクを減らすことができます。

### データの共有
異なるプログラムやシステム間でデータをやり取りする際に、シリアライズフォーマットを使用することで、データを統一された形式に変換し、共有を簡単にします。

**利点**
1. 異なるプログラムやシステムは、異なるデータ形式や構造を持つことが多いため、データを共通の形式に変換することで、互換性を保ちます。データのやり取りがスムーズになります。
1. シリアライズフォーマットを使用することで、データの信頼性が向上します。統一された形式でデータを共有することで、データの解釈や使用時にエラーが発生しにくくなります。
1. シリアライズフォーマットは、データの一貫性を保つために重要です。統一された形式でデータを保存し、共有することで、データがどこでも同じように扱われるため、データの整合性が保たれます。

### まとめ
シリアライズフォーマットを利用すると、これらの利点があります。
- データがプログラム終了後も失われないように保存することができる(データの永続性)
- 保存したデータを再度利用することができる(データの再利用)
- 他のプログラムやシステムと共有することができる(データの共有)
- データが正確である(データの信頼性)
- 一貫した形式で保存することができる(データの信頼性)


## よく使われるシリアライズフォーマット
JSON、XML、YAML、CSV、Protobufの特徴、使用例、利点、欠点を詳しく説明します。
それぞれのフォーマットの具体的な使用例とサンプルコードもあわせて載せました。

### JSON（JavaScript Object Notation）
読み方: ジェイソン

**特徴**
- 軽量なデータ交換形式です。
- キーと値のペアでデータを表現します。
- 人間が読みやすく、多くのプログラミング言語で利用できます。

**使用例**
- Web APIのリクエストとレスポンス。
- 設定ファイル。
- データをシリアライズするとき。

**利点**
- 読みやすく、理解しやすい。
- ほとんどのプログラミング言語でネイティブにサポート。
- データの交換が容易。

**欠点**
- テキストベースなので、バイナリデータの扱いには向かない。
- 複雑なデータ構造には冗長になる場合がある。

**データ例**
```json
{
    "name": "John Doe",
    "age": 30,
    "city": "New York"
}
```
**Pythonでの使用例**
```python
import json

# JSONデータをPythonの辞書に変換
data = '{"name": "John Doe", "age": 30, "city": "New York"}'
parsed_data = json.loads(data)
print(parsed_data['name'])  # "John Doe"

# Pythonの辞書をJSONに変換
python_data = {"name": "Jane Doe", "age": 25, "city": "Los Angeles"}
json_data = json.dumps(python_data)
print(json_data)  # '{"name": "Jane Doe", "age": 25, "city": "Los Angeles"}'
```
***

### XML（eXtensible Markup Language）
読み方: エックスエムエル

**特徴**
- タグを使ってデータを階層構造で表現します。
- 拡張性が高い。
- 文書の形式やデータ交換に広く使用されます。

**使用例**
- 設定ファイル。
- 文書データ。
- Webサービス（SOAPなど)
  - **SOAP（Simple Object Access Protocol）**: XMLベースのプロトコルで、異なるシステム間でデータを交換するために使用されます。例えば、銀行のシステム間でのトランザクションや、複雑な操作を伴う企業間のデータ交換に利用されます。


**利点**
- 複雑なデータ構造を表現できます。
- 自己記述的で拡張に向いてます。
- 多くの標準化されたツールとライブラリが存在します。

**欠点**
- 冗長で読みづらい。
- パースが遅い(データの解析と変換に時間がかかる)。

**データ例**
```xml
<person>
    <name>John Doe</name>
    <age>30</age>
    <city>New York</city>
</person>
```

**Pythonでの使用例**
```python
import xml.etree.ElementTree as ET

# XMLデータをパース
data = '''<person>
    <name>John Doe</name>
    <age>30</age>
    <city>New York</city>
</person>'''

root = ET.fromstring(data)
print(root.find('name').text)  # "John Doe"


# XMLデータの作成
person = ET.Element("person")
name = ET.SubElement(person, "name")
name.text = "Jane Doe"
age = ET.SubElement(person, "age")
age.text = "25"
city = ET.SubElement(person, "city")
city.text = "Los Angeles"

tree = ET.ElementTree(person)
tree.write("person.xml")
```

***
### YAML（YAML Ain't Markup Language）
読み方: ヤムル

**特徴**
- インデントで階層構造を表現。
- シンプルで読みやすい。
- 設定ファイルとしてよく使用。

**使用例**
- DevOpsツールの設定（Docker Compose、Kubernetes）。
- 設定ファイル。
- データシリアライズ。

**利点**
- 人間が読みやすく、書きやすい。
- インデントによって構造がわかりやすくなる。

**欠点**
- インデントに敏感で、エラーが起こりやすい。
- 複雑なデータ構造には向かないことがある。

**データ例**
```yaml
name: John Doe
age: 30
city: New York
```

**Pythonでの使用例**
```python
import yaml

# YAMLデータをPythonの辞書に変換
data = """
name: John Doe
age: 30
city: New York
"""
parsed_data = yaml.safe_load(data)
print(parsed_data['name'])  # "John Doe"

# Pythonの辞書をYAMLに変換
python_data = {"name": "Jane Doe", "age": 25, "city": "Los Angeles"}
yaml_data = yaml.dump(python_data)
print(yaml_data)
```
***

### CSV（Comma-Separated Values）
読み方: シーエスブイ

**特徴**
- テキスト形式で、データをカンマで区切る。
- シンプルで軽量。
- 多くのプログラムやツールでサポート。

**使用例**
- データのインポートとエクスポート。
- スプレッドシートやデータベースのデータ交換。

**利点**
- シンプルでわかりやすい。
- 多くのツールでサポートしています。

**欠点**
- 階層構造を表現できません。
- データ型の情報を持たないため、すべてのデータが文字列として扱われます。

**データ例**
```csv
name,age,city
John Doe,30,New York
Jane Smith,25,Los Angeles
```

**Pythonでの使用例**
```python
import csv

# CSVデータを読み込む
with open('data.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print(row['name'])  # "John Doe", "Jane Smith"

# CSVデータを書き込む
with open('output.csv', 'w', newline='') as csvfile:
    fieldnames = ['name', 'age', 'city']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerow({'name': 'John Doe', 'age': 30, 'city': 'New York'})
    writer.writerow({'name': 'Jane Smith', 'age': 25, 'city': 'Los Angeles'})
```
***

### Protocol Buffers（Protobuf）
読み方: プロトコルバッファーズ（略してプロトバフ）

**特徴**
- Googleが開発したバイナリシリアライズフォーマット。
- スキーマ定義に基づいてデータを効率的にシリアライズおよびデシリアライズ。
- 言語非依存で、複数のプログラミング言語でサポート。
- 高速かつコンパクトなデータ表現が可能。

**使用例**
- 高性能なデータ交換（例：マイクロサービス間の通信）。
- 大規模なデータ処理システム。
- モバイルアプリケーションとサーバ間の通信。

**利点**
- バイナリ形式であるため、データサイズが小さく、シリアライズとデシリアライズが高速に行われます。
- 多くのプログラミング言語でサポートされており、異なるシステム間でのデータ交換が容易です。
- スキーマに基づくため、データ構造が明確です。

**欠点**
- バイナリ形式であるため、人間が直接読み書きすることは難しい。
- スキーマの定義やツールの使い方を習得する必要があります。
- スキーマの変更には注意が必要で、互換性を保つための工夫が必要です。


```proto
syntax = "proto3";

message Person {
  string name = 1;
  int32 age = 2;
  string city = 3;
}
```
**Pythonでの使用例**
事前にprotocコンパイラでperson.protoファイルをコンパイルして生成されたperson_pb2モジュールを使用します。
```python
import person_pb2

# データの作成
person = person_pb2.Person()
person.name = "John Doe"
person.age = 30
person.city = "New York"

# バイナリデータにシリアライズ
serialized_data = person.SerializeToString()

# デシリアライズ
new_person = person_pb2.Person()
new_person.ParseFromString(serialized_data)
print(new_person.name)  # "John Doe"
```



# まとめ
- シリアライズフォーマットとは、プログラムのデータを保存したり送信したりするときに、標準化された形式に変換する方法です。
- 形式に則ってシリアライズすることで、データが一貫して扱われて、異なるシステム間でのデータ交換がうまくいきます。
- JSON,XML,YAML,CSV,Protobufそれぞれに利点があるので、使われる場面も異なります。