轉自oschina 參與翻譯(14人):git
我最常作的開發任務是設計一個可重用的API組件。組件一般爲iOS(儘管有時它們是OS X) 設計的,且老是GUI控件或某種視圖。github 多年來,我爲客戶開發了不少API組件,其中包括像Apple這樣的客戶,並且我已經很瞭解這個過程。我也按期發佈開源組件,而且我把曾經對我有幫助的資料和API設計指南放在一塊兒與你們分享。api 這是一個重要的主題,不管你是一個開源貢獻者,或做爲團隊的一員參與開發大型的應用,或者只是設計本身的軟件。正如開發一個應用的過程,API接口是使用你代碼的開發者對你代碼的第一印象,將嚴重影響着開發者決定是使用或扔掉它。架構 APIs是開發者的用戶體驗。我一直驚訝,具體到這個流行平臺上沒有不少的資料是寫咱們這方面工做的。app 當咱們閱讀一些設計指南時,必要的時候,我將要用我最近發佈的開源GUI組件MGTileMenu做爲一個例子。你能夠在這裏先閱讀全部關於MGTileMenu的信息,若是你喜歡。框架 |
hyaicc
|
其它翻譯版本(1) |
如何使人滿意應用程序接口(API)設計和用戶界面、用戶體驗設計很相像。你的目標用戶有不一樣的需求和特色,但歸根結底他們的目標仍是把需求完成而已。就像一個設計友好、易用的應用程序的用戶界面同樣,你須要讓你的API有如下的特色:函數
如同人們設計的其它的軟件同樣,咱們首先須要考慮的是使用案列。咱們的設計須要使最常常被用到的的功能簡單易用,不須要過分的配置。在默認配置下軟件就應該是可用的,而且具備必定的可配置性。軟件的設計應該具備可探索性,並且應該容許用戶從已知的的範例中推廣到其餘應用場景。這和咱們建立一個用戶界面的規則很是的相像。工具 |
WangWenjing
|
其它翻譯版本(1) |
開發者的界面用於和開發者交互的元素使用四個主要的顯示意味着:
咱們須要把每個都設計成:明智和慎重的,用於人類使用。這裏有2個問題當你設計API的時候須要考慮:
咱們的核心原則是讓已有的類和模型保持一致性,以用來保證咱們能夠把一個開發者不熟悉的控制讓他很輕鬆的在他能夠理解的平臺上使用。使用標準APIs,模型,和模式不管是否是可能(而且這個應該是總用的)。對於終端用戶,熟悉和直覺性是和代碼層級同樣重要的。 讓咱們看看咱們以前提到的這四個元素: |
周榮冰
|
其它翻譯版本(1) |
類接口Here’s the interface file for MGTileMenu. 在咱們討論具體的接口以前,這有一些涵蓋範圍比較普遍的規則: Rule 1: 使用方言我所看到最多見的錯誤是API的設計利用了外來的約定。APIs 屬於固定平臺和固定的開發者生態系統。你根本沒法使用任何習語和你用過的其餘平臺的架構,這樣作會污染您當前的代碼庫,並對其餘開發人員的效率形成損害。 在coding以前要了解你目標平臺的約定,好比,在iOS 或者 OS X,不使用異常對待control的流程 。以適當的方式命名你的方法(一般指有足夠詳細,但也應該有足夠的簡潔)。 瞭解協議,和委託,類別分別是什麼。在你的代碼中使用他們。學習相關的構造函數和析構函數的命名方案。請遵照內存管理規則。詞彙和語法是不可分割的,你要麼發展爲一個固定的的平臺,或者你跨平臺。 |
魏濤
|
Rule 2: 設計解耦任何component的設計應該沒有鏈接到你當前建立的項目,若是他是一個GUI control或者一個視圖,它應該默認顯示一些東西。使用現有的框架做爲一個指南,與委託協議,精心設計的/命名的API方法和通知在適當的地方保持鬆耦合。 一個很明顯的,但很是有效的方式,是每次爲你的component建立一個項目,並逐漸的隔離開發component。強迫本身使用本身的API。遠離無關的類。 接下來,讓咱們來適當談談類的接口。初始化方法的接口中最重要的部分之一,由於他們是人們如何開始使用您的組件。你的類將有必定的初始配置所需的設置。因此,一個明顯的規律: |
魏濤
|
其它翻譯版本(1) |
Rule 3: 必須設置初始化參數若是有什麼須要設置的,不要等待 -須要它了就去作,若是你沒有獲得的東西的當即返回nil。
Rule 4: 容許訪問初始化參數Allow access to initializer parameters這個前一個結果的必然結果: 記住不要僅僅傳入參數,應該能夠經過屬性或者賦值來訪問他們,若是他們能夠經過任何方式來一場「按摩」(修改,重寫等)
|
魏濤
|
||||
其它翻譯版本(1) |
Rule 5: 註釋你的header文件 (包含默認值)實際上,你不總爲component提供單獨的文檔。若是你不提供文檔,你的.h文件(包括demo app)就是你的文檔。他們應該適當的描述,個人意思是:
特別是,你應該簡要註釋在屬性或訪問器旁邊;頭文件掃描比在初始化實例的時候更容易。
|
魏濤
|
||||||
其它翻譯版本(1) |
Rule 6: 習慣於運行3行代碼你的類應該設計成只須要最少的代碼來集成(包括後續將用到的委託/數據源協議)。但不包括委託方法,你應該着手於用3行代碼就能夠達到測試的目的。 這3行代碼以下:
|
haoio
|
||||||||||||||||
其它翻譯版本(1) |
Rule 7: 臃腫的demo一般意味着組件是糟糕的另外一個推論:您的demo的大小是衡量你component質量的標準,其值越小越好。Demo/Code 應該儘量的小巧而又精簡(用於演示,旨在描述全部組件的定製或功能)。 核心思想是當你的代碼從你的空的Xcode項目模板到你的demo中應該保持最小化的修改。這並非一個好的藉口當你須要複製粘貼demo來讓你的component運行。 |
魏濤
|
Rule 8:分析特定的場景我對於apps的準則就是:不要讓用戶去作選擇。選擇知足多數人的人性化的默認設置,略去參數設置窗口。畢竟,好的軟件都是有傾向性的。 因爲運用場景不是那麼的清晰明確,因此不一樣的組件面對的狀況也有些不一樣。你固然能夠作一個只知足某種特定狀況的組件,可是,一般咱們都但願有些靈活性。你毫不會準確的知道另外一個開發者將會怎樣使用你的組件,因此你必須作到有必定的通用性。 認真的選擇你的定製點是很重要的。考慮依賴關係更加的重要——不是對編譯/連接的理解,而是定製類型之間的邏輯關係。個人方法就是儘可能從「方面」的層次上考慮而不是實例變量的層次上。你但願你的組件的那些方面容許被定製化?那麼你就知道哪些特定的屬性須要暴露。 經過不暴露足夠的的配置點,就能夠很容易的弱化某個特定的定製類型。例如:1.若是沒有考慮圓角半徑,就不要暴露寬度和高度。 2.若是沒有高亮的背景顏色,就不要暴露背景顏色。 3.若是沒有空間,就不要暴露大小。 具體的狀況取決於具體的組件,可是須要從外觀或者功能角度來考慮屬性之間的關係。學會理解開發者。不要禁止組件的個性化,讓它靈活些。
|
crAzyli0n
|
Rule 9: 多點屬性,少點方法有一個特定的模式持續出如今我所喜歡的一些來自標準庫、開源的第三方以及我本身的一些代碼組件。它是一個組件中屬性(或者訪問器,定製點)個數與方法(也就是全部其它的,從初始化到狀態更新)個數的比率。 多屬性少方法(再申明一次,方法不是指在Interface Builder中的那些)。MGTileMenu有一個初始化函數和四個實際上供公共使用的願意很是(每個都很方便調用另外一個方法)。對定製點而言,它的比率有4倍之多。我認爲這是一個很是好的比率,使組件不但在功能上變得簡潔,並且在定製時更加靈活。
|
showme
|
Rule 10: 在你的控件中使用控件 一個同時簡化組件API和實現的好方法就是在你的實現中使用己有的控件。具備統一的外在並不意味着你不可使用已經存在的組件(確實,這是軟件工程當中的一個基本原則)。 考慮是什麼讓UITableViewCell和UIButton擁有簡單的API接口,發現這是由於它們使用諸如UIImageView和UILabel這樣的子控件。你也能夠,而且該這樣去作,而且若是可行的話使用相應的子控件來使你的類接口保持簡單不變。 舉個例子,在MGTileMenu中,它的外表是常規的UIButtons(不僅是子類)。跟在一個的view中自定義去畫它的樣式、處理輸入事件和支持訪問而言,極大地簡化了它的實現。 |
showme
|
Rule 11: 於人方便就是於己方便你會很天然地在實現的過程當中加入合適的方法並下意識地將其設置爲私有的。相反,應該考慮是否能夠公開這些方法,使這些組件能被集成到別人的應用程序。 對你而言那些如何簡單方便地加入一個方法或函數的方式,對開發者而言一樣如此。 舉例來講,在MGTileMenu中,我建立了這些合適的函數:
|
showme
|
Rule 12:魅力能夠,魔數卻不行。你早晚都會在你的component中加入一些魅力。人人都但願有大量的Steve Jobs式的直觀、宜人、富於掌控力的魅力,可是我所說的倒是代碼中的一些東西,諸如擁有特殊含義的數字或者值。例如,-1在某項設置或者某個特殊場景中,就有着某個特定的意義。 很好,那樣作真的挺好的。不爽的是你的代碼中充滿一些莫名其妙的原始值,更不爽的是還將它們暴露在API中。若是你正在暴露一些魔數,那麼爲了便於使用,最好仍是用#define或者常量或者其餘的東西包裝一下它們,這樣會讓魔數更加的直觀和易於理解。
|
crAzyli0n
|
代理和數據源協議代理協議是奇妙的。它們是實現MVC模式的簡單的、熟悉的和靈活的方式,它們更會使你養成鬆耦合的好習慣而且教你明智的API設計。 這個是 MGTileMenu’s delegate protocol. 有太多經典的代理和數據源協議供咱們用到幾乎全部的組件中。若是你正在顯示數據,這個準確的數據源協議可能更接近於:
一樣的,在幾乎任何的狀況中,這個準確代理協議可能採用下面的形式:
這也被稱爲Should, Will, Did協議模式,這也巧妙的連結了以後的Will-Did通知模式。 讓咱們來討論一下你可能會以爲有爭議的話題:我發現將代理協議合併到數據源協議中被完美的接受了(也就是說將他們整合到一個協議中)。我在MGTileMenu和幾個其餘的組件中這樣作了。 我徹底接受分離他們的原則,而且我能想到不少你想保持他們分離的例子。一般,蘋果也是保持他們分離的。那好吧。 但是,就個人經驗看,在大多數例子中合併他們是很好的。大多數人將數據源方法和代理方法放到同一個地方。我歷來沒有由於合併這些協議而抱怨過,我幾乎不能記得一個存在分開的協議在不一樣的地方使用的狀況。 若是你重視清晰,或者有將代理從數據源中分離出來的需求,那麼很明顯你應該那樣作。我只是不認爲若是你合併他們會以爲很差。 |
李遠超
|
規則 13:限制‘required’代理方法的數量 當你選擇設置哪些代理方法爲required(必須實現)時必定要當心。太多的required方法將會代表:
一個精心設計的組件應該有不多不多required代理方法-僅僅是那些不得不的方法。當心選擇。一樣的,記住再後來添加optional(可選擇實現)方法是很簡單的,可是添加required方法就很是的困難(不少時候人們會抱怨)。 在MGTileMenu中有5個required方法,其中有4個是數據源方法:
前兩個屬於一個真正的數據源協議。第三第四個也是,可是這也代表了個人觀點:我認爲軟件應該是容易理解的,而且我正在強制你爲每個tile提供一個標籤和表述來共讀者們閱讀。我很享受這些。 固然也有一個代理方法
這個方法是required,由於他告訴你如何來發現一個tile是激活狀態的。若是你不打算實現這個方法,MGTileMenu將不會作任何有用的事情,甚至你可能就根本不能用它。因此他是必須實現的。 |
李遠超
|
規則 14:設計成容易理解的 馬上跟上這最後的規則:使設計是容易理解的。不要在最後才注意到它,偏偏相反,應該是在起初就設計成容易理解的。若是你遵循了「在你的控件中運用控件」原則,那麼你可能在不知不覺中就遵循了這個原則。 上面展現的代理(倒不如說是數據源)方法是另外一個開發者爲了使他們給語音輔助提供一些東西的地方。 若是你可以在視覺上(就像展現一個文本標籤)自動地改變一些事情的意圖就像一個語音輔助標籤那樣,那該多好啊(此外,在大多數例子當中語音輔助已經爲你實現了這個)。 在交流方面保持清醒。作到不容易理解的設計卻是困難的。我也寫了另一篇關於在IOS應用中支持語音輔助功能的文章,這也是蘋果向在容易理解的程序有聯繫的合夥人們推薦的。我也推薦它,可是我寫它就是爲了你能夠接受它。 |
李遠超
|
規則 15:利用語義對象來作參數 這不只僅適用於協議,但協議是尤爲重要的部分。最好是在實際應用中,用合適的語義對象做爲數據,雖然在你的實現中這樣作可能會更加的麻煩。 若是你須要一個日期,不要用一些數字-而應該是一個真實的日期對象。對象或者結構體能夠表示每同樣事物,而且你應該有意地去用它們。若是須要的話能夠建立一個類(你可能不會須要)。 固然一個標準的目錄除外-除了基元沒有任何理由能夠把他們變成任何事物,自從NSNumber的加入,對於抵消打包/非打包帶來的麻煩沒有任何事物是語義地足夠重要的。 |
李遠超
|
規則 16:若是語義不合適的話就提升API 我時刻都在注意這一點。我曾在早些時候提到過,你怎麼能就像一些事物已經存在(一般,就像是已經存在了的在你的實現中無心間用到的東西)了那樣考慮幾乎任何新的定製的控件呢? 那很是好,而且你是很聰明的,可是不能讓語義賽過類似點。爲了使語義合適,在一個已經存在了的API上疊加一個新的API絕對是好的(或者漂亮的)。例如:
諸如此類的等等。不要時常地強制你本身(或者其餘的開發者)在抽象的實現API和真實的組件語義之間作精神上的轉變 - 反而應該讓這個API反映出組件真實的目的。 MGTileMenu 的代理協議經過不把菜單當作UIBUttons(實現了的)的集合而寧肯說是菜單的統一作到了這一點,利用每一個菜單中相關的有限的tile來展現內容。 |
李遠超
|
Rule 17: 高亮是有趣的當我不得不回過頭來添加一個新的代理方法和通知到我認爲已經完成了的API中,我才意識到這一點。對交互控件來講,高亮是有趣的。經過「高亮」,意味着其在應用程序中潛在的重要性。 任何控件都會通知App(在某種意義上來講,可能只是經過調用一個動做或方法),當它被徹底觸發時;可是當它們被高亮(選中,按住)或取消高亮被觸發時,只有比較少的狀況纔會通知。這說明它實際上很是重要。應用程序可能須要:
|
showme
|
Rule 18: 可選的方法不是一個保證咱們大部分人都把可選的委託方法當作二選一的情形:若是你不實現他們,就使用默認的行爲;若是你要實現他們,那你就要爲將發生的事情所有負責。那不是理想的事情。 在任何的提供一個可選的委託方法的實現中,你應該仍然返回去默認的行爲,即便這個方法已經被實現了,但不要返回一些明顯的東西。這聽起來很明顯,可是使人驚訝到底有多少組件無憂無慮地而後委託對象返回任何類型沒有通過精細檢查的愚蠢東西,僅僅是由於這委託莫名奇妙地答應經過實現這個方法來管理本身的行爲。 我要具體地討論下可視化的定製,如背景顏色和圖片。很是很是仔細地考慮下,你是否不該該去幹涉那種狀況,同時依靠於你的默認界面。他們真的不想展現些東西嗎?甚至讓感受好一點?它會讓控制看起來很糟糕嗎?若是如此,插手介入吧,同時僅在若是委託方法歷來不在開始的地方就實現的時候準備默認的。 相關地,用一個有文檔的、標準的及不是很突兀的方式去慎重地從每一個可選的委託方法中經過返回一些如空的東西來執行默認的行爲。 例如,MGTileMenu有一個比較複雜的層次方式讓你能夠自定義標題的背景。你能夠實現三個委託方法中的任何(或者所有,或者不)方法去爲每一個標題提供一個背景圖片、梯度或者顏色。你也可以在任什麼時候候爲任何標題選擇默認的行爲,經過返回空或者NULL等適當的類型。 你將不得不嘗試至關困難地去使標題的背景透明(經過返回清澈的顏色或者使用空的UIImage對象)。 |
throwable
|
Rule 20: 在查詢方法中首先放置可區分的參數一個真正的數據源協議總有將最感興趣東西放在前邊的方法。好比,你請求的指定質量或屬性等。像這樣:
不要像這樣:
返回類型天然而然應做爲方法名的第一部分,這並不會另人奇怪(請注意上邊兩個函數的不一樣處)。數據源協議中常常有許多命名類似的方法,所以咱們應該最早考慮保持函數的惟一性和感興趣部分。這樣的話,(這些方法)更容易讀,更容易作到自動補全。 有人指出:Apple公司的UITableViewDataSource協議並無按照那些作,他們是把sender放在第一位的,例如:
|
weizhe72
|
Rule 21:在通知方法中把sender放到第一位一個真正的委託(Deletage)協議不是用來查詢,而是用來通知的。在這種狀況下,你應該將sender放到第一位(參考 「說出誰正在說話」 規則)。
取而代之,你應該說出誰正在說話。這是一個習慣,能夠很方便地將查詢(數據源)與通知(委託)方法區分開來。 |
weizhe72
|
規則 22:若是約定被打破了,那就拋開它吧! 上面已經說了這麼多,記住約定和一致性必定是在某些時刻要屈服於優秀的觀點的 - 在這個例子當中,或者你的例子中。若是約定被打破,那就好不擔憂的去跳過它。若是你的觀點真的更好,那就去作吧! 舉個例子,在菜單控件中已經存在一個約定了,靠這個約定你可以經過代理來使菜單選項可用或者不可用,利用calledvalidateMenuItem:方法。爲了一致性的緣故,我曾考慮過給我代理協議中的一部分方法用相同的名字。可是我最終決定沒有那樣作,由於:
相反的,我繼續爲了更簡單而且更加的容易理解而打破了約定:
咱們可以爲了特殊的語法而戰,可是當你遇到那個方法時,你應該馬上就知道它是作什麼的?如何來使用它。我認爲,那樣會更好。 |
李遠超
|
通知通知是委託協議的另外一部分。我認爲,若是你使用委託協議(若是合適,你應當用它),你最好加上通知,否則它不算完整。 在 MGTileMenu 中,你能夠在 MGTileMenuController 的接口文件 中找到的通知。 |
Khiyuan
|
規則 23:通知和代理方法並行 在代理方法(注意;不是數據源方法)和通知之間有一個剪不斷理還亂的聯繫。在你的代碼中一樣的地方你會同時用到它們,而且起到一樣的做用。 若是一個代理方法告訴代理髮生了一些事情,你一般應該爲了起到相同的做用發送一個通知。就像代理方法同樣加上通知,去除掉模棱兩可的方法,而且落實你的通知列表。 代理方法的參數應該和通知的userInfo的內容相匹配,這是很明顯的除非你做爲對象來傳遞sender,而不是捆綁在字典信息中。 代理方法:
|
李遠超
|
||||||||
其它翻譯版本(1) |
Rule 24: 通知關聯的 userInfo 要儘可能詳細儘可能爲通知提供有用的信息。記住:通知接收方(很)可能與你組件裏面的代理方法或者數據源鏈徹底無關。 你要想一想到底哪些信息會有用,並提供相應的信息。至少,你必需確保代理方法的全部參數都包含在 userInfo 對象裏。 代理方法:
|
daxiaoming
|
Rule 25: 最終測試 最終有些事咱們已經知道了. 軟件工程和敬業精神的第101條: 確保它真地有效. 是否用正式TDD測試取決於你,可是測試是不可缺乏的。每一個可選的委託方法。每個發佈的通知。定製的每一個點,在每個可能的組合。組件提供了一千個微妙的問題的機會。 可能有一些缺陷。找到他們,先解決這些問題。若是你的時間推後,切功能,而不是調試。你要受的苦沒有出貨的錯誤。 |
寂寞沙洲
|
最後的思考我制定上述的規則是經過我本身這幾年在建立components和APIs時所犯的錯誤中總結的。我也努力的嘗試的遵照我制定的規則,可是不免的在某些狀況下我沒有。 雖然不可能在每一個場景or每一個事件中應用到這些規則,可是若是儘量的遵循這些規則,你將可能創造出一個設計良好的,靈活,可重用的components。讓其餘人一塊兒享用的components。 你也許想要一個簡單的提綱關於這些規則,下面的圖片就是。我有全尺寸的圖片版本託管在Flickr上。 若是你喜歡發佈本身的components給別人去使用,就像個人MGTileMenu同樣。那麼也許你也想去讀讀我發的open source code(開源代碼),其中幾個點也許會觸及到。這篇文章也討論了一些README文件,協議選擇的相關事宜。 |