脈絡:數個應用程式透過遵循某個約定資料格式(也許是全企業的 Canonical Data Model)的訊息溝通。然而這個格式將來可能需要改變

格式一定會變#

即使你設計出一套適用於所有參與應用程式的資料格式,未來的需求仍可能改變:

  • 新加入的應用程式帶來新的格式需求
  • 訊息中需要加入新資料
  • 開發者找到更好的方式來組織同樣的資料

設計一套企業資料模型本來就夠難了;設計一套永遠不必改變的,幾乎不可能。

為什麼不能大家一起換#

若企業的資料格式改變時所有應用程式都跟著改,那就沒問題了:每個應用程式都同時停用舊格式、啟用新格式,轉換就很簡單。

現實是:有些應用程式會比別人早轉換,某些冷門的應用程式可能永遠不會轉換。 而且即使所有應用程式能同時轉換,轉換之前還得先把所有訊息消費完、讓所有通道都清空才行。

因此現實上,應用程式必須同時支援舊格式與新格式。要做到這件事,它們得能分辨哪些訊息用舊格式、哪些用新格式。

一個不好的解法#

一種可能是替新格式的訊息另開一組通道。但這會導致通道數量暴增、設計重複,以及設定上的複雜——每個應用程式都得為一組不斷膨脹的通道做設定。

更好的解法是:讓新格式的訊息沿用舊格式訊息一直在用的那些通道。這意味著接收端需要一種方式,來分辨同一通道上格式不同的訊息——訊息必須指明自己用的是什麼格式

解法#

格式指示子讓寄件端能告訴接收端這則訊息的格式。如此一來,預期會收到數種可能格式的接收端,就知道某則訊息用的是哪一種、因而該如何解讀它的內容

三種實作方式#

  1. 版本號(Version Number)——一個唯一標識該格式的數字或字串。收發雙方必須就「哪個指示子代表哪個格式」達成共識。
  2. 外部鍵(Foreign Key)——一個唯一 ID(檔名、資料庫列鍵、home primary key,或網際網路 URL),指向一份格式文件。收發雙方必須就「鍵到文件的對應」以及 schema 文件的格式達成共識。
  3. 格式文件(Format Document)——一份描述資料格式的 schema。它不必透過外部鍵取回、也不必從版本號推斷,而是直接嵌在訊息裡收發雙方必須就 schema 的格式達成共識。

格式文件則可能太長或太複雜,塞不進表頭欄位——此時訊息內文就得採用一種**含有兩部分(schema 與資料)**的格式。

範例:XML 中三種作法都看得到

XML 文件同時展示了上述三種作法。

版本號——XML 宣告:

<?xml version="1.0"?>

這裡的 1.0 是版本號,指出該文件符合這一版的 XML 規格。

外部鍵——文件型別宣告的其中一種形式,含有系統識別碼:

<!DOCTYPE greeting SYSTEM "hello.dtd">

系統識別碼 hello.dtd 是一個外部鍵,指出描述這份 XML 文件格式的 DTD 檔案。

格式文件——宣告也可以在本地內嵌:

<!DOCTYPE greeting [
 <!ELEMENT greeting (#PCDATA)>
]>

其中的標記宣告 [<!ELEMENT greeting (#PCDATA)>] 就是一份格式文件——一份內嵌的 schema 文件,描述這份 XML 的格式。