ホームページ  >  記事  >  バックエンド開発  >  Go flat プロジェクトの構造を理解する

Go flat プロジェクトの構造を理解する

coldplay.xixi
coldplay.xixi転載
2020-08-13 16:54:253564ブラウズ

Go flat プロジェクトの構造を理解する

Go flat プロジェクトの構造を理解する

コードをパッケージに分割する方法を理解するのに時間を費やす代わりに、フラット構造のアプリケーションにはすべてが含まれます .go ファイルはパッケージに配置されます。

myapp/
  main.go
  server.go
  user.go
  lesson.go
  course.go

Go flat プロジェクトの構造を理解する を始めるとき、ほとんどの人はフラットなアプリケーション構造から始めます。 Go flat プロジェクトの構造を理解する ツアーのすべてのプログラム、Go flat プロジェクトの構造を理解するphercises のほとんどの演習、およびその他の初期の Go flat プロジェクトの構造を理解する プログラムの多くは、どのパッケージにも分割されていません。代わりに、いくつかの .go ファイルを作成し、すべてのコードを同じ (通常は main) パッケージに入れるだけです。

最初は、これは悪く聞こえるかもしれません。コードはすぐに扱いにくくなるでしょうか?ビジネス ロジックを UI レンダリング コードから分離するにはどうすればよいですか?正しいソース ファイルを見つけるにはどうすればよいですか?結局のところ、パッケージを使用する理由の大きな部分は、適切なソース ファイルへの迅速な移動を容易にしながら、懸念事項を分離することです。

関連する学習の推奨事項: Go flat プロジェクトの構造を理解する 言語チュートリアル

フラット構造の効果的な使用

フラット構造を使用する場合、次のことを行う必要があります。コーディングのベスト プラクティスに従ってください。アプリケーションのさまざまな部分を分離するには、さまざまな .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)
}

実際には、次のことが可能です。基本的にフラット構造のコードをすべて 1 つのパッケージで使用し、コマンドを別の 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 パッケージが存在します。ニーズがあるためです。たとえば、同じコア アプリケーションを使用して 2 つのコマンドをサポートする必要がある場合があります。

なぜフラット構造を使用するのでしょうか?

フラット構造の主な利点は、すべてのコードを 1 つのディレクトリに保管したり、そのような愚かなことをしないことです。この構造の主な利点は、物事をどのように整理するかを心配する必要がなくなり、アプリケーションで解決しようとしている問題の解決に取り掛かることができることです。

このアプリケーション構造が PHP 時代を思い出させてくれるのがとても気に入っています。初めてコーディングを学んだとき、ロジックがあらゆる種類の HTML と混合されたランダムな PHP ファイルを使用し始めましたが、それは本当に混乱しました。大規模なアプリケーションのように構築することを提案しているわけではありませんが、それはひどいことになります。しかし、私はすべてをどこに置くべきかについてあまり心配せず、コーディング方法を学び、特定の問題を解決することに集中します。アプリケーションのニーズ、ドメイン、または一般的なコーディング方法を理解しようとしている場合でも、フラット構造を使用すると、学習と構築に集中しやすくなります。

これは真実です。なぜなら、「このロジックはどこに行けばよいのか?」などの質問について心配する必要がなくなるからです。なぜなら、もし間違いを犯したとしても、修正するのは簡単だからです。それが関数の場合は、パッケージ内の任意の新しいソース ファイルに移動できます。間違ったタイプのメソッドである場合は、2 つの新しいタイプを作成し、ロジックを元のタイプから分離できます。これらを使用すると、パッケージが 1 つしかないため、奇妙な循環依存関係の問題が発生することを心配する必要がなくなります。

フラット構造を検討するもう 1 つの重要な理由は、アプリケーションの複雑さが増すにつれて、構造の進化がはるかに容易になることです。コードを別のパッケージに分割することで利点が得られることが明らかな場合、通常必要なのは、いくつかのソース ファイルをサブディレクトリに移動し、そのパッケージを変更し、新しいプログラム パッケージのプレフィックスを使用するように参照を更新することだけです。たとえば、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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。