淳安縣千島湖建設(shè)集團網(wǎng)站市場調(diào)研報告800字
前言
?????? 隨著項目的代碼量在不斷地增長,不同的開發(fā)人員按自己意愿隨意布局和創(chuàng)建目錄結(jié)構(gòu),項目維護性就很差,代碼也非常凌亂。良好的目錄與文件結(jié)構(gòu)十分重要,尤其是團隊合作的時候,良好的目錄與文件結(jié)構(gòu)可以減少很多不必要的麻煩。項目目錄結(jié)構(gòu)規(guī)范的的本質(zhì)是提高了代碼的可讀性,最終目的是提高團隊協(xié)作效率,降低工程維護成本。
????? 我們知道 java 項目結(jié)構(gòu)是請求達到路由層控制器 controller,然后 controller 會去調(diào)用 service 層邏輯代碼,然后 service 層會去調(diào)用 dao 層的接口方法,其實 dao 層都是以接口的形式提供,然后這些接口里頭的都是操作數(shù)據(jù)庫的方法,然后與 dao 層對應(yīng)著的有一個 mapper,mapper 是以 xml 形式提供的,與 dao 層中的接口相對應(yīng),xml 中實際就是實現(xiàn)了 dao 接口中的這些具體方法,xml 中會與指定的 dao 接口中指定的方法進行綁定,xml 中會去寫 sql 邏輯。具體請看架構(gòu)師技能1:Java工程規(guī)范、淺析領(lǐng)域模型VO、DTO、DO、PO、優(yōu)秀命名
?????
?
一、Go語言自身項目的基本結(jié)構(gòu)
首先我們先看Go語言自身項目的基本結(jié)構(gòu)。
Go項目的項目結(jié)構(gòu)自1.0版本發(fā)布以來一直十分穩(wěn)定,直到現(xiàn)在Go項目的頂層結(jié)構(gòu)基本沒有大的改變。go項目大致結(jié)構(gòu)如下,GitHub - golang/go: The Go programming language
$ tree -LF 1 ~/go/src/github.com/golang/go
./go
├── api/
├── doc/
├── lib/
├── misc/
├── src/├── test
├── PATENTS
├── LICENSE
├── CONTRIBUTING.md
└── README.md
作為Go語言的“創(chuàng)世項目”,其項目結(jié)構(gòu)的布局對后續(xù)的其他Go語言項目具有重要的參考意義,尤其是早期Go項目中src目錄下面的結(jié)構(gòu),更是在后續(xù)被Go社區(qū)作為Go應(yīng)用項目結(jié)構(gòu)的模板被廣泛使用。我們以早期的Go 1.3版本的src目錄下的結(jié)構(gòu)為例:
$ tree -LF 1 ./src
./src
├── all.bash*
├── all.bat
├── all.rc*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── lib9/
├── libbio/
├── liblink/
├── make.bash*
├── make.bat
├── Make.dist
├── make.rc*
├── nacltest.bash*
├── pkg/
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
└── sudo.bash*
src目錄下面的結(jié)構(gòu)三個特點:
1)代碼構(gòu)建的腳本源文件放在src下面的頂層目錄下;
2)src下的二級目錄cmd下面存放著go工具鏈相關(guān)的可執(zhí)行文件(比如:go、gofmt等)的主目錄以及它們的main包源文件;
3)src下的二級目錄pkg下面存放著上面cmd下各工具鏈程序依賴的包、go運行時以及go標準庫的源文件
在Go 1.3版本以后至今,Go項目下的src目錄中發(fā)生了幾次結(jié)構(gòu)上的變動:
Go 1.4版本中刪除了Go源碼樹中src/pkg/xxx中pkg這一層級目錄而直接使用src/xxx;
Go 1.4版本在src下面增加internal目錄,用于存放無法被外部導(dǎo)入僅Go項目自用的包;
Go 1.6版本在src下面增加vendor目錄,但Go項目自身真正啟用vendor機制是在Go 1.7版本中。vendor目錄中存放了go項目自身對外部項目的依賴,主要是golang.org/x下的各個包,包括:net、text、crypto等。該目錄下的包會在每次Go版本發(fā)布時做更新;
Go 1.13版本在src下面增加了go.mod和go.num,實現(xiàn)了go項目自身的go module遷移,go項目內(nèi)所有包被放入名為std的module下面,其依賴的包依然是golang.org/x下的各個包
// Go 1.13版本go項目src下面的go.mod
module std
?
go 1.12
?
require (
??? golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68
??? golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
??? golang.org/x/sys v0.0.0-20190529130038-5219a1e1c5f8 // indirect
??? golang.org/x/text v0.3.2 // indirect
)
下面是最新的Go 1.16版本src目錄下的完整布局:
├── Make.dist
├── README.vendor
├── all.bash*
├── all.bat
├── all.rc*
├── bootstrap.bash*
├── buildall.bash*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── cmp.bash
├── go.mod
├── go.sum
├── internal/
├── make.bash*
├── make.bat
├── make.rc*
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
├── testdata/
...
└── vendor/
?
Go 1.14 Go Modules 投入使用后,就無需擔心 $GOPATH 以及項目放置的位置。所以項目的 vendor 可以忽略了,建議直接使用 module 來管理依賴
二、優(yōu)秀開源 的go項目結(jié)構(gòu)樣例
1、Docker
https://github.com/moby/moby
├── api? ? ? //?存放對外公開的 API 規(guī)則
├── builder? // 存放構(gòu)建腳本等
├── cli? ? ? // 命令行的主要邏輯
├── cmd? ? ? // 存放可執(zhí)行程序,main 包放這個目錄中
├── contrib? // 存放一些有用的腳本或文件,但不是項目的核心部分
├── docs? ? // 存放文檔
├── internal // 只在本項目使用的包(私有)
├── pkg? ? ?// 本項目以及其他項目可以使用的包(公有)
├── plugin? // 提供插件功能
2、Kubernetes
https://github.com/kubernetes/kubernetes
├── api
├── build? // 存放構(gòu)建腳本等
├── cmd
├── docs
├── pkg
├── plugin
├── test? ? // 單元測試之外的測試程序、測試數(shù)據(jù)
├── third_party // 經(jīng)過修改的第三方的代碼
3、Gogs
https://github.com/gogs/gogs
├── cmd
├── conf? ? // 對配置進行解析
├── docker? // 存放 docker 腳本
├── models? // MVC 中的 model
├── pkg
├── public? // 靜態(tài)公共資源,實際項目會將其存入 CDN
├── routes? // 路由
├── scripts // 腳本文件
├── templates // 存放模板文件
總體上這些優(yōu)秀開源項目,沒有統(tǒng)一一致的目錄結(jié)構(gòu)方式,但大體上,有一些通用的地方,這就有
project-layout/README_zh.md at master · golang-standards/project-layout · GitHub做參考。
三、通用項目目錄結(jié)構(gòu)參考
參考:
project-layout/README_zh.md at master · golang-standards/project-layout · GitHub
1、web服務(wù)應(yīng)用程序目錄
/api
OpenAPI/Swagger 規(guī)范,JSON 模式文件,協(xié)議定義文件。
/web
特定于 Web 應(yīng)用程序的組件:靜態(tài) Web 資產(chǎn)、服務(wù)器端模板和 SPAs。
2、通用應(yīng)用目錄
/configs
配置文件模板或默認配置。
將你的?confd
?或?consul-template
?模板文件放在這里。
/init
System init(systemd,upstart,sysv)和 process manager/supervisor(runit,supervisor)配置。
/scripts
執(zhí)行各種構(gòu)建、安裝、分析等操作的腳本。
這些腳本保持了根級別的?Makefile 變得小而簡單(例如,?terraform/Makefile at main · hashicorp/terraform · GitHub?)。
有關(guān)示例,請參見 ?/scripts?目錄。
/build
打包和持續(xù)集成。
將你的云( AMI )、容器( Docker )、操作系統(tǒng)( deb、rpm、pkg )包配置和腳本放在?/build/package
?目錄下。
將你的 CI (travis、circle、drone)配置和腳本放在?/build/ci
?目錄中。請注意,有些 CI 工具(例如 Travis CI)對配置文件的位置非常挑剔。嘗試將配置文件放在?/build/ci
?目錄中,將它們鏈接到 CI 工具期望它們的位置(如果可能的話)。
/deployments
IaaS、PaaS、系統(tǒng)和容器編排部署配置和模板(docker-compose、kubernetes/helm、mesos、terraform、bosh)。注意,在一些存儲庫中(特別是使用 kubernetes 部署的應(yīng)用程序),這個目錄被稱為?/deploy
。
/test
額外的外部測試應(yīng)用程序和測試數(shù)據(jù)。你可以隨時根據(jù)需求構(gòu)造?/test
?目錄。對于較大的項目,有一個數(shù)據(jù)子目錄是有意義的。例如,你可以使用?/test/data
?或?/test/testdata
?(如果你需要忽略目錄中的內(nèi)容)。請注意,Go 還會忽略以“.”或“_”開頭的目錄或文件,因此在如何命名測試數(shù)據(jù)目錄方面有更大的靈活性。
有關(guān)示例,請參見??/test?目錄。
我們可以參考project-layout/README_zh.md at master · golang-standards/project-layout · GitHub
3、其他目錄
/docs
設(shè)計和用戶文檔(除了 godoc 生成的文檔之外)。
有關(guān)示例,請參閱?/docs?目錄。
/tools
這個項目的支持工具。注意,這些工具可以從?/pkg
?和?/internal
?目錄導(dǎo)入代碼。
有關(guān)示例,請參見?/tools?目錄。
/examples
你的應(yīng)用程序和/或公共庫的示例。
有關(guān)示例,請參見?/examples?目錄。
/third_party
外部輔助工具,分叉代碼和其他第三方工具(例如 Swagger UI)。
/githooks
Git hooks。
/assets
與存儲庫一起使用的其他資產(chǎn)(圖像、徽標等)。
/website
如果你不使用 Github 頁面,則在這里放置項目的網(wǎng)站數(shù)據(jù)。
有關(guān)示例,請參見?/website?目錄。
4、不應(yīng)該擁有的目錄
/src
有些 Go 項目確實有一個?src
?文件夾,但這通常發(fā)生在開發(fā)人員有 Java 背景,在那里它是一種常見的模式。如果可以的話,盡量不要采用這種 Java 模式。你真的不希望你的 Go 代碼或 Go 項目看起來像 Java:-)
不要將項目級別?src
?目錄與 Go 用于其工作空間的?src
?目錄(如?How to Write Go Code?中所述)混淆。$GOPATH
?環(huán)境變量指向你的(當前)工作空間(默認情況下,它指向非 windows 系統(tǒng)上的?$HOME/go
)。這個工作空間包括頂層?/pkg
,?/bin
?和?/src
?目錄。你的實際項目最終是?/src
?下的一個子目錄,因此,如果你的項目中有?/src
?目錄,那么項目路徑將是這樣的:?/some/path/to/workspace/src/your_project/src/your_code.go
。注意,在 Go 1.11 中,可以將項目放在?GOPATH
?之外,但這并不意味著使用這種布局模式是一個好主意。
四、代碼架構(gòu)
我們在《架構(gòu)設(shè)計1:談?wù)劶軜?gòu)》已經(jīng)提到代碼架構(gòu),主要定義內(nèi)容:
一、代碼單元:
? ? ? ? 1、配置設(shè)計
? ? ? ? 2、框架、類庫。
二、代碼單元組織:
? ? ? ?1、編碼規(guī)范,編碼的慣例。
? ? ? ?2、項目模塊劃分
? ? ? ?3、頂層文件結(jié)構(gòu)設(shè)計,比如mvc設(shè)計。
? ? ? ?4、依賴關(guān)系
?我們再次只提分層依賴和目錄規(guī)范結(jié)構(gòu):
1、代碼分層和依賴
?????? 代碼分層,讓不同層次的代碼做不同的動作。層次清晰的代碼,提高可讀性,從代碼結(jié)構(gòu)就大概能了解到代碼是如何分層,每層大概功能是什么。例如java常用的Controller、Service、Mapper/Dao三層代碼結(jié)構(gòu),其各層的代碼邏輯范圍。
2、默認上層依賴于下層
??? 依賴規(guī)則規(guī)定上層的代碼可以依賴下層,但是下層的代碼不可以依賴上層。也就是說下層邏輯不可以依賴任何上層定義的變量,函數(shù),結(jié)構(gòu)體,類,模塊等等代碼實體。
?通過分層,一個龐大系統(tǒng)切分成不同部分,便于分工合作和維護。
??????? 應(yīng)用層:主要負責具體的業(yè)務(wù)邏輯處理
???????? 服務(wù)層:提供可復(fù)用的服務(wù)
???????? 數(shù)據(jù)層:負責數(shù)據(jù)的存儲和訪問
?????? 假如說,最上層應(yīng)用層處使用了 go 語言的 gorm 三方庫,并定義了 gorm 相關(guān)的數(shù)據(jù)庫結(jié)構(gòu)體及其 tag 等。那么下層數(shù)據(jù)層不可以引用任何外層中 gorm 相關(guān)的結(jié)構(gòu)體或方法,甚至不應(yīng)該感知到 gorm 的存在。
?但是,分層架構(gòu)也有一些挑戰(zhàn):①必須合理規(guī)劃層次邊界和接口;②禁止跨層次的調(diào)用及逆向用。?? 《架構(gòu)設(shè)計5:架構(gòu)模式-分層模式》?? 《架構(gòu)設(shè)計5:架構(gòu)模式-分層模式》?? 《架構(gòu)設(shè)計5:架構(gòu)模式-分層模式》
3、參考的項目目錄結(jié)構(gòu)
可以參考,可以根據(jù)自己團隊和實際項目來做改動,規(guī)范的最主要目的是統(tǒng)一認知。
├── app/application // App層,處理Adapter層適配過后與框架、協(xié)議等無關(guān)的業(yè)務(wù)邏輯
├ ├── api 處理OpenAPI 接口請求
├ ├── web 請求Web頁面請求
├ ├── consumer //(可選)處理外部消息
├ ├── scheduler/task //處理定時任務(wù),比如Cron格式的定時Job
├── domain // Domain層,最純粹的業(yè)務(wù)實體及其規(guī)則的抽象定義
│ ├── interface/gateway // 領(lǐng)域網(wǎng)關(guān),model的核心邏輯以Interface形式在此定義,交由biz層去實現(xiàn)
│ └── model // 領(lǐng)域模型實體
├── biz/module 業(yè)務(wù)/業(yè)務(wù)模塊層
├ └──module1
├ ├──dao 數(shù)據(jù)庫層
├ ├──model 業(yè)務(wù)模型
├ ├──entity 數(shù)據(jù)庫模型
├ ├──service 業(yè)務(wù)邏輯
├ └──manager 復(fù)用邏輯
├── configs 配置
├── init //系統(tǒng)初始化
├── pkg
├── public // 靜態(tài)公共資源,實際項目會將其存入 CDN
├── build 打包和持續(xù)集成
├── scripts // 腳本文件:執(zhí)行各種構(gòu)建、安裝、分析等操作的腳本
├── test // 單元測試之外的測試程序、測試數(shù)據(jù)
├── plugin 各種插件
├── util/tools 工具包
├── main.go 項目運行入口
└── pkg // 各層可共享的公共組件代碼