摘要:今天我來和大家分享一下以及自動化生成工具的開發經驗。代碼生成工具接著講講代碼生成工具,對于來講,有官方的代碼生成器,還有其他的同類開源項目比如。現有的代碼生成器沒有可以開箱即用的,都需要去進行不少的修改。
前言
在開發工作中,經常會遇到新產品、服務上線后,需要將其 API 編寫不同語言的 SDK。但不同語言 SDK 中都有很大一部分內容是用來進行 API 的描述,而且這部分代碼量是最大的,手寫起來也枯燥易錯。所以我們需要一種?Data-Driven 的開發方式,通過工具(Snips)來自動化的生成準確、優雅的代碼,讓開發者減少重復無意義的工作,將更多精力放在產品以及業務上。
本文共 4420 字,閱讀大概需要 18 分鐘。
今天的內容包括:?
? QingStor SDK 簡介 ? QingStor SDK 開發流程的改變 ? API Specification ? SDK 生成工具 Snips ? 場景化測試 ? 使用 Snips 開發 QingStor Go SDK?正文
大家好,我是青云 QingCloud 系統工程師 Aspire 。今天我來和大家分享一下 QingStor SDK 以及自動化 SDK 生成工具 Snips 的開發經驗。
今天交流的內容包括:
QingStor SDK 簡介
QingStor SDK 的開發流程
API Specification
SDK 生成工具 Snips
場景化測試
使用 Snips 開發 QingStor Go SDK
1. QingStor SDK 簡介QingStor? 對象存儲為用戶提供可無限擴展的通用數據存儲服務,在 QingCloud Console (青云控制臺)中可以直接創建、使用和管理對象存儲 Bucket ,可以方便的上傳下載文件。我們也提供了命令行工具(如 qingcloud-cli, qsctl) 來在各種場景下進行數據的存取。但是面對海量數據的操作時,圖形化的界面和命令行工具是不夠的。另外,我們的用戶也需要在代碼層面使用 SDK 或者直接請求 API 來接入 QingStor 對象存儲。自上線以來我們就開放了一套標準、規范且簡潔的 RESTful API ,以及一個 Python 的 SDK 。雖說 Python 的用戶量非常大,但是顯然只有這一種的 SDK 是無法滿足用戶需求的,再加上 QingStor 的 API 是遵循 RESTful 標準的,直接使用 API 來接入 QingStor 的成本也會高一些。(不過好在我們已在今年上半年兼容了 AWS S3 的 API ,所以用戶也可以使用 S3 的 SDK 來接入 QingStor 。)
這里將 QingStor API 和 QingCloud IaaS 的 API 做個簡單比較:
相比之下用戶使用 API 來接入 QingStor 的難度會高一些,對 SDK 的需求也就更強烈。
目前 QingStor 提供了包括 Go 、 JavaScript 、 Ruby 、 PHP 、 Swift 、 Java 、 Python 在內 7 種語言的 SDK ,已經可以做到覆蓋主流編程語言,而且有了 Snips 的幫助,開發者也能夠在短時間內開發出另一種語言的 SDK 。
同時,此次我們將 QingCloud IaaS 和 QingStor 的 SDK 進行了拆分,例如 qingcloud-sdk-swift (尚未發布) 和 qingstor-sdk-swift 。這樣做主要是考慮到移動端對空間比較敏感,所引入的第三方庫越小越好,由于 QingCloud IaaS 目前開放的 API 數量是 QingStor 的三倍,將兩者合并為一個包會造成空間的浪費,對于一個僅需要 QingStor 做為存儲的 App 來講,只引入 QingStor 的 SDK 就足夠了。
QingStor SDK 的中文使用文檔可以參考 https://docs.qingcloud.com/qi... ;另外這些 SDK 也已開源在 GitHub ,可以訪問 https://github.com/yunify 來獲取,也歡迎大家給我們提 Issue 和 Pull Request 。
2. QingStor SDK 的開發流程首先可以回顧一下我們 Python SDK 的開發方式,就是在 API 發生改變之后,手動增加 SDK 中與之對應部分的代碼,這種做法效率不高,維護起來也讓人頭疼。
再加上 QingCloud IaaS 和 QingStor 共有兩百多個開放 API ,并且不斷有新的 API 伴隨產品或功能上線,要做到 SDK 的實時跟進比較困難。而且現在只有一個 Python 的 SDK ,如果再加上其他語言的,每種語言都手動維護,會耗費工程師很多不必要的精力。還有一個問題比較麻煩,如果有用戶對一些小眾語言的 SDK 有需求,我們也沒法立即進行支持,這點行業內基本都有類似的情況。
要解決這些問題,就需要換一種思路。我們可以看到,不同語言的 SDK 中都有很大一部分內容是用來進行 API 的描述(或者叫定義),而且這部分代碼量是最大的,手寫起來枯燥易錯。所以我們采用了一種新的 SDK 的開發流程,使用標準的數據來生成代碼,之后通過場景化的測試來進行驗證,其中用到了我們自己寫的一個代碼生成工具━━ Snips 。
Snips 使用 API 的標準化描述和代碼模版來生成各種語言 API 調用的那部分代碼,除了生成出來的代碼,還需要手動編寫的代碼,每種語言都不一樣,不適合統一生成代碼,比如錯誤處理,文件讀寫,網絡請求等。這樣做比起純手工打造一個 SDK ,需要開發的代碼量會小很多,開發效率能夠得到很大的提升。
上面是利用 Snips 開發一種新的語言的 SDK 的示意圖。下面具體說明一下。
新增一種語言的 SDK :
手寫哪些錯誤處理、網絡請求等相關的的代碼
編寫代碼模版
使用 Snips 生成代碼
通過場景化測試
發布
更新 SDK :
更新 API 描述
重新生成代碼
通過場景化測試
發布
這里的 API 的描述我們是通過 Git Submodule 的形式引入到各個 SDK 項目中,這樣如果是 API 的變更,完全不需要手動編寫 SDK 的代碼就可以做到 SDK 的更新。
下面會逐個講一下 API 描述規范 ( API Specification )、 Snips 和 場景化測試( Scenario Based Testing )這幾個部分,我們是怎么做的。
3. API Specification要實現上述的流程,得先有 API 的描述,我們花了很長時間來確定使用怎樣的 API 描述規范,也走了一些彎路。
起初我們自己制定了一個 API Specification 的 Schema :
這個 Schema 的目標是描述 HTTP API
每一個 API Specification 文件呈現一個 Service (如 QingCloud IaaS 或者 QingStor )
Service 中可以有 SubService
同時 Service 和 SubService 中都包含 Metadata 、 Properties 、 Operations 、 Endpoint 等信息
Operation 是具體的 API 請求,其中包含 Request 和 Response 的描述以及其他基本信息
定義了 boolean 、 integer 、 timestamp 、 binary 、 list 、 object 等幾種基本的數據類型,及自定義的數據類型 CustomizedType, CustomizedType 可以出現多級引用
之后使用這套 Schema ,去描述了 QingStor 的 所有 API ,并且寫了解析器,快速實現了從 API 描述生成 Go SDK 的代碼。但是 Review 時我們發現這個自己定義的 Schema 還是太簡陋,沒有經過足夠的數據進行驗證,很多情況都沒有考慮到,還有一些 Corner Case 也難以描述,并且這個 Schema 本身的校驗效果也不理想。而且如果使用這套自己定義的 Schema 來描述 QingStor 和 QingCloud API ,無論是在內部使用還是開放出去,都是讓人比較難以接受的,這種自立門戶的做法也沒有太大意義。
然后我們對比了幾個目前可以用到的幾個 API Specification 的規范,最后選擇了 Swagger 。
Swagger 是一個描述 RESTful API 的規范, Swagger 具體的 Specification 大家可以訪問它的網站來查看: http://swagger.io 。
今年的一月份 Swagger 更名為 OpenAPI Specification ,由 Linux 基金會贊助成立了 OpenAPI Initiative 來繼續 OpenAPI Specification 的開發。在 Google 、 Microsoft 等大廠的支持下, Swagger 儼然已經成了業界標準,相關的生態和工具也已比較齊全,用它來作我們 API 的描述規范再合適不過,所以我們最終選擇了 Swagger 來重新描述了 QingStor APIs ,并且實現了用 Swagger 描述規范來生成代碼。
使用 Swagger 規范無疑是正確的,因為 Swagger 的工具和生態相對比較完善。以 Swagger Editor 為例,它是一個 API Specification 的 Web 編輯器,可以在編輯的同時提供代碼補全、高亮和實時語法驗證功能,感興趣的朋友可以在 http://editor.swagger.io 體驗一下。
Swagger 雖然發展的比較快,但并不是對所有 API 都友好。 QingCloud IaaS 的 API ,請求參數部分里會有數組( Array )和字典( Map )。例如 statics.n.router_static_name 、 statics.n.router_static_value 這種請求參數,用戶實際提供的是一個由 Static 字典組成的數組,并且這個請求參數是位于 Request URL Query , SDK 會把數組和字典轉換一下格式,構造出 statics.0.router_static_name=name&statics.0.router_static_value=value 這種形式的請求串。這樣就會出現問題,在描述請求的時候需要定義數組和字典參數,由于 Swagger 的規范比較嚴格, Operation Parameter 不允許自定義類型出現,這時就只能將請求參數的描述放在 Request Body 里面來定義,這樣就需要解析 Specification 的時候做一些特殊處理。
Swagger 標準也考慮到了 API 數量很多導致描述文件過長的情況,它支持使用 $ref 來引用其他文件,當然這個引用的功能其實是 JSON Reference 和 JSON Pointer 規范提供的,但是這里的 $ref ,只支持同一個文件內的引用,或者是引用某個 URL 鏈接。我們測試的解析器,包括 Swagger 官方的 swagger-codegen 都不支持文件間的引用,更不用提 Circle Reference 這種常用的情況了。不過這個問題我們在 Snips 中也解決掉了,可以看到我們的 QingStor API Specs 中的 API 描述是拆分成了很多文件的,具體內容等下 Snips 的部分會提到。
使用 Swagger API Specification 規范來描述 API ,其作用不僅僅可以用來生成代碼,生成文檔,更重要的是它的約束作用,它反過來可以規范 API 的開發和交付,進一步保證 QingCloud 的整體服務質量。對于 SDK 開發來講則是一種 Data-Driven 的開發方式,這種思路可以讓產出的各個 SDK 在功能上保持很強的一致性,不會出現某種語言的 SDK 缺失功能,或者是更新滯后,這種思路的優勢也會隨著更多產品和功能的上線變得越來越明顯。
API Specification 文件本身也需要驗證正確性,而使用 Swagger 標準可以輕而易舉的使用 JSON Schema 來實現 Specification 數據的驗證。
QingStor 的 API Specification 也放到了 GitHub ,這里是地址 https://github.com/yunify/qin... 。
4. 代碼生成工具 Snips接著講講代碼生成工具,對于 Swagger 來講,有官方的代碼生成器 swagger-codegen ,還有其他的同類開源項目比如 go-swagger 。
它們雖說可以生成代碼,但是生成出來的代碼可控性和可讀性都不高,并不能滿足我們的需求,定制起來也比較麻煩。
例如采用 swagger-codegen 得 fork 過來,改它的 Java 代碼,而且每增加一種語言的 SDK 基本上都要去增加對應的 Java 代碼,這對于 Java SDK 之外的開發者來講是非常不友好的。
除此之外還有很多其他細節上的問題,例如我們 API 的遺留問題,上面說到的 QingCloud IaaS 的請求參數不標準;例如 swagger-codegen 和 go-swagger 不支持文件引用的解析;生成出來的代碼大小寫控制不嚴格( acl 被轉換成了 Acl ,而不是 ACL )等。
現有的代碼生成器沒有可以開箱即用的,都需要去進行不少的修改。但是去實現一個 Swagger 的解析器又太費時費力了,所以我們想到了一種折中的方案,使用開源的 Swagger 解析器來構建自己的生成器。
比對了幾個開源項目之后,我們采用的解析器是 go-openapi/spec ( https://github.com/go-openapi/), 這個解析器的作者也是 go-swagger 的作者, go-swagger 是在這個解析器之上構建的。遺憾的是 go-openapi 也不支持文件引用,看到未來有支持文件引用功能的計劃,不過不知道什么時候才會加上。于是我們簡單熟悉了一下代碼,之后提交了幾個 PR 把這功能幫他們實現了,作者也欣然接受 “ With this PR go-swagger is the first library on go that fully supports json schema and ref resolving so very happy with it ?”。
隨后就有了代碼生成工具 Snips ,它是一個命令行工具,很好地支持著我們的 SDK 開發,以 Go 語言 SDK 為例,包括模版在內,手寫的代碼大約 6 千行左右,而生成出來的代碼已經達到了 2 萬多行,開發效率得到了不小的提升。
關于模版, Snips 會從指定路徑加載模版文件,模版目錄下需要有一個 manifest 文件,可以是 JSON 或者 YAML 格式,這個文件指定了一些生成規則,例如指定該目錄下模版文件的格式,輸出文件名的命名風格是 CamelCase 還是 snake_case ;輸出文件的擴展名和前后綴,可以參考 example 下的 manifest.yaml 來查看所有支持的規則。模版文件格式目前只支持一種,是 Go 語言的 template 。
與代碼生成有關的簡單邏輯是放在模版里去實現的,同時生成器也提供了一些內置函數可以在模版中使用,如大小寫風格的轉換、字符串替換、數據傳遞等,從而做到了生成器與某種語言無關,新增語言不需要去修改生成器的代碼。上文提到的 acl 轉換成 Acl 的問題,使用 Snips 提供的函數就可以正確轉換,例如 {{snakeCase "acl"}} 會轉換成 “ ACL ”。
關于多版本 API , Snips 也有解決方案。
通過 -n (--service-api-version) 參數來指定使用的 API 版本,然后將代碼生成到不同的目錄,例如 latest version 的代碼在 service 目錄,特定版本的代碼可以在 service-2016-01-06 中,再根據語言的不同看是否還需要相應的調整。以 Go 語言為例,用戶使用的時候 import 不同的路徑的 service 即可切換不同版本的 API ,如 import "github.com/yunify/qingstor-sdk-go/service-2016-01-06"。
Snips 目前已經開源, GitHub 地址: https://github.com/yunify/snips 。目前是針對 QingCloud IaaS 和 QingStor API 的代碼生成工具, Snips 的思路和其他的 Swagger 生成器的思路不太一樣,未來也可能會做成一個通用的代碼生成器。
5. 場景化測試SDK 開發出來了,除了單元測試之外,還需要在線上生產環境進行測試,保證交付的 SDK 可正常工作,我們稱之為服務測試( Service Test )。
服務測試中我們采用 Cucumber ( https://cucumber.io),它是一個 Behaviour-Driven Development (BDD) 工具。 Cucumber 會讀取通過自然語言描述的測試場景和數據,然后結合不同的測試實現去驗證是否通過。 Cucumber 可以被稱作是一種測試方式,基本上每種語言都有它的實現。
舉個例子:
獲取一個 Object , Cucumber 描述是這樣的:
Ruby 中對應的測試實現是這樣的:
Cucumber 會檢查代碼場景執行過程中的數據是否滿足預期,給出一個完成的測試結果
這樣以使用者的角度來真實的測試 SDK ,并且可以讓所有 SDK 的測試用例保持一致,在保證 SDK 質量的同時,也可以做到各種語言 SDK 功能的一致性。
QingStor SDK 的測試場景也放在了 GitHub : https://github.com/yunify/qin...
6. 使用 Snips 開發 QingStor Go SDK上面講了整套的 QingStor 的 SDK 開發流程,下面用 QingStor Go SDK 來舉例說明一下。
qingstor-sdk-go https://github.com/yunify/qin...
首先需要實現 SDK 最基礎的部分,比如網絡請求和簽名處理、文件讀寫、錯誤處理等等,然后再使用 Snips 生成 API 相關的代碼。
假設基礎部分現在已經完成了,并且經過了單元測試。
接下來安裝 Snips ,可以使用 go get -u github.com/yunify/snips 安裝,或者直接訪問 GitHub 下載編譯好的二進制文件。
在代碼倉庫目錄下以 git submodule 的形式引入 API Specification 和 Test Scenarios:
./specs/qingstor 引用 QingStor API specifications
./test/features 引用 QingStor 測試場景
然后便可編寫代碼模版,下圖所示為 Go SDK 的模版文件:
具體的模板文件內容請見:
https://github.com/yunify/qin...
模板編寫完成后,即可利用模版和 API Specifications 來生成代碼。下圖為生成代碼的命令,生成完的代碼有可能會難看,可以格式化一下代碼,當然如果模版控制的嚴格,生成出來的代碼足夠漂亮,可以跳過格式化的步驟。
之后便可使用這些生成好的代碼,實現測試場景,具體的代碼請見這里: https://github.com/yunify/qin...
最后運行測試
目前 QingStor 已經提供了七種語言的 SDK (其中 Python SDK 的新版也會使用 Snips 來重新生成),覆蓋了主流的編程語言,但還有一些編程語言的 SDK 我們沒有來得及開發,為激勵更多的開發者參與進來貢獻其它語言的 SDK ,我們特此發起 QingStor SDK 大賽活動,報名地址請見: https://jinshuju.net/f/0MB6w6
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86591.html
摘要:今天我來和大家分享一下以及自動化生成工具的開發經驗。代碼生成工具接著講講代碼生成工具,對于來講,有官方的代碼生成器,還有其他的同類開源項目比如。現有的代碼生成器沒有可以開箱即用的,都需要去進行不少的修改。 前言 在開發工作中,經常會遇到新產品、服務上線后,需要將其 API 編寫不同語言的 SDK。但不同語言 SDK 中都有很大一部分內容是用來進行 API 的描述,而且這部分代碼量是最大...
摘要:今天我來和大家分享一下以及自動化生成工具的開發經驗。代碼生成工具接著講講代碼生成工具,對于來講,有官方的代碼生成器,還有其他的同類開源項目比如。現有的代碼生成器沒有可以開箱即用的,都需要去進行不少的修改。 前言 在開發工作中,經常會遇到新產品、服務上線后,需要將其 API 編寫不同語言的 SDK。但不同語言 SDK 中都有很大一部分內容是用來進行 API 的描述,而且這部分代碼量是最大...
摘要:配置驗證,輸入。按鍵,自動補全則成功添加相關,將里面目錄下的文件移動到目錄下的文件下,就可以使用了,如 安裝plug (https://github.com/junegunn/v... curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent... 編輯~/.vimrc文件(不...
摘要:配置驗證,輸入。按鍵,自動補全則成功添加相關,將里面目錄下的文件移動到目錄下的文件下,就可以使用了,如 安裝plug (https://github.com/junegunn/v... curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent... 編輯~/.vimrc文件(不...
摘要:為了構建可伸縮的測試自動化框架,需要記住以下三個最重要的干凈編碼實踐。因此,組織期望其或測試自動化架構師設計和開發健壯,可維護的智能測試自動化框架。包括適當的文檔在測試自動化框架開發項目中工作的程序員不太可能獨自編寫代碼。 ...
閱讀 2584·2021-11-25 09:43
閱讀 1858·2021-09-22 15:26
閱讀 3735·2019-08-30 15:56
閱讀 1712·2019-08-30 15:55
閱讀 1897·2019-08-30 15:54
閱讀 814·2019-08-30 15:52
閱讀 3156·2019-08-29 16:23
閱讀 895·2019-08-29 12:43