蒼時弦也
蒼時弦也
資深軟體工程師
發表於

資料跟資訊的差異 - Rails 開發實踐

這篇文章是 Rails 開發實踐 系列的一部分。

你有想過資料(Data)資訊(Information)的差異嗎?在軟體開發的過程中,我們做的通常被叫做「資訊系統」然而大多數情況,我們很可能只是單純的把資料放到一個程序裡面,然後對這些資料做了一些調整,中間並沒有「資訊」的概念在裡面。

脈絡

在英文字典中,資訊的定義是「有脈絡(Context)的資料」而在中文字典,資訊是指「經過處理的資料」也就是說,我們平常在使用的「資料庫」是保存未經處理的部分,那麼脈絡是什麼呢?

舉例來說,假設我們在一個超商買東西的場景,當我拿出鈔票付錢的時候,我們就自然的理解了一些脈絡,在這個時候我們直接用「50」也能馬上被理解為「50 元」這就是所謂的脈絡,在這個過程中「50」是我們的資料,而 「50 元」就是所謂的資訊。

在轉換需求為規格的過程中,我們遭遇到最大的問題其實是日常溝通中需要透過多次的「對話」來補全脈絡,規格和 Key Examples(關件案例)這類資訊,就是從需求中提取出可以代表這個脈絡的關鍵資訊來使用。

模型與實體

在 Rails 中我們會很自然的把資料跟 Model(模型)聯想在一起,這是因為 ORM(Object Relational Mapping,物件關係映射)機制的特性,大多數的 MVC 框架都會提供這樣的機制,因而讓我們忘記了在程式中使用的 Model 應該是一個脈絡下的 Entity(實體)

大多數人接觸到 Entity 的概念應該是因為 Domain-Driven Design(領域驅動開發)的關係,在這個章節我們不會深入討論過多,先以一個 Model 作為例子。

1class Subscription < ApplicationRecord
2  has_many :items, class_name: 'SubscriptionItem'
3
4  attribute :expired_at, :datetime
5
6  def calculate_expired_at
7    self.expired_at = created_at + items.sum(&:extend_amount)
8  end
9end

在上面這個例子中,過期時間是透過 ActiveModel 的 DSL 所定義的,而不是透過 ActiveRecord 自訂映射而來,然而我們仍然可以正常使用這個屬性。

這會影響使用嗎?其實這是一種設計的選擇,我們可以在資料庫建立一個 expired_at 的欄位來儲存這個資訊,也可以改為儲存每一筆紀錄,最後用聚合(Aggregate)的函示 SUM 將所有延展的時間加總,最後跟開始訂閱的時間相加去計算出最後過期的時間點。

也就是說,我們的模型不總是跟資料庫完全對應的,他會取決於我們怎麼使用。

從狀態出發

Entity 在一個系統中扮演的角色是「維護狀態」以前面訂閱的例子來看,每一筆訂閱紀錄都會知道自己在什麼時候開始,但不會特別去儲存「過期時間」當我們需要知道何時過期時,可以透過每一次續訂的紀錄來計算,這是因為受到「規格」的影響。

假設每一次的續訂都是延展 30 天,如果用日期來紀錄,其實會變得有點麻煩,因為我們會需要每次都計算延展 30 天是到哪一天。

然而改為延展天數,那麼就可以直接儲存 30,未來改變延展的時間,只需要調整 30 這個常數即可。

反過來看,如果訂閱機制是以「月底」為基礎來判定,在這個狀況下,用 3031 來儲存就會變得複雜,正因如此,假設我們還無法確定怎樣儲存資料能更符合需求,不如先避免儲存到資料庫的設計,用不同的方式規劃 Model 來驗證,等到我們找到適合的狀態管理方式後,再進行資料表的設計與建立。