中文字幕无码久久精品,13—14同岁无码A片,99热门精品一区二区三区无码,菠萝菠萝蜜在线观看视频高清1

您當(dāng)前的位置是:  首頁 > 資訊 > 國內(nèi) >
 首頁 > 資訊 > 國內(nèi) >

【融云分析】如何保障 API 設(shè)計的穩(wěn)定性(內(nèi)含福利)

2019-06-24 11:13:41   作者:   來源:CTI論壇   評論:0  點擊:


  計算機行業(yè)有句名言 —— 計算機科學(xué)領(lǐng)域的任何問題,都可以通過增加一個間接的中間層來解決。
  當(dāng)前的計算機領(lǐng)域,無論廣度還是深度,已經(jīng)沒有一個人能完全掌握了。但是,通過各種中間層的組合使用,我們不需要了解其內(nèi)部細節(jié),也可以像搭積木一樣,開發(fā)出各種有趣的服務(wù)和應(yīng)用。
  而各個中間層之所以能組合工作,正是因為大家都通過定義好的 API 交互和通信。每個模塊在對外提供經(jīng)過抽象 API 的同時,也需要使用其他模塊的 API 作為自身運行的基礎(chǔ)。
  今天我們來聊聊融云在設(shè)計 API 過程保障穩(wěn)定性的一些實踐。
    無處不在的 API
  API(Application Programming Interface) 又稱為應(yīng)用編程接口。
  而接口,本質(zhì)可以理解為契約,一種約定。
  計算機接口的概念起源于硬件。早期各家研發(fā)的各種元器件都不通用也沒有標準,相互使用非常困難,于是大家約定了功能和規(guī)格,就產(chǎn)生了接口,后來蔓延到軟件中。
  接口蔓延到軟件之后,又分為ABI(Application Binary Interface)和API(Application Programming Interface) 。
  前者主要約定了二進制的運行和訪問的規(guī)則,后者則專注于邏輯模塊的交互。本文以下內(nèi)容僅討論開發(fā)者經(jīng)常接觸的 API。
  很多人對 API 的印象只是包含一些函數(shù)的 Class 或 頭文件。但 API 在我們生活中無處不在,只是我們有時并沒有注意到。
  比如,當(dāng)我們在撥打電話時,手機和基站通信的整個系統(tǒng)是非常復(fù)雜的。
  好在我們不需要了解內(nèi)部的細節(jié),僅需要把 11 位的電話號碼傳給“電話系統(tǒng)”的接口就可以,而隱藏的國家區(qū)號(如+86)可以理解為接口的默認參數(shù)。
  這個高度抽象的 API 背后,隱藏了非常多的細節(jié)。借助上面的中間層理論,我們可以系統(tǒng)性地討論設(shè)計一個 API 所需要考慮哪些內(nèi)容。
  1. 模塊對上層暴露的 API 如何被使用?
  API 從使用的耦合方式上,可以分為兩類:一種是通過協(xié)議調(diào)用,如調(diào)用 HTTP 接口;另一種是語言直接通過聲明調(diào)用。
  如設(shè)計 HTTP Restful API 時,并不需要關(guān)心使用者的操作系統(tǒng)、使用的編程語言、內(nèi)存線程管理等,因此會比后者簡單一些。
  API 從使用者的規(guī)模和可控范圍上,可以分為 LSUD(Larget Set of Unkown Developers) 和 SSKD(Small Set of Kown Developers) 兩種。
  前者一般都是公網(wǎng)開放的云服務(wù),任何開發(fā)者都可以使用,無法提前預(yù)知以何種姿勢被使用,版本也不可控制。融云提供的通信云就是這種 API。
  后者用戶群有限,一般都在同一家公司或團隊內(nèi)。比如前段時間比較火的組件化,即對內(nèi)提供的模塊化 API,使用范圍和方式均可控,在更新時一般不用太糾結(jié)向后兼容。
  API 的第一受眾是人,然后才是機器,所以“可理解性”在設(shè)計時需要優(yōu)先考慮。
  而良好的 API 文檔、簡單扼要的 Demo、關(guān)鍵的 log,可以提升 API 使用者的體驗。
  2. API 所屬模塊對下層有什么依賴?
  API 所屬模塊都運行在一定的地址空間中。而其中的環(huán)境變量、加載庫、內(nèi)存和線程模型、系統(tǒng)和語言特性都需要考慮。
  3. API 所屬模塊的內(nèi)部實現(xiàn)對其他層有什么影響?
  一般而言,設(shè)計良好的 API 在使用時,并不需要理解其內(nèi)部實現(xiàn)。但如果能了解其內(nèi)部架構(gòu)并輔助關(guān)鍵 log,有助于提升使用 API 的效率。
  并且模塊的內(nèi)部實現(xiàn),有時也會影響到 API 設(shè)計的風(fēng)格。
  如一個強依賴 IO 的接口,可能需要使用異步的方式。大量異步的方式,就衍生出了 RxJava 等框架。
  向后兼容
  因為 API 如此重要,涉及的范圍又如此廣泛,廣大開發(fā)者對 API 的向后兼容可以說要求非常高。
  畢竟誰也不想在開發(fā)過程中,頻繁的更新接口和代碼,想想《 swift 從入門到精通到再次入門到再再次入門》的慘案就心有余悸。
  我們不僅問,為什么很多公司或者項目都無法向后兼容,僅僅是投入不夠或不夠重視,還是說 100% 的向后兼容實際就是不可能的?
  假設(shè)設(shè)計是理想和經(jīng)過論證的,正如一個完美的圓圈。
  設(shè)計是要落實到編碼中的,而編碼的過程中總是不可避免的引入一些 bug,而帶著 bug 的某個版本實現(xiàn),其實正如一個 Amoeba 變形蟲,形態(tài)是不固定的。而隨著版本不斷演進,不可避免會產(chǎn)生一定的差異。
  第一個版本實現(xiàn):
  第二個版本實現(xiàn):
  所以說 100% 向后兼容本身就是不可能的。
  因此,大家平時在談?wù)?API 穩(wěn)定性時,其實默認是可以包含一定程度變更的。
  但由于 API 涉及的范圍太廣泛,保障向后兼容都需要極大代價。
  比如 Linux 就希望快速迭代,完全不保證 API 的穩(wěn)定性。針對這個問題,Linux 還特意寫了 stable-api-nonsense 文檔。有興趣的可以點擊閱讀:
  stable-api-nonsense.rst
  漸進式改進
  所以說,保障 API 的穩(wěn)定性會面臨很多挑戰(zhàn),比如:
  • 業(yè)務(wù)形態(tài)還不穩(wěn)定,還在高速發(fā)展
  • 業(yè)務(wù)和 API 歷史包袱較重
  • 多個平臺和語言的特性不一致
  • 用戶群和使用方式不明確
  我們回顧一下正常的開發(fā)流程,看看是否能通過一些指標和工具,改善 API 的穩(wěn)定性,主要涉及:需求、設(shè)計、編碼、Review、測試、發(fā)布、反饋等步驟。
  需求
  普通的產(chǎn)品開發(fā),在啟動的時候,用戶需求都比較明確,但對于 LSUD 的云服務(wù)而言,無法提前預(yù)知用戶群都有哪些,以及用戶在他的產(chǎn)品中如何使用 API。
  這容易造成,沒有明確的用戶需求,API 就不好進行設(shè)計和迭代,沒有設(shè)計就沒有用戶,需求更無從談起。這是一個雞生蛋、蛋生雞的問題。
  建議可以在 API 發(fā)布之前,內(nèi)部先針對典型的使用場景,設(shè)計幾個完整的 Demo,驗證 API 的設(shè)計和使用是否合理。
  需要注意的是,Demo 需要有完整應(yīng)用場景,達到上架地步,如果能內(nèi)部使用, Eating your own dog food 最好,過于簡單的 Demo 無法提前暴露 API 的使用問題。
  Demo 的開發(fā)人員最好與 API 的設(shè)計者有所區(qū)分,避免思維固化,更多內(nèi)容大家可以參照 Rust 語言開發(fā)在自舉過程中的一些實踐。
  設(shè)計
  在設(shè)計 API 的時候,有很多需要注意的點和普通開發(fā)不太一樣。
  普通開發(fā),快速實現(xiàn)功能始終被放在第一位。比如大家會用一些敏捷開發(fā)的方式,優(yōu)先實現(xiàn)功能再快速迭代等。
  但 API 設(shè)計時,接口無法頻繁變更,所以首先需要考慮的是“少”,少即是多。
  每個 API 做的事情要少
  一個接口只做一件事,把這個事情做好就足夠了。
  需要避免為了討好某個場景,在一個 API 上進行復(fù)雜的組合邏輯,提供一個類似語法糖的接口。否則,場景的業(yè)務(wù)自身在演進時,很難保證 API 的行為不變。
  如果需要支持多種業(yè)務(wù),可以考慮將 API 分層,比如融云客戶端的 API 會分為下面幾層。
  舉個例子,融云考慮通用性,基于訂閱分發(fā)的模型,抽象了 RTCLib,客戶端能處理媒體的任意流,非常的靈活,但是對于用戶而言開發(fā)代價可能高些,要思考和做的工作比較多。
  考慮到大量的用戶,其實需要的是音視頻通話的業(yè)務(wù),基于 RTCLib,融云分裝了不帶 UI 的 CallLib 以及集成了 UI 的 CallKit。
  如果一個用戶,需求和微信的音視頻通話類似,可以集成帶 UI 界面的 CallKit,開發(fā)效率會非常高;
  如果用戶對通話音視頻通話 UI 的交互有大量需求,可以基于 CallLib 進行開發(fā),對 UI 可以進行各種定制。
  暴露的信息要少 
  成熟的 API 設(shè)計者都會盡可能的隱藏內(nèi)部實現(xiàn)細節(jié)。
  比如字段不應(yīng)該直接暴露而是通過 Getter/Setter 提供,不需要的類、方法、字段都應(yīng)該隱藏,都已經(jīng)成為各個語言的基礎(chǔ)要求,在此就不細述了。
  但容易被忽略的一點需要提醒大家,應(yīng)盡量隱藏技術(shù)棧的信息。
  比如:API http://api.example.com/cgi-bin/
  get_user.php?user=100,就明顯混入了很多無用的信息,并且以后技術(shù)切換升級想維持 API 穩(wěn)定非常麻煩。
     行為擴散要少
  在語言直接調(diào)用的 API 中,需要避免基礎(chǔ)接口通過繼承導(dǎo)致行為擴散。
  在普通的編碼過程中,抽象類和繼承都是面向?qū)ο蟮膹姶笪淦。但是對?API,更建議通過組合使用。
  比如一個管理生命周期的類,如果被繼承,子類有些行為就有可能被修改而導(dǎo)致出錯。這時候建議使用 Interface + 工廠的方法提供實例。
  由于 Java 8 之前 interface 沒有 default 實現(xiàn),為了避免增加功能需要頻繁修改接口,可以使用 final class。
  Objetive-C則可以使用 __attribute__ ((objc_subclassing_restricted))和__attribute__((objc_requires_super))控制子類繼承行為。
  畫風(fēng)切換要少
  API 命名要做到多個平臺的業(yè)務(wù)命名統(tǒng)一,與每個平臺的風(fēng)格統(tǒng)一。
  這點 HTTP 的接口要簡單一些,只需要選定一種風(fēng)格即可,Restful 或者 GraphQL 或者自己定義。
  語言調(diào)用的 API 命名,建議首先遵循平臺的風(fēng)格,然后再是參考語言標準,最后才考慮團隊的風(fēng)格。
  比如:iOS 平臺的 API 開發(fā),需要首先參照 iOS 的命名風(fēng)格,did 和 will 之類的時態(tài)就非常有特色。
  命名上細節(jié)較多,詞匯、時態(tài)、單復(fù)數(shù)、介詞、?小寫、同步異步風(fēng)格等都需要考量,需要長時間的積累。
  理解成本要少
  一般 API 每個接口都會有相應(yīng)的注釋說明,但是值得注意的是,大部分開發(fā)者并不看注釋。
  大部分開發(fā)者對接口的了解,都僅源于 IDE 的補全和提醒。一個接口看著像就直接用,不行再換一個試試,這其實是一種經(jīng)驗式編程的方式。也就意味著接口命名需要提高可理解性。有一個辦法可以驗證,將接口的所有注釋抹掉,使用者能否非常直接的看懂每個接口的含義。如果很困難,則需要改進。
  API 設(shè)計還有一處和普通開發(fā)不太一致。普通開發(fā)設(shè)計好架構(gòu)即可,每個模塊的開發(fā)可能是同一個人,接口并不需要在設(shè)計時確定下來。但是 API 的設(shè)計階段,需要進行 Review 并直接確定接口的設(shè)計,以保證多端在開發(fā)時遵循完全一直的規(guī)則。
  編碼
  在 API 的編碼過程中,有以下幾點需要注意。
  1、在 API 中,預(yù)定義好版本號。
  這個主要是針對 HTTP API,如:
  http://api.example.com/v1/users/12345?fields=name,age。
  如果目前僅有一個版本,也可以暫時不加,第二版時再區(qū)分。
  2、注意 API 版本檢查。
  當(dāng)分層提供多種 API 時,每層 API 需要在啟動時,先校驗一下版本號,避免不匹配的情況。
  比如在以下 Java 代碼中,大家可能覺得判斷版本號相等的代碼非常奇怪,應(yīng)該永遠是 true 才對。
  但是抽象類和實現(xiàn)類出現(xiàn)在不同的分層模塊中,并且實現(xiàn)類先編譯,抽象類版本更新后再編譯,就會出現(xiàn)不一致的情況。有很多語言或平臺能提供類似的方式來確定版本。
  3、提供規(guī)范性的 log 輸出。
  普通開發(fā)的log,主要用于自己定位問題。但是 API 在編碼時,最好針對性的添加一些 log,有利于 API 的使用者理解并簡單排查問題。但出于性能考慮,需要定義好 log 的級別并可以調(diào)整。
  4、注意廢棄與遷移。
  當(dāng)一個以前設(shè)計的 API 不再符合要求或者有重大問題時,我們可以對外標記成已廢棄,并在注釋中建議使用者遷移到另一個接口。如果是類似的被廢棄接口,內(nèi)部編碼時最好能使用新的接口來實現(xiàn),以降低向后兼容的維護成本。HTTP 的 API,需要預(yù)定義好遷移的錯誤碼,比如在 HTTP 規(guī)范中,可以使用 410 Gone 說明已經(jīng)不再支持某個接口。
  Review
  API 的 Review 基于普通開發(fā)的 Code Review。如果基礎(chǔ)的 Code Review 都沒有做好,肯定無法保障 API 的質(zhì)量和穩(wěn)定性。
  可以通過一些工具,為 API 的 Review 提供一些參考報告。比如可以使用 SonarLint 分析代碼復(fù)雜度,如果接口層的代碼復(fù)雜度較高,會是一個危險的信號。還可以借助 Java 反射、Clang 語法分析,獲取當(dāng)前的 API 接口列表,生成接口變更報告,也有利于減少無用接口的暴露。另外,自動化工具生成的接口文檔也是 Review 重要的一環(huán)。
  測試
  在測試環(huán)節(jié),我們可以通過 unit test 來關(guān)注 API 的穩(wěn)定性。與敏捷開發(fā)經(jīng)常修改 test case 不同,API 的 test case 基本代表了接口的穩(wěn)定性。所以在修改舊 case 時需要特別明確,是 case 自身的 bug 還是接口行為發(fā)生了變更。
  發(fā)布
  我們可以通過區(qū)分 dev 和 stable 版本,為不同階段的開發(fā)者提供更好的體驗。
  dev 版本包含最新的功能,但是 API 接口有變更風(fēng)險。stable 版本 API 穩(wěn)定,但功能不一定是最新的。如果開發(fā)者還在開發(fā)過程中,可以選用最新的 dev 版本,基于最新 API 開發(fā)。如果應(yīng)用已經(jīng)上線,可以選擇升級直接到最新的 stable 版本。
  反饋
  由于前面提到的,云服務(wù)的 API 比較難確定用戶群和用戶的使用方式?梢詤⒖ APM(Application Performance Management) 的方式,記錄熱點 API 使用情況,為后續(xù)的優(yōu)化提供數(shù)據(jù)。
  總結(jié)
  上面的改進,讓保障 API 的穩(wěn)定性變得更容易。下面以融云 IMLib iOS SDK 2.0 版本演進為例,歷盡 2015至 2019 四年時間,從 2.2.5 到 2.9.16 共 98 個版本。API 接口數(shù)量翻了一番,考慮到接口更內(nèi)聚,功能大約增加了 3 倍。
  但是需要用戶遷移的接口非常少,即使遷移時開發(fā)成本都非常低。


  看完整篇文章大家是否get到了保障 API 設(shè)計的穩(wěn)定性方法
  下面小編來考考大家,答題還有禮品拿哦
  參與方式:
  • 在文末下方留言區(qū)寫下你的答案
  •  獲得點贊排名前5的小伙伴,可獲得定制禮包(定制T恤和8G U盤)
  • 點贊沒那么高也不要灰心,小編會在精選留言中抽出5個小伙伴送出單項禮品(定制T恤)
  活動時間:
  即刻起至 6 月 26 日 9:30
  中獎公布:
  中獎結(jié)果將于下周推文公布
  快來答題吧:
 、 API 是不是可以做到 100% 的向后兼容?
  A.  是
  B.  不是
 、 HTTP API 如果不幸發(fā)生永久遷移,可以使用什么 HTTP 錯誤碼?
  A.  302 Moved Temporarily
  B.  404 Not Found
  C.  410 Gone
  ③ 開發(fā)者還在開發(fā)過程中,可以選用融云的最新___版本,基于最新 API 開發(fā)。
  A.  dev 版本
  B.  stable 版本
  C.  beta 版本
【免責(zé)聲明】本文僅代表作者本人觀點,與CTI論壇無關(guān)。CTI論壇對文中陳述、觀點判斷保持中立,不對所包含內(nèi)容的準確性、可靠性或完整性提供任何明示或暗示的保證。請讀者僅作參考,并請自行承擔(dān)全部責(zé)任。

專題

CTI論壇會員企業(yè)