無需花時間試圖弄清楚如何將程式碼分解為軟體包,而是採用扁平結構的應用程式會將所有.go
檔案放置在一個軟體包中。
myapp/ main.go server.go user.go lesson.go course.go
進入了解Go 扁平化專案結構時,幾乎每個人都從一個平面應用程式結構開始。 了解Go 扁平化專案結構 tour中的每個程序,了解Go 扁平化專案結構phercises中的大多數練習以及許多其他早期的了解Go 扁平化專案結構程序都沒有被分解成任何包裝。取而代之的是,我們只創建幾個.go
文件,然後將所有程式碼放入相同的(通常是main
)套件中。
起初,這聽起來很糟糕。程式碼會很快變得笨拙嗎?如何將業務邏輯與UI渲染程式碼分開?我如何找到正確的原始檔?畢竟,我們使用軟體套件的很大一部分原因是要分離關注點,同時使更容易快速地導航到正確的來源檔案。
相關學習推薦:了解Go 扁平化專案結構語言教學
#使用平面結構時,您仍應嘗試遵守編碼最佳實踐。您將需要使用不同的.go
檔案分隔應用程式的不同部分:
myapp / main.go#阅读配置并在此处启动您的应用 server.go#总体HTTP处理逻辑在这里 user_handler.go#用户http处理程序逻辑在这里 user_store.go#用户数据库逻辑在这里 # 等等...
全域變數仍然可能成為問題,因此您應考慮將類型與方法配合使用,以使它們脫離程式碼:
type Server struct { apiClient *someapi.Client router *some.Router } func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.router.ServeHTTP(w, r) }
而且您的main()
函數可能仍應在設定應用程式之外刪除大多數邏輯:
//警告:此示例非常人为设计,甚至可能无法编译。 type Config struct { SomeAPIKey string Port string EnableTheThing bool } func main() { var config Config config.SomeAPIKey = os.Getenv("SOMEAPI_KEY") config.Port = os.Getenv("MYAPP_PORT") if config.Port == "" { config.Port = "3000" } config.EnableTheThing = true if err := run(config); err != nil { log.Fatal(err) } } func run(config Config) error { server := myapp.Server{ APIClient: someapi.NewClient(config.SomeAPIKey), } return http.ListenAndServe(":" + config.Port, server) }
實際上,您實際上基本上是平面結構的程式碼全部可以使用在一個軟體包中,並在單獨的main
軟體包中定義命令。這將允許您使用常見的cmd
子目錄模式:
myapp/ cmd/ web/ # package main main.go cli/ # package main main.go # package myapp server.go user_handler.go user_store.go ...
在此範例中,您的應用程式基本上仍然是平坦的,但是您拔出了main
軟體包是因為您有需要-例如可能需要使用相同核心應用程式來支援兩個命令。
扁平結構的主要好處不是將所有程式碼都保存在一個目錄中,也不是那樣愚蠢的東西。這種結構的核心好處是您可以不必擔心如何組織事物,而可以繼續解決您打算透過應用程式解決的問題。
我絕對喜歡這個應用程式結構讓我回想起PHP的日子。當我第一次學習編碼時,我開始使用隨機PHP文件,其邏輯與各種HTML混合在一起,這真是一團糟。我並不是建議我們以大型應用程式的方式構建-那樣會很糟糕-但是我並不擔心一切都應該放在哪裡,而是更加關注學習如何編寫程式碼和解決我的特定問題。無論您是要了解應用程式的需求,您的網域還是一般的編碼方式,使用扁平結構都可以使您更輕鬆地專注於學習和建構。
這是正確的,因為我們可以不再擔心諸如「這種邏輯應該去哪裡?」之類的問題。因為如果我們犯了一個錯誤,就很容易解決。如果它是一個函數,我們可以將其移動到套件中的任何新原始檔案中。如果它是錯誤類型的方法,我們可以建立兩個新類型並將邏輯與原始類型分開。有了這些,我們就不必擔心會遇到奇怪的週期性依賴問題,因為我們只有一個軟體包。
考慮平面結構的另一個重要原因是,隨著應用程式複雜性的提高,結構的發展變得容易得多。當您明顯可以從將程式碼拆分到單獨的程式包中受益時,您通常需要做的就是將一些原始檔案移到一個子目錄中,更改其程式包,並更新任何引用以使用新的程序包前綴。例如,如果我們有SqlUser
並決定從一個單獨的sql
套件中處理所有與資料庫相關的邏輯中受益,我們將更新所有引用以現在使用sql. User將類型移到新軟體包後
。我發現,像MVC這樣的結構在重構上更具挑戰性,儘管並非沒有其他程式語言那麼困難或困難。
扁平結構對於通常太快無法建立套件的初學者特別有用。我真的不能說為什麼會發生這種現象,但是了解Go 扁平化專案結構的新手喜歡創建大量的軟體包,這幾乎總是導致口吃(user.User
),週期性依賴關係或其他一些問題。
在下一篇有關MVC的文章中,我們將探討這種創建過多包的現像如何使MVC在了解Go 扁平化專案結構中顯得不可能的方法,儘管事實並非如此。
通过推迟创建新程序包的决定,直到我们的应用程序增长一点并更好地了解它,发芽的了解Go 扁平化專案結構phers犯此错误的可能性就大大降低了。
这也是为什么很多人会鼓励开发人员避免过早将其代码分解到微服务中的原因-您通常没有足够的知识来真正知道应该和不应该将哪些内容分解为微服务以及抢先式微服务( I kinda希望能成为一句俗语)只会在将来带来更多工作。
假装使用扁平结构没有任何不利之处,这对我来说是不诚实的,所以我们也应该讨论这些。
对于初学者来说,扁平的结构只能使您受益匪浅。它会工作一段时间(可能比您想象的更长),但是到某个时候,您的应用程序将变得足够复杂,您需要开始分解它。使用平面结构的好处是您可以推迟使用它,并且在分解时可能会更好地理解您的代码。缺点是,您将需要花一些时间进行重构,并且您可能(也许-但这很麻烦)发现自己已经重构为您想从任何地方开始的结构。
使用平面结构时,命名冲突有时也会很尴尬。例如,假设您想要在应用程序中使用Course
类型,但是在数据库中表示课程的方式与在JSON中呈现课程的方式不同。一个快速的解决方案是创建两种类型,但是由于它们都在同一个包中,因此每种类型都需要使用不同的名称,并且可能最终以类似以下内容的形式出现:SqlCourse
和JsonCourse
。这确实没什么大不了的,但是有点令人遗憾的是我们最终得到了零类型,简单地称为Course
。
将代码重构为新程序包也不总是那么简单。是的,这通常很容易,但是由于所有代码都在一个包中,因此您有时可能会遇到天生具有周期性的代码。例如,假设我们的课程是否具有在JSON响应中始终以crs_
开头的ID,并且我们想以各种货币返回价格。我们可以创建一个JsonCourse
来处理:
输入JsonCourse struct { ID字符串`json:“ id”` 价格结构{ USD字符串`json:“ usd”` }`json:“价格”` }
同时,SqlCourse
仅需要存储一个整数ID和一个以美分为单位的单一价格,我们可以使用各种货币对其进行格式化。
type SqlCourse struct { ID int Price int }
现在我们需要一种将SqlCourse
转换为JsonCourse
的方法,因此我们可以将其作为SqlCourse
类型的方法:
func (sc SqlCourse) ToJson() (JsonCourse, error) { jsonCourse := JsonCourse{ ID: fmt.Sprintf("crs_%v", sc.ID), } jsonCourse.Price.USD = Price: fmt.Sprintf("%d.%2d", sc.Price/100, sc.Price%100) return jsonCourse, nil }
然后稍后我们可能需要一种方法来解析传入的JSON并将其转换为SQL等效项,因此我们将其添加到JsonCourse
类型中作为另一种方法:
func (jc JsonCourse) ToSql() (SqlCourse, error) { var sqlCourse SqlCourse // JSON ID is "crs_123" and we convert to "123" // for SQL IDs id, err := strconv.Atoi(strings.TrimPrefix(jc.ID, "crs_")) if err != nil { // Note: %w is a 了解Go 扁平化專案結構 1.13 thing that I haven't really // tested out, so let me know if I'm using it wrong
相关学习推荐:编程视频
以上是了解Go 扁平化專案結構的詳細內容。更多資訊請關注PHP中文網其他相關文章!