97成人免费视频,97视频免费公开成人福利,免费视频99,99婷婷,国产伊人久久,亚洲视频欧美,国产精品福利久久

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

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

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


  計算機行業(yè)有句名言 —— 計算機科學領(lǐng)域的任何問題,都可以通過增加一個間接的中間層來解決。
  當前的計算機領(lǐng)域,無論廣度還是深度,已經(jīng)沒有一個人能完全掌握了。但是,通過各種中間層的組合使用,我們不需要了解其內(nèi)部細節(jié),也可以像搭積木一樣,開發(fā)出各種有趣的服務(wù)和應用。
  而各個中間層之所以能組合工作,正是因為大家都通過定義好的 API 交互和通信。每個模塊在對外提供經(jīng)過抽象 API 的同時,也需要使用其他模塊的 API 作為自身運行的基礎(chǔ)。
  今天我們來聊聊融云在設(shè)計 API 過程保障穩(wěn)定性的一些實踐。
    無處不在的 API
  API(Application Programming Interface) 又稱為應用編程接口。
  而接口,本質(zhì)可以理解為契約,一種約定。
  計算機接口的概念起源于硬件。早期各家研發(fā)的各種元器件都不通用也沒有標準,相互使用非常困難,于是大家約定了功能和規(guī)格,就產(chǎn)生了接口,后來蔓延到軟件中。
  接口蔓延到軟件之后,又分為ABI(Application Binary Interface)和API(Application Programming Interface) 。
  前者主要約定了二進制的運行和訪問的規(guī)則,后者則專注于邏輯模塊的交互。本文以下內(nèi)容僅討論開發(fā)者經(jīng)常接觸的 API。
  很多人對 API 的印象只是包含一些函數(shù)的 Class 或 頭文件。但 API 在我們生活中無處不在,只是我們有時并沒有注意到。
  比如,當我們在撥打電話時,手機和基站通信的整個系統(tǒng)是非常復雜的。
  好在我們不需要了解內(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ā)者都可以使用,無法提前預知以何種姿勢被使用,版本也不可控制。融云提供的通信云就是這種 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è)計的風格。
  如一個強依賴 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ù)而言,無法提前預知用戶群都有哪些,以及用戶在他的產(chǎn)品中如何使用 API。
  這容易造成,沒有明確的用戶需求,API 就不好進行設(shè)計和迭代,沒有設(shè)計就沒有用戶,需求更無從談起。這是一個雞生蛋、蛋生雞的問題。
  建議可以在 API 發(fā)布之前,內(nèi)部先針對典型的使用場景,設(shè)計幾個完整的 Demo,驗證 API 的設(shè)計和使用是否合理。
  需要注意的是,Demo 需要有完整應用場景,達到上架地步,如果能內(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 上進行復雜的組合邏輯,提供一個類似語法糖的接口。否則,場景的業(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é)。
  比如字段不應該直接暴露而是通過 Getter/Setter 提供,不需要的類、方法、字段都應該隱藏,都已經(jīng)成為各個語言的基礎(chǔ)要求,在此就不細述了。
  但容易被忽略的一點需要提醒大家,應盡量隱藏技術(shù)棧的信息。
  比如:API http://api.example.com/cgi-bin/
  get_user.php?user=100,就明顯混入了很多無用的信息,并且以后技術(shù)切換升級想維持 API 穩(wěn)定非常麻煩。
     行為擴散要少
  在語言直接調(diào)用的 API 中,需要避免基礎(chǔ)接口通過繼承導致行為擴散。
  在普通的編碼過程中,抽象類和繼承都是面向?qū)ο蟮膹姶笪淦鳌5菍τ?API,更建議通過組合使用。
  比如一個管理生命周期的類,如果被繼承,子類有些行為就有可能被修改而導致出錯。這時候建議使用 Interface + 工廠的方法提供實例。
  由于 Java 8 之前 interface 沒有 default 實現(xiàn),為了避免增加功能需要頻繁修改接口,可以使用 final class。
  Objetive-C則可以使用 __attribute__ ((objc_subclassing_restricted))和__attribute__((objc_requires_super))控制子類繼承行為。
  畫風切換要少
  API 命名要做到多個平臺的業(yè)務(wù)命名統(tǒng)一,與每個平臺的風格統(tǒng)一。
  這點 HTTP 的接口要簡單一些,只需要選定一種風格即可,Restful 或者 GraphQL 或者自己定義。
  語言調(diào)用的 API 命名,建議首先遵循平臺的風格,然后再是參考語言標準,最后才考慮團隊的風格。
  比如:iOS 平臺的 API 開發(fā),需要首先參照 iOS 的命名風格,did 和 will 之類的時態(tài)就非常有特色。
  命名上細節(jié)較多,詞匯、時態(tài)、單復數(shù)、介詞、?小寫、同步異步風格等都需要考量,需要長時間的積累。
  理解成本要少
  一般 API 每個接口都會有相應的注釋說明,但是值得注意的是,大部分開發(fā)者并不看注釋。
  大部分開發(fā)者對接口的了解,都僅源于 IDE 的補全和提醒。一個接口看著像就直接用,不行再換一個試試,這其實是一種經(jīng)驗式編程的方式。也就意味著接口命名需要提高可理解性。有一個辦法可以驗證,將接口的所有注釋抹掉,使用者能否非常直接的看懂每個接口的含義。如果很困難,則需要改進。
  API 設(shè)計還有一處和普通開發(fā)不太一致。普通開發(fā)設(shè)計好架構(gòu)即可,每個模塊的開發(fā)可能是同一個人,接口并不需要在設(shè)計時確定下來。但是 API 的設(shè)計階段,需要進行 Review 并直接確定接口的設(shè)計,以保證多端在開發(fā)時遵循完全一直的規(guī)則。
  編碼
  在 API 的編碼過程中,有以下幾點需要注意。
  1、在 API 中,預定義好版本號。
  這個主要是針對 HTTP API,如:
  http://api.example.com/v1/users/12345?fields=name,age。
  如果目前僅有一個版本,也可以暫時不加,第二版時再區(qū)分。
  2、注意 API 版本檢查。
  當分層提供多種 API 時,每層 API 需要在啟動時,先校驗一下版本號,避免不匹配的情況。
  比如在以下 Java 代碼中,大家可能覺得判斷版本號相等的代碼非常奇怪,應該永遠是 true 才對。
  但是抽象類和實現(xiàn)類出現(xiàn)在不同的分層模塊中,并且實現(xiàn)類先編譯,抽象類版本更新后再編譯,就會出現(xiàn)不一致的情況。有很多語言或平臺能提供類似的方式來確定版本。
  3、提供規(guī)范性的 log 輸出。
  普通開發(fā)的log,主要用于自己定位問題。但是 API 在編碼時,最好針對性的添加一些 log,有利于 API 的使用者理解并簡單排查問題。但出于性能考慮,需要定義好 log 的級別并可以調(diào)整。
  4、注意廢棄與遷移。
  當一個以前設(shè)計的 API 不再符合要求或者有重大問題時,我們可以對外標記成已廢棄,并在注釋中建議使用者遷移到另一個接口。如果是類似的被廢棄接口,內(nèi)部編碼時最好能使用新的接口來實現(xiàn),以降低向后兼容的維護成本。HTTP 的 API,需要預定義好遷移的錯誤碼,比如在 HTTP 規(guī)范中,可以使用 410 Gone 說明已經(jīng)不再支持某個接口。
  Review
  API 的 Review 基于普通開發(fā)的 Code Review。如果基礎(chǔ)的 Code Review 都沒有做好,肯定無法保障 API 的質(zhì)量和穩(wěn)定性。
  可以通過一些工具,為 API 的 Review 提供一些參考報告。比如可以使用 SonarLint 分析代碼復雜度,如果接口層的代碼復雜度較高,會是一個危險的信號。還可以借助 Java 反射、Clang 語法分析,獲取當前的 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 接口有變更風險。stable 版本 API 穩(wěn)定,但功能不一定是最新的。如果開發(fā)者還在開發(fā)過程中,可以選用最新的 dev 版本,基于最新 API 開發(fā)。如果應用已經(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 版本
【免責聲明】本文僅代表作者本人觀點,與CTI論壇無關(guān)。CTI論壇對文中陳述、觀點判斷保持中立,不對所包含內(nèi)容的準確性、可靠性或完整性提供任何明示或暗示的保證。請讀者僅作參考,并請自行承擔全部責任。

專題

CTI論壇會員企業(yè)

玛多县| 隆化县| 诸城市| 正蓝旗| 太仓市| 伊金霍洛旗| 化州市| 岳池县| 龙口市| 四子王旗| 枣强县| 密云县| 婺源县| 陈巴尔虎旗| 明光市| 泾阳县| 灵宝市| 固安县| 麻栗坡县| 苏尼特右旗| 克东县| 宣化县| 义马市| 潞西市| 沙湾县| 宜兴市| 金阳县| 广河县| 东乌珠穆沁旗| 和平区| 武乡县| 靖江市| 光山县| 都江堰市| 塔城市| 拜泉县| 苗栗市| 石景山区| 鄯善县| 宜川县| 剑川县|