議程6 - A Gin user's rethinking: those bad smells - 葉家郡

tags: GopherDay2024 Agenda
HackMD Error: 403 error

Slido 連結

投影片連結

https://i.xnum.in/go/gd2024

Problems

  • Unit test tedious
  • Gin built-in feature vs own implementation
  • Architectural design when project grows

Why Gin

  • 用 framwork 可以加速草創期開發
  • document 完整
  • opensource 有很多雙眼睛
  • 比 std library 多許多擴充功能(透過 tag) e.g. JSON or bindings

Testing: use httptest.Recorder() + gin.Router.ServeHTTP

Bad things

  • Naive permission checking: use 3 different routers
    ​​​​type Router struct{
    ​​​​    API    gin.IRoute // /api
    ​​​​    Public gin.IRoute // /api/public
    ​​​​    Admin  gin.IRoute // /api/admin
    ​​​​}
    
  • Use controller to register gin API
    不確定是否要建立新的 controller,而找一個既有的 controller 塞進去,例如將 permission 掛在 user controller 上。
  • Model binding and vertification
    • by tag,如 gorm tag
    • 會看不出來一個 binding 的驗證條件是否正確、可能要寫完整測試
    • 解法:自己的 struct 自己實作 validator interface: Validate() error
  • Forget to add return after gin response
  • Fragmentation of ofbusiness logic
    • business logic 依賴 middleware 的順序 -> 會導致邏輯錯誤、難追蹤、重覆寫了 response
    • middleware panic 不好找 root cause,可能只會看到 status override from 500 to 200
    • 可能會誤把 middleware 直接註冊到 root engine,造成污染
  • Hard to test
    • Too many boilerplate code
    • Hope QA to test it
    • head count not enough
    • 沒人敢改這段 code
  • Code quality is limited by test quality

Solutions

拒當 framework 的奴隸

  • 根據專案大小決定專案架構
    • 小型:MVC、DI
    • 中型:分層、CA
    • 大型:micro-services、DDD、Event-Driven
  • DB interface 應該要做更高級的抽象,不是只是 repository 的 wrapper
  • 把 handler 包成 method chain,將 error handling 還原為最基本的 return error
    • 如果回傳的 err 有實作 HTTPStatusError(),可以呼叫對應的 function 拿到 status code
      • anti pattern 的點在於內部由於外部需要 http status code 而非得要實做 HTTPStatusError()
  • refactor 期間同時還債,從架構去思考如何重構,有時候去重複反而不夠彈性
  • composite over inherit
Select a repo