<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go整潔架構(gòu)模版,建議收藏

          共 10417字,需瀏覽 21分鐘

           ·

          2021-09-02 20:31

          本文翻譯自 https://github.com/evrone/go-clean-template,由于本人翻譯水平有限,翻譯不當之處煩請指出。希望大家看了這篇文章能有所幫助。感謝捧場。
          概括

          模板的作用 :

          • 如何組織項目并防止它變成一坨意大利面條式的代碼。
          • 在哪里存放業(yè)務(wù)邏輯,使其保持獨立,整潔和可擴展。
          • 如何在微服務(wù)擴展時不失控

          模版使用了 Robert Martin ( 也叫 Bob 叔叔 ) 的原則[1]。

          Go-clean-template[2] 此倉庫由 Evrone[3] 創(chuàng)建及維護。

          目錄內(nèi)容

          • 快速開始
          • 項目結(jié)構(gòu)
          • 依賴注入
          • 整潔架構(gòu)之道

          快速開始

          本地開發(fā)

          # Postgres, RabbitMQ
          $ make compose-up
          # Run app with migrations
          $ make run

          集成測試 ( 可以在 CI 中運行 )

          # DB, app + migrations, integration tests
          $ make compose-up-integration-test

          項目結(jié)構(gòu)

          ├── cmd
          │   └── app
          │       └── main.go
          ├── config
          │   ├── config.go
          │   └── config.yml
          ├── docs
          │   ├── docs.go
          │   ├── swagger.json
          │   └── swagger.yaml
          ├── go.mod
          ├── go.sum
          ├── integration-test
          │   ├── Dockerfile
          │   └── integration_test.go
          ├── internal
          │   ├── app
          │   │   ├── app.go
          │   │   └── migrate.go
          │   ├── delivery
          │   │   ├── amqp_rpc
          │   │   │   ├── router.go
          │   │   │   └── translation.go
          │   │   └── http
          │   │       └── v1
          │   │           ├── error.go
          │   │           ├── router.go
          │   │           └── translation.go
          │   ├── domain
          │   │   └── translation.go
          │   └── service
          │       ├── interfaces.go
          │       ├── repo
          │       │   └── translation_postgres.go
          │       ├── translation.go
          │       └── webapi
          │           └── translation_google.go
          ├── migrations
          │   ├── 20210221023242_migrate_name.down.sql
          │   └── 20210221023242_migrate_name.up.sql
          └── pkg
              ├── httpserver
              │   ├── options.go
              │   └── server.go
              ├── logger
              │   ├── interface.go
              │   ├── logger.go
              │   └── zap.go
              ├── postgres
              │   ├── options.go
              │   └── postgres.go
              └── rabbitmq
                  └── rmq_rpc
                      ├── client
                      │   ├── client.go
                      │   └── options.go
                      ├── connection.go
                      ├── errors.go
                      └── server
                          ├── options.go
                          └── server.go

          cmd/app/main.go

          配置和日志實例的初始化,main 函數(shù)中調(diào)用internal/app/app.go 文件中 的 Run 函數(shù),main 函數(shù)將會在此 "延續(xù)"。

          config

          配置。首先讀取 config.yml,然后用環(huán)境變量覆蓋相匹配的 yaml 配置。配置的結(jié)構(gòu)體在 config.go 文件中。env-required: true 結(jié)構(gòu)體標簽強制您指定一個值 ( 在 yaml 或在環(huán)境變量中 )。

          對于配置讀取,我們選擇 cleanenv[4] 庫。它在 GitHub 上沒有很多 star,但很簡單且滿足所有的需求。

          從 yaml 中讀取配置違背了12 要素,但在實踐中,它比從環(huán)境變量中讀取整個配置更方便。假設(shè)默認值定義在 yaml 中,敏感的變量定義在環(huán)境變量中。

          docs

          Swagger 文檔。可以由 swag[5] 庫自動生成。而你不需要自己改正任何事情。

          integration-test

          集成測試。它們作為單獨的容器啟動,緊挨著應用程序容器。使用 go-hit[6] 測試 REST API 非常方便。

          internal/app

          在 app.go 文件中一般會有一個 Run 函數(shù),它“延續(xù)”了main函數(shù)。

          這是創(chuàng)建所有主要對象的地方。依賴注入通過“ New...”構(gòu)造函數(shù) ( 參見依賴注入 ) 。這種技術(shù)允許我們使用依賴注入原則對應用程序進行分層,使得業(yè)務(wù)邏輯獨立于其他層。

          接下來,為了優(yōu)雅的完成,我們啟動服務(wù)并在select中等待特定的信號。如果 app.go 代碼越來越多,可以將其拆分為多個文件。

          對于大量的注入,可以使用 wire[7] 庫 ( wire 是一個代碼生成工具,它使用依賴注入自動連接組件)。

          migrate.go 文件用于數(shù)據(jù)庫自動遷移。如果指定了 migrate 標簽的參數(shù),則會包含它。例如 :

          $ go run -tags migrate ./cmd/app

          internal/delivery

          服務(wù)的handler層 ( MVC 控制器 )。模板展示了兩個服務(wù):

          • RPC ( RabbitMQ 用于傳遞消息 )
          • REST HTTP ( GIN 框架 )

          服務(wù)的路由也以同樣的風格編寫 :

          • Handlers按照應用領(lǐng)域分組 ( 按公共基礎(chǔ) )
          • 對于每個組,都創(chuàng)建自己的路由結(jié)構(gòu),以及處理接口路徑的方法
          • 業(yè)務(wù)邏輯的結(jié)構(gòu)被注入到路由結(jié)構(gòu)中,由handlers處理調(diào)用

          internal/delivery/http

          簡單的 REST 版本控制。對于 v2,我們需要添加具有相同內(nèi)容的 http/v2 文件夾。在 internal/app 程序文件中添加以下行 :

          handler := gin.New()
          v1.NewRouter(handler, translationService)
          v2.NewRouter(handler, translationService)

          你可以使用任何其他的 HTTP 框架甚至是標準的 net/http 庫來代替 Gin。

          在 v1/router.go 和上面的 handler 方法中,有一些注釋是用 swag庫來生成 swagger 文檔的。

          internal/domain

          業(yè)務(wù)邏輯的實體 ( 模型 ) 可以在任何層中使用。也可以有方法,例如,用于驗證。

          internal/service

          業(yè)務(wù)邏輯

          • 方法按應用領(lǐng)域分組 ( 在公共的基礎(chǔ)上 )
          • 每個組都有自己的結(jié)構(gòu)
          • 一個文件一個結(jié)構(gòu)

          Repositories、 webapi、 rpc 和其他業(yè)務(wù)邏輯結(jié)構(gòu)被注入到業(yè)務(wù)邏輯結(jié)構(gòu)中 ( 見依賴注入 )。

          internal/service/repo

          repository 是業(yè)務(wù)邏輯使用的抽象存儲 ( 數(shù)據(jù)庫 )。

          internal/service/webapi

          它是業(yè)務(wù)邏輯使用的抽象 web API。例如,它可能是業(yè)務(wù)邏輯通過 REST API 訪問的另一個微服務(wù)。包的名稱根據(jù)用途而變化。

          pkg/rabbitmq

          RabbitMQ RPC 模式 :

          • RabbitMQ 內(nèi)部沒有路由
          • 使用Exchange fanout 廣播模式,將1 個獨立隊列綁定到其中,這是最高效的配置。
          • 重新連接斷開丟失的連接

          依賴注入

          為了消除業(yè)務(wù)邏輯對外部包的依賴,使用了依賴注入。

          例如,通過 NewService 構(gòu)造函數(shù),我們將依賴注入到業(yè)務(wù)邏輯的結(jié)構(gòu)中。這使得業(yè)務(wù)邏輯獨立 ( 便于移植 )。我們可以重寫接口的實現(xiàn),而不需要對 service 包進行更改。

          package service

          import (
              // Nothing!
          )

          type Repository interface {
              Get()
          }

          type Service struct {
              repo Repository
          }

          func NewService(r Repository) *Service{
              return &Service{r}
          }

          func (s *Service) Do()  {
              s.repo.Get()
          }

          它還允許我們自動生成模擬參數(shù) ( 例如使用 mockery[8] ) 和輕松地編寫單元測試。

          我們可以不受特定實現(xiàn)的約束,來將一個組件更改為另一個組件。如果新組件實現(xiàn)了該接口,則業(yè)務(wù)邏輯中不需要進行任何更改。

          整潔架構(gòu)之道

          關(guān)鍵點

          程序員在編寫了大量代碼后才意識到應用程序的最佳架構(gòu)。

          一個好的架構(gòu)允許盡可能推遲決策。

          主要原則

          Dependency Inversion ( 與 SOLID 相同 ) 是依賴倒置的原則。依賴關(guān)系的方向是從外層到內(nèi)層。由于這個原因,業(yè)務(wù)邏輯和實體仍然獨立于系統(tǒng)的其他部分。

          因此,應用程序分為內(nèi)部和外部兩個層次 :

          • 業(yè)務(wù)邏輯 ( 使用 Go 標準庫 )
          • 工具 ( 數(shù)據(jù)庫、其他服務(wù)、消息代理、任何其他包和框架 )
          Clean Architecture

          業(yè)務(wù)邏輯的內(nèi)層應該是整潔的,它應該 :

          • 沒有從外層導入的包
          • 只使用標準庫的功能
          • 通過接口調(diào)用外層 !

          業(yè)務(wù)邏輯對 Postgres 或詳細的 web API 一無所知。業(yè)務(wù)邏輯應該具有一個用于處理抽象數(shù)據(jù)庫或抽象 web API 的接口。

          外層還有其他限制 :

          • 這一層的所有組成部分都不知道彼此的存在。如何從一個工具調(diào)用另一個工具?不是直接,而是只能通過內(nèi)層的業(yè)務(wù)邏輯來調(diào)用。
          • 對內(nèi)層的所有調(diào)用都是通過接口來完成的
          • 數(shù)據(jù)以便于業(yè)務(wù)邏輯的格式傳輸 ( internal/domain )

          例如,你需要從 HTTP ( 控制器 ) 訪問數(shù)據(jù)庫。HTTP 和數(shù)據(jù)庫都在外層,這意味著它們對彼此一無所知。它們之間的通信是通過 service ( 業(yè)務(wù)邏輯 ) 進行的 :

              HTTP > service
                     service > repository (Postgres)
                     service < repository (Postgres)
              HTTP < service

          符號 > 和 < 通過接口顯示層與層邊界的交集,如圖所示 :

          Example

          或者更復雜的業(yè)務(wù)邏輯 :

              HTTP > service
                     service > repository
                     service < repository
                     service > webapi
                     service < webapi
                     service > RPC
                     service < RPC
                     service > repository
                     service < repository
              HTTP < service

          層級

          Example

          整潔架構(gòu)的術(shù)語

          • 實體是業(yè)務(wù)邏輯操作的結(jié)構(gòu)。它們位于 internal/domain 文件夾中。Domain 暗示我們堅持 DDD ( 領(lǐng)域驅(qū)動設(shè)計 ) 的原則,這在一定程度上是正確的。在 MVC 術(shù)語中,實體就是模型。
          • 用例是位于 internal/service 中的業(yè)務(wù)邏輯。從整潔架構(gòu)的角度來看,調(diào)用業(yè)務(wù)邏輯使用 service 一詞不是習慣的用法,但是對于一個包名稱來說,使用一個單詞 ( service ) 比使用兩個單詞 ( use case ) 更方便。

          業(yè)務(wù)邏輯直接交互的層通常稱為基礎(chǔ)設(shè)施層。它們可以是存儲庫 internal/service/repo、web API internal/service/webapi、任何pkg,以及其他微服務(wù)。在模板中,_ infrastructure 包位于 internal/service 中。

          你可以根據(jù)需要去選擇如何調(diào)用入口點。選項如下 :

          • delivery (in our case)
          • controllers
          • transport
          • gateways
          • entrypoints
          • primary
          • input

          附加層

          經(jīng)典版本的 整潔架構(gòu)之道[9] 是為構(gòu)建大型單體應用程序而設(shè)計的,它有4層。

          在最初的版本中,外層被分為兩個以上的層,兩層之間也存在相互依賴關(guān)系倒置 ( 定向內(nèi)部 ),并通過接口進行通信。

          在邏輯復雜的情況下,內(nèi)層也分為兩個( 接口分離 )。

          復雜的工具可以被劃分成更多的附加層,但你應該在確實需要時再添加層。

          替代方法

          除了整潔架構(gòu)之道,洋蔥架構(gòu)和六邊形架構(gòu) ( 端口適配器模式 ) 是類似的。兩者都是基于依賴倒置的原則。端口和適配器模式非常接近于整潔架構(gòu)之道,差異主要在術(shù)語上。

          類似的項目

          • https://github.com/bxcodec/go-clean-arch
          • https://github.com/zhashkevych/courses-backend

          擴展閱讀鏈接

          • 整潔架構(gòu)之道[10]
          • 12 要素[11]

          參考資料

          [1] 

          原則: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

          [2] 

          Go-clean-template: https://evrone.com/go-clean-template?utm_source=github&utm_campaign=go-clean-template

          [3] 

          Evrone: https://evrone.com/?utm_source=github&utm_campaign=go-clean-template

          [4] 

          cleanenv: https://github.com/ilyakaznacheev/cleanenv

          [5] 

          swag: https://github.com/swaggo/swag

          [6] 

          go-hit: https://github.com/Eun/go-hit

          [7] 

          wire: https://github.com/google/wire

          [8] 

          mockery: https://github.com/vektra/mockery

          [9] 

          整潔架構(gòu)之道: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

          [10] 

          整潔架構(gòu)之道: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

          [11] 

          12 要素: https://12factor.net/ru/





          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關(guān)注公眾號 「polarisxu」,回復 ebook 獲??;還可以回復「進群」,和數(shù)萬 Gopher 交流學習。

          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲天堂精品视频 | 特级茜茜人体444WWw高清大胆 | www豆花视频 | 亚洲激情网站 | 国产婷婷操逼动态图视频网站 |