人性化介面

2005 年 12 月 5 日

跟 Ruby 社群混了一陣子後,我常常聽到「人性化介面」這個詞。它描述了 Rubyist 在撰寫類別介面時的一部分態度,我認為它也設定了 API 設計中兩個思想流派之間有趣的對比(另一個是 最小介面)。

人性化介面的精髓是找出人們想做的事,並設計介面讓常見情況下真的容易執行。

與最小介面的明顯對比在於,人性化介面往往大得多,而且人性化介面設計師不太擔心介面變大。這並不是說具有人性化介面的類別在實作上需要更大。兩者的基本功能通常相當類似。

觀察人性化介面和最小介面之間差異的一個好方法,是比較 Java 和 Ruby 中的清單元件。Java 有個介面 (java.util.List),宣告了 25 個實例方法。Ruby 有個 Array 類別(它是一個清單,不是陣列),有 78 個方法。大小上的差異在某種程度上暗示了這裡有不同的風格(儘管造成這種差異的原因還有更多)。兩個元件都提供基本的相同服務,但 Ruby 的陣列包含許多額外的功能。這些功能都是相對較小的東西,可以在 Java 的最小介面上建構。

我們舉一個小例子來說明差異:取得清單中的最後一個項目。在 Java 中,執行方式如下:

aList.get(aList.size -1)

在 Ruby 中,執行方式如下:

anArray.last

事實上,這比想像中更驚人:Ruby 的 Array 也有 first 方法,所以你可以使用 anArray.first 而不是 anArray[0]

還有更大的功能元素。Ruby 的 Array 有個 flatten 方法,可以將巢狀陣列轉換成單一層級。

irb> [1,2,[3,4,[5,6],7],8].flatten
=> [1, 2, 3, 4, 5, 6, 7, 8]

重點在於,所有這些功能,無論是像 last 一樣簡單,還是像 flatten 一樣複雜,都可以由客戶端自行撰寫,而不會增加清單類別的大小。極簡主義者傾向於專注於支援這些行為的必要方法的最小集合,而人性化設計師則會嘗試新增必要的其他方法。這些額外的方法通常稱為便利方法,極簡主義者並不認為這是個褒義詞。

這引發了一個問題:「決定應該新增什麼到人性化介面的依據是什麼?」如果你放進任何人都可能想要的東西,你會得到一個非常複雜的類別。人性化介面設計師會嘗試找出類別最常見的用途,並設計介面讓這些用途容易執行。

此原則不僅啟發您新增方法,也影響您命名它們的方式。在 RubyConf 中,Tanaka Akira 指出偏好為常用方法命名簡短名稱的價值。由於這些方法更常被使用,因此您會熟悉它們 - 如果你經常使用簡短名稱,很容易記住它們,而且它更實用,因為它節省了打字和閱讀的時間。一個例子是 DateTime 上的 parse 方法,它對常見的日期格式進行預設解析,以及更靈活的 strptime,它可以採用任何格式,但您使用得較少。

此命名原則與極簡主義方法並不衝突。的確,當 Java 的 List 介面出現時,它將舊有的 Vector 的 elementAt 方法變更為 get

Ruby 人性化介面哲學的另一個有趣後果是別名方法名稱。當您想要清單的長度時,您應該使用 length 還是 size?有些函式庫使用一個,有些使用另一個,Ruby 的 Array 兩者都有,標記為別名,以便任一名稱都呼叫相同的程式碼。Rubyist 的觀點是,函式庫同時擁有兩者比要求函式庫的使用者記住哪一個更容易。

您可以針對哪種介面設計風格最好而獲得冗長且乏味的執行緒。在這裡,我將嘗試總結支持人性化介面的論點(有關另一面的資訊,請參閱 MinimalInterface)。

物件的大部分優勢在於其行為,而非其資料。如果您只嘗試提供最少的功能,您最終會讓多個客戶端重複編寫常見情況的程式碼。在像 flatten 的情況下,您最終會讓一群人撰寫自己的遞迴函式。這不難,但如果這不是罕見的情況,為什麼他們要費心呢?

即使對於像 last 這樣的簡單情況,讀者也必須學習慣用語。當一個簡單的方法可以直接讀取時,為什麼他們必須看到間接的東西?好的軟體會優先考慮使用者,並讓他們的操作更輕鬆。人性化介面遵循此原則。

人性化介面會執行更多工作,以便客戶端不必執行。特別是 API 的人類使用者需要一些東西,以便他們的常見任務易於執行 - 對於閱讀和寫入都是如此。

雙方都有很好的論點。就我個人而言,我傾向於人性化介面方法,儘管我確實認為這比較困難。

後續追蹤

This one caused a bit of stir, which has led to some interesting and useful discussion. At some point I might put some narrative over the links to help you read them, until then I'll just list them. The debate was mostly triggerred by Elliotte Harold's short but robust criticism of the humane approach and James Robertson's reply (make sure you check the comments on Robertson's posts). Then came the deluge | Cees de Groot | Antonio Vieiro | David Hoefler | James Higgs | Peter Williams | Cedric Beust | John D. Mitchell | Stuart Roebuck | Elliotte Harold (2) | Jon Tirsen | Hitesh Jasani | Blaine Buxton | Ramnivas Laddad | Anders Noras | James Robertson (2) | Kieth Ray | James Robertson (3) | Elliotte Harold (3) | Charles Miller | Rob Lally | Bernard Notarianni | David Crow | Jim Weirich | Jim Weirich (2) | Ian Bicking | Brian Foote | Justin Gehtland | Tom Moertel | Antonio Vieiro (2) | Kris Wehner | The Server Side | Ravi Mohan | Danny Lagrouw | Piers Cawley | Peter Williams | Florian Frank | Chris Siebenmann .

還有更多,我尚未發現所有,而且我只針對那些我認為對辯論有幫助且避免謾罵的內容。有種傾向過度關注 Ruby 陣列與 Java 清單範例,而非基礎原則,但這是很自然的。這場討論有許多好的方向,如果我有機會,我會試著發展其中一兩個方向。

或者你可以閱讀 Joey deVilla 的文章,其中包含上述大部分內容的摘錄。