Go

Google 開發的靜態強型別、編譯型、並發型,具垃圾回收的程式語言。由 Robert Griesemer、Rob Pike 和 Ken Thompson 設計。被稱為雲端時代的 C 語言。

Go

讓錯誤成為資源:gRPC 的錯誤處理模型

錯誤處理是所有 RPC 服務都要具備的設計,但是怎樣的錯誤處理模型,算是好的模型呢?從字面上來看,錯誤處理可以分解成「錯誤」跟「處理」,如果用 RESTful 的觀點,將錯誤當成是 Resource,一個好的模型應該要能匹配不同場景的 Resource,並根據場景需求來處理這些 Resource。 錯誤模型 在 RESTful 中,通常會用 HTTP Status Code 當錯誤訊息的分類(Category),錯誤內容則放在 Payload。這樣的好處是,只要看到分類,就能先進行大方向的處理,如果需要特定資訊,再從 Payload 拿取。通常錯誤內容的格式會自行定義,以支付服務 Stripe 的 API 為例,定義的格式就有 * type (string) * code (string) * decline_

By Ken Chen
在 GitLab 顯示測試覆蓋率:以 Go 為例

Go

在 GitLab 顯示測試覆蓋率:以 Go 為例

對現代開發者來講,單元測試已經不是可選,而是必備了。單元測試能保護程式碼,讓錯誤提早現形,也能讓重構時更安心。通常我們在評估單元測試的執行狀況時,會用 coverage 當成其中一項指標。當然,coverage 還是會有一些使用的場合跟侷限,當談到專案落地,可能大家會想知道的是,coverage 該怎麼使用,才能幫助到專案? 開發、審查、回顧 我們先來看看什麼時候會需要知道 coverage?通常依照團隊的工作流程,將它分為三個階段:開發、審查、回顧。每個階段關注的場景會略有不同。 一個一個講。對開發中情形,開發者想知道的是剛寫完的邏輯是否能正常運行,有沒有對應的測試,覆蓋範圍是否已經足夠,如果還有條件分支沒覆蓋到的話,是哪裡?是不是每個錯誤都有處理了。這時最需要的是,codebase 要能 highlight 剛剛講的資訊,幫助開發者一眼掌握。 當開發完成,feature branch 被提交到原始碼管理系統,例如 GitLab,會需要一名

By Ken Chen

Go

用 Fx 來替 Go 依賴注入吧

相信平常開發時,即使沒真的用到,也會聽別人提起「依賴注入」的概念。我們都知道依賴注入的目的是解耦模組間的依賴,但具體來說,依賴注入應該要怎麼進行呢?Go 對於依賴注入有什麼比較好的實踐呢?這篇就來談談 Go 相關的依賴注入話題。 常見的實踐方式 講到依賴注入,從 OOP 的觀點來看,可以回到 Martin Fowler 的 SOLID 原則,其中的 Dependency Inversion Principle 落實到編程中,就是依賴注入。James Grenning 曾經簡單扼要說明 DIP 原則的出發點 Martin tells us that high-level modules shouldn’t depend on low-level modules. 這裡,高層級的模組指的是商業邏輯的實現。依賴反轉原則之所以重要,

By Ken Chen

Go

初探 Go 的單元測試:兼談 Stub 跟 Mock

測試是程式的防護網,能確保程式符合設計,而當開發者需要對程式進行重構,以增進品質時,測試也可以確保程式不會出現改 A 壞 B 的情況。從商業角度來看,測試能降低維護與改善程式的成本,進而提高軟體開發的競爭力。 既然測試這麼好,那為什麼常看到軟體專案中沒有測試?在我的經驗中,主要原因有兩個:首先是軟體開發初期,架構還不是很穩定,API 隨時有可能改變,在 API 不穩時,如果就開始寫大量測試,會造成後面很大的維護成本,試著想想,API 的改變,可能就牽涉到測試流程跟測試資料的改變,而之前的 Corner Case 很可能都變成沒有價值的投資,在這情況下寫測試沒有意義。 再來,程式中可能會引用到第三方套件,例如 ORM 或 HTTP 之類的外部依賴,如果要實際測試,就會需要建構測試環境,而這些也會有建置與維護成本,像是網路斷掉,可能就會在程式邏輯沒動到的狀況下,讓 HTTP 的測試失效,這些維護成本會讓寫測試的投資報酬率看起來不太划算。

By Ken Chen

Go

自動生成重複代碼:使用 Go 的 Template

開發軟體時,常常會發現有些函式或方法很類似,例如對 Callback Function 來說,開發者都需要註冊回調函式,並在適當的時機,將資料交給回調函式處理,我們可以將這兩個動作,稱為 OnAction 跟 EmitAction。儘管繼承或組合能讓程式碼重複使用類似的組件,幫助開發者節省時間,但對於較複雜的情況,像是不同類(Class)的函式名稱也要不同時,仍需要仰賴開發者自行編寫。 試著想想,如果開發者僅僅寫設定檔(Config File),就有程式能根據設定檔來自動產生程式碼,不是很美好的事嗎?這是有的,在實務上,這類用於產生程式的程式被稱為 Code Generator,例如前面介紹過的 genny。Golang 有內建 generate 這個命令行工具,能幫助開發者將 Code Generator 跟編譯更密切結合在一起。 本文會用 Callback 的 Generator 當例子,講解如何開發並使用一套 Code Generator。

By Ken Chen

Go

Go 的泛型替代方案:型別斷言與代碼生成

用函數式編程(Functional Programming)的風格寫程式時,會常常重複使用一些通用函式,舉個例子,假設有個 array,開發者需要從該 array 中篩選符合條件的元素,重新組成新的 array。合理的情況是,如果有個 filter 函式,只需要設定條件,剩下的事情都能交給語言處理。 Golang 的 append 有點這味道,類似 JavaScript 的 push,能新增 slice 中的元素,但 Golang 畢竟不是徹底的函數式語言,內建函式庫中沒有 filter、map、reduce 等等 array 常用的函式。如果想要自行實現,語言的強型別系統會要求開發者在使用前告知對象型別,這等於是對不同的型別都要實現幾乎相同的函式,可想而知不切實際。 同樣是強型別語言,C++ 或 C# 在面對這問題時,是靠著泛型(

By Ken Chen

Go

資料庫版本遷移:以 Go 為例

接續前面,繼續來討論資料庫議題吧。 在商務初期,追求的是驗證市場,這時資料庫往往只有相對簡單的版本,各種欄位也還不是很齊全。隨著商業模式逐漸成熟,資料庫會需要負擔更多的營運功能,也會需要在原有表格中加入新欄位。資料庫的版本管理問題就出現了。 我們通常稱呼資料庫版本遷移為 Migration,在 Laravel 或 RoR 中都有整合好的 Migration 工具,而 Golang 目前仍需要仰賴自己動手,golang-migrate 是現在比較成熟的專案。本文會講解如何使用 golang-migrate 的 CLI 跟函式庫,來建立資料庫 Migration。 Introduction 既然說版本遷移是 Migration,為什麼不直接稱呼 Version 就好,它跟 Version 有什麼不同?兩者的區別可以看看下圖 簡單來說,Version 指的是資料庫的狀態,而 Migration 指的是狀態到狀態之間的改變。因為後端程式會使用到資料庫,如果用到資料庫沒有的欄位,就會出現問題。

By Ken Chen

Go

MQTT:輕量的消息隊列協定

這幾年隨著物聯網(IoT)越喊越熱,MQTT 這套通訊協定也越來越常聽人提起。物聯網的核心精神是將終端數據傳輸到網路,網路中的運算單元在分析這些數據後,可以將它轉化為使用者想要的應用。在網路中,數據是用通訊協定來交換,而常見的通訊協定 HTTP 結構相對複雜,傳輸成本較高,也更要求終端裝置的效能,而且 HTTP 採用輪詢(Polling)機制來取得資料,需要客戶端頻繁跟裝置拉取訊息,不適合 IoT 的應用;相對的,MQTT 輕量、採用發佈/訂閱模式,更適合 IoT 的傳輸需求。 最常見的 MQTT 工具是由 Eclipse Foundation 維護的 mosquitto,相關工具也都有開源。本文會講解如何使用 Golang 的 mqtt 套件,搭配 mosquitto 的中間人 Broker 服務,

By Ken Chen

Go

GORM:從建置到 CRUD

進行後端開發時,少不了要使用資料庫,由於資料庫的設計與使用方式偏向函數思維,跟主流的物件導向習慣不同,因此很多語言都有對應的 ORM 套件,用來將資料庫轉為物件,方便開發者使用。 Golang 同樣有許多第三方的 ORM 套件,例如 lib/pq、go-pg、gorm、pgx,其中 gorm 是 GitHub 上星星數較多的專案,而且能對應到不同類型的資料庫,在 Golang 中常被使用。本文會講解如何使用 gorm 來操作 Postgres,順帶走一次後端資料庫開發的基本流程。 Establish Database 既然要使用 ORM 來開發資料庫,當然要先有資料庫啦。Postgres 是常用到的關聯式資料,它是 web based,支援高併發,相對傳統的 SQLite 等 file based

By Ken Chen

Go

模組間的解耦合:發佈/訂閱模型

Observer Pattern 是物件導向常用的架構,例如多個 Chart 與單一 Data Source 的互動,就可以使用 Observer Pattern 設計,好避免資料不同步的問題。而且 Observer Pattern 可以切開 Subject 跟 Observer,讓個別模組的功能更明確,修改副作用更小。 Golang 的哲學是簡單,語言上更強調小元件的延展與復用,例如使用組合取代繼承,使用 Goroutine 取代 Thread 等。本文會講解怎麼使用 channel 來實現 Observer Pattern,或者更現代的說法,實現 Publish/Subscribe 的架構,來建構彼此獨立的模組。 Introduce Observer Pattern 先來對 Observer Pattern 做個解說。

By Ken Chen

Web

一種更緊湊的數據格式:Protobuf 入門

Protocol buffers,簡稱 Protobuf,是由 Google 設計的結構化序列化資料技術。對網路應用來講,常常需要在不同的伺服端、客戶端之間交換資料,這些資料格式有 XML、JSON 等等之類。XML 特點是完整,便於記載更多的 meta data,但格式複雜,需要更強的效能來解析,傳輸時也需要更多頻寬;而 JSON 是 JavaScript 用於表示物件的語法,相對 XML 來得簡潔,隨著 JavaScript 普及,也變成現在常用的輕量級資料交換格式。 儘管 XML 跟 JSON 在當前網路應用中已經相當常見,但用不同語言開發的伺服端程式,都需要分別實現自己語言的 XML 或 JSON 解析,同時,這些格式定義也是團隊協作的痛點。假設 A 團隊開發某支應用,

By Ken Chen

Go

訊息的處理架構:路由與中間層模式

進行後端程式開發時,常會使用到 Golang 的 http 標準庫。例如要對某個 URL 進行處理時,會用到 http.Handle("/foo", fooHandler) 可以想像,如果沒有 http 庫,就需要使用大量的 if else 來對 URL 判斷,大幅降低程式碼可讀性。http 庫對 URL 進行 function 註冊的設計模式,不僅可以使用在後端開發,也能應用於更普遍的情境。對於要對同類型資訊進行不同處理的例子,都可以使用這個設計模式。 本文會用 Golang 來開發一個類似 http middleware 的程式,處理自訂的訊息格式,藉由這過程,也順便走一次 http 庫的路由設計原理。 Build a

By Ken Chen