>백엔드 개발 >Golang >Go flat 프로젝트 구조 이해

Go flat 프로젝트 구조 이해

coldplay.xixi
coldplay.xixi앞으로
2020-08-13 16:54:253599검색
myapp/
  main.go
  server.go
  user.go
  lesson.go
  course.go

Go flat 프로젝트 구조 이해에 입문하면 거의 모든 사람이 플랫한 애플리케이션 구조로 시작합니다. Go flat 프로젝트 구조 이해 투어의 모든 프로그램, Go flat 프로젝트 구조 이해phercises의 대부분의 연습 및 기타 많은 초기 Go flat 프로젝트 구조 이해 프로그램은 어떤 패키지로도 분할되지 않습니다. 대신, 몇 개의 .go 파일을 만들고 모든 코드를 동일한(보통 main) 패키지에 넣습니다. Go flat 프로젝트 구조 이해

처음에는 끔찍하게 들립니다. 코드가 금방 다루기 어려워지나요? UI 렌더링 코드에서 비즈니스 로직을 분리하는 방법은 무엇입니까? 올바른 소스 파일을 어떻게 찾나요? 결국, 우리가 패키지를 사용하는 가장 큰 이유는 문제를 분리하는 동시에 올바른 소스 파일을 더 쉽고 빠르게 탐색할 수 있도록 하기 위한 것입니다.

Go flat 프로젝트 구조 이해관련 학습 권장사항: Go flat 프로젝트 구조 이해 언어 튜토리얼

플랫 구조를 효과적으로 사용하세요

플랫 구조를 사용할 때에도 코딩 모범 사례를 준수해야 합니다. 애플리케이션의 여러 부분을 분리하려면 서로 다른 .go 파일을 사용해야 합니다. .go文件放置在一个软件包中。

myapp /
  main.go#阅读配置并在此处启动您的应用
  server.go#总体HTTP处理逻辑在这里
  user_handler.go#用户http处理程序逻辑在这里
  user_store.go#用户数据库逻辑在这里
  # 等等...

进入Go flat 프로젝트 구조 이해时,几乎每个人都从一个平面应用程序结构开始。 Go flat 프로젝트 구조 이해 tour中的每个程序,Go flat 프로젝트 구조 이해phercises中的大多数练习以及许多其他早期的Go flat 프로젝트 구조 이해程序都没有被分解成任何包装。取而代之的是,我们只创建几个.go文件,然后将所有代码放入相同的(通常是main)包中。

起初,这听起来很糟糕。代码会很快变得笨拙吗?如何将业务逻辑与UI渲染代码分开?我如何找到正确的源文件?毕竟,我们使用软件包的很大一部分原因是要分离关注点,同时使更容易快速地导航到正确的源文件。

相关学习推荐:Go flat 프로젝트 구조 이해语言教程

有效使用平面结构

使用平面结构时,您仍应尝试遵守编码最佳实践。您将需要使用不同的.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)
}

全局变量仍然可能成为问题,因此您应考虑将类型与方法配合使用,以使它们脱离代码:

//警告:此示例非常人为设计,甚至可能无法编译。

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()函数可能仍应在设置应用程序之外删除大多数逻辑:

myapp/
  cmd/
    web/
      # package main
      main.go
    cli/
      # package main
      main.go
  # package myapp
  server.go
  user_handler.go
  user_store.go
  ...

实际上,您实际上可以将基本上是平面结构的代码全部使用在一个软件包中,并在单独的main软件包中定义命令。这将允许您使用常见的cmd子目录模式:

输入JsonCourse struct {
  ID字符串`json:“ id”`
  价格结构{
    USD字符串`json:“ usd”`
  }`json:“价格”`
}

在此示例中,您的应用程序基本上仍然是平坦的,但是您拔出了main软件包是因为您有需要-例如可能需要使用同一核心应用程序来支持两个命令。

为什么要使用扁平结构?

扁平结构的主要好处不是将所有代码都保存在一个目录中,也不是那样愚蠢的东西。这种结构的核心好处是您可以不必担心如何组织事物,而可以继续解决您打算通过应用程序解决的问题。

我绝对喜欢这个应用程序结构让我回想起PHP的日子。当我第一次学习编码时,我开始使用随机PHP文件,其逻辑与各种HTML混合在一起,这真是一团糟。我并不是在建议我们以大型应用程序的方式构建-那样会很糟糕-但是我并不担心一切都应该放在哪里,而是更加关注学习如何编写代码和解决我的特定问题。无论您是要了解应用程序的需求,您的域还是一般的编码方式,使用扁平结构都可以使您更轻松地专注于学习和构建。

这是正确的,因为我们可以不再担心诸如“这种逻辑应该去哪里?”之类的问题。因为如果我们犯了一个错误,很容易解决。如果它是一个函数,我们可以将其移动到包中的任何新源文件中。如果它是错误类型的方法,我们可以创建两个新类型并将逻辑与原始类型分开。有了这些,我们就不必担心会遇到奇怪的周期性依赖问题,因为我们只有一个软件包。

考虑平面结构的另一个重要原因是,随着应用程序复杂性的提高,结构的发展变得容易得多。当您明显可以从将代码拆分到一个单独的程序包中受益时,您通常需要做的就是将一些源文件移到一个子目录中,更改其程序包,并更新任何引用以使用新的程序包前缀。例如,如果我们有SqlUser并决定从一个单独的sql包中处理所有与数据库相关的逻辑中受益,我们将更新所有引用以现在使用sql.User将类型移动到新软件包后。我发现,像MVC这样的结构在重构方面更具挑战性,尽管并非没有其他编程语言那样困难或困难。

扁平结构对于通常太快无法创建包的初学者特别有用。我真的不能说为什么会发生这种现象,但是Go flat 프로젝트 구조 이해的新手喜欢创建大量的软件包,这几乎总是导致口吃(user.User

type SqlCourse struct {
  ID    int
  Price int
}
전역 변수는 여전히 문제가 될 수 있으므로 코드에 포함되지 않도록 메소드가 있는 유형을 사용하는 것을 고려해야 합니다. :

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
}
그리고 main() 함수는 아마도 애플리케이션 설정 이외의 로직 대부분을 제거해야 할 것입니다.
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 flat 프로젝트 구조 이해 1.13 thing that I haven't really
    // tested out, so let me know if I'm using it wrong
실제로 전체 코드를 기본적으로 평면 구조로 만들 수도 있습니다. 패키지에 포함하고 별도의 main 패키지에 명령을 정의합니다. 이렇게 하면 일반적인 cmd 하위 디렉터리 패턴을 사용할 수 있습니다: 🎜rrreee🎜 이 예에서 애플리케이션은 기본적으로 여전히 플랫하지만 main를 꺼냈습니다. 패키지는 필요가 있습니다. 예를 들어 동일한 핵심 애플리케이션을 사용하여 두 개의 명령을 지원해야 할 수도 있습니다. 🎜

플랫 구조를 사용하는 이유는 무엇인가요?

🎜플랫 구조의 주요 이점은 모든 코드를 하나의 디렉토리에 보관하거나 그와 유사한 어리석은 작업을 수행하지 않는다는 것입니다. 이 구조의 핵심 이점은 항목을 구성하는 방법에 대한 걱정을 멈추고 애플리케이션으로 해결하려는 문제를 계속해서 해결할 수 있다는 것입니다. 🎜🎜저는 이 애플리케이션 구조가 제 PHP 시절을 생각나게 한다는 점을 정말 좋아합니다. 처음 코딩을 배웠을 때 모든 종류의 HTML이 논리와 혼합된 임의의 PHP 파일을 사용하기 시작했는데 정말 엉망이었습니다. 대규모 애플리케이션처럼 구축하라고 제안하는 것은 아닙니다. 그러면 끔찍할 것입니다. 하지만 모든 것이 어디에 있어야 하는지에 대한 걱정을 덜고 특정 문제를 코딩하고 해결하는 방법을 배우는 데 더 집중할 수 있습니다. 애플리케이션, 도메인 또는 일반적인 코딩 방법의 요구 사항을 이해하려는 경우 평면 구조를 사용하면 학습 및 구축에 더 쉽게 집중할 수 있습니다. 🎜🎜맞습니다. "이 논리는 어디로 가야 하는가?"와 같은 질문에 대한 걱정을 멈출 수 있기 때문입니다. 실수를 하면 고치기가 쉽기 때문입니다. 함수인 경우 패키지의 새 소스 파일로 이동할 수 있습니다. 잘못된 유형의 메서드인 경우 두 개의 새로운 유형을 만들고 원래 유형에서 논리를 분리할 수 있습니다. 이를 사용하면 패키지가 하나만 있으므로 이상한 순환 종속성 문제가 발생할까 걱정할 필요가 없습니다. 🎜🎜플랫 구조를 고려해야 하는 또 다른 큰 이유는 애플리케이션의 복잡성이 증가함에 따라 구조를 발전시키는 것이 훨씬 더 쉬워진다는 것입니다. 코드를 별도의 패키지로 분할하면 이점을 얻을 수 있다는 것이 분명한 경우 일반적으로 해야 할 일은 일부 소스 파일을 하위 디렉터리로 이동하고, 해당 패키지를 변경하고, 새 프로그램 패키지 접두사를 사용하도록 모든 참조를 업데이트하는 것입니다. 예를 들어 SqlUser가 있고 별도의 sql 패키지에서 모든 데이터베이스 관련 논리를 처리하는 이점을 누리기로 결정한 경우 이제 sql을 사용하도록 모든 참조를 업데이트합니다. .사용자 유형은 이후 새 패키지로 이동되었습니다. MVC와 같은 구조는 다른 프로그래밍 언어만큼 어렵거나 어렵지는 않지만 리팩토링하기가 더 어렵다는 것을 알았습니다. 🎜🎜플랫 구조는 패키지를 너무 빨리 만드는 초보자에게 특히 유용합니다. 실제로 왜 이런 일이 발생하는지 말할 수는 없지만 Go flat 프로젝트 구조 이해 초보자는 수많은 패키지를 만드는 것을 좋아하는데, 이로 인해 거의 항상 끊김 현상(user.User), 순환 종속성 또는 기타 문제가 발생합니다. 🎜🎜🎜 MVC에 대한 다음 기사에서는 너무 많은 패키지를 생성하는 현상이 Go flat 프로젝트 구조 이해에서는 그렇지 않더라도 MVC가 불가능해 보일 수 있는 방식을 살펴보겠습니다. 🎜🎜

通过推迟创建新程序包的决定,直到我们的应用程序增长一点并更好地了解它,发芽的Go flat 프로젝트 구조 이해phers犯此错误的可能性就大大降低了。

这也是为什么很多人会鼓励开发人员避免过早将其代码分解到微服务中的原因-您通常没有足够的知识来真正知道应该和不应该将哪些内容分解为微服务以及抢先式微服务( I kinda希望能成为一句俗语)只会在将来带来更多工作。

平坦的结构并不全是阳光和彩虹

假装使用扁平结构没有任何不利之处,这对我来说是不诚实的,所以我们也应该讨论这些。

对于初学者来说,扁平的结构只能使您受益匪浅。它会工作一段时间(可能比您想象的更长),但是到某个时候,您的应用程序将变得足够复杂,您需要开始分解它。使用平面结构的好处是您可以推迟使用它,并且在分解时可能会更好地理解您的代码。缺点是,您将需要花一些时间进行重构,并且您可能(也许-但这很麻烦)发现自己已经重构为您想从任何地方开始的结构。

使用平面结构时,命名冲突有时也会很尴尬。例如,假设您想要在应用程序中使用Course类型,但是在数据库中表示课程的方式与在JSON中呈现课程的方式不同。一个快速的解决方案是创建两种类型,但是由于它们都在同一个包中,因此每种类型都需要使用不同的名称,并且可能最终以类似以下内容的形式出现:SqlCourseJsonCourse。这确实没什么大不了的,但是有点令人遗憾的是我们最终得到了零类型,简单地称为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 flat 프로젝트 구조 이해 1.13 thing that I haven't really
    // tested out, so let me know if I'm using it wrong

相关学习推荐:编程视频

위 내용은 Go flat 프로젝트 구조 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제