Maison  >  Article  >  développement back-end  >  Comprendre la structure du projet Go flat

Comprendre la structure du projet Go flat

coldplay.xixi
coldplay.xixiavant
2020-08-13 16:54:253553parcourir

Comprendre la structure du projet Go flat

Comprendre la structure du projet Go flat

Au lieu de passer du temps à essayer de comprendre comment diviser votre code en packages, une application à structure plate aura tout .goLes fichiers sont placés dans un package.

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

Quand on se lance dans Comprendre la structure du projet Go flat, presque tout le monde commence avec une structure d'application plate. Chaque programme de la tournée Comprendre la structure du projet Go flat, la plupart des exercices de Comprendre la structure du projet Go flatphercises et de nombreux autres premiers programmes Comprendre la structure du projet Go flat ne sont divisés en aucun package. Au lieu de cela, nous créons simplement quelques .go fichiers et mettons tout le code dans le même package (généralement main).

À première vue, cela semble mauvais. Le code deviendra-t-il rapidement lourd ? Comment séparer la logique métier du code de rendu de l'interface utilisateur ? Comment trouver le bon fichier source ? Après tout, une grande partie de la raison pour laquelle nous utilisons des packages est de séparer les problèmes tout en facilitant la navigation rapide vers les fichiers sources corrects.

Recommandations d'apprentissage associées : Tutoriel de langue Comprendre la structure du projet Go flat

Utilisation efficace des structures plates

Lorsque vous utilisez des structures plates, vous devez toujours essayez de suivre les meilleures pratiques de codage. Vous devrez utiliser différents .go fichiers pour séparer les différentes parties de votre application :

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

Les variables globales peuvent toujours poser problème, vous devriez donc envisager d'utiliser des types avec des méthodes pour les garder en dehors de votre code :

type Server struct {
  apiClient *someapi.Client
  router *some.Router
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  s.router.ServeHTTP(w, r)
}

Et votre fonction main() devrait probablement encore supprimer la majeure partie de la logique en dehors de l'application de configuration :

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

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)
}

En fait, vous pouvez réellement utiliser ce qui est fondamentalement une structure plate de code tout en un package et définissez les commandes dans des main packages séparés. Cela vous permettra d'utiliser le modèle de sous-répertoire cmd commun :

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

Dans cet exemple, votre application est toujours fondamentalement plate, mais vous avez retiré le package main parce que vous en avez besoin - par exemple il peut être nécessaire d'utiliser la même application principale pour prendre en charge les deux commandes.

Pourquoi utiliser une structure plate ?

Le principal avantage d'une structure plate est de ne pas conserver tout votre code dans un seul répertoire, ou quelque chose de stupide comme ça. Le principal avantage de cette structure est que vous pouvez cesser de vous soucier de la façon d'organiser les choses et de résoudre le problème que vous souhaitez résoudre avec votre application.

J'adore la façon dont cette structure d'application me rappelle mes années PHP. Quand j’ai appris à coder, j’ai commencé à utiliser des fichiers PHP aléatoires avec leur logique mélangée à toutes sortes de HTML, et c’était un véritable gâchis. Je ne suggère pas que nous la construisions comme une grande application - ce serait terrible - mais je m'inquiète moins de savoir où tout devrait être et me concentre davantage sur l'apprentissage de la façon de coder et de résoudre mon problème spécifique. Que vous essayiez de comprendre les besoins de votre application, de votre domaine ou comment coder en général, l'utilisation d'une structure plate vous permet de vous concentrer plus facilement sur l'apprentissage et la construction.

C'est vrai parce que nous pouvons arrêter de nous soucier de questions comme "où doit aller cette logique ?" Parce que si nous faisons une erreur, c’est facile à réparer. S'il s'agit d'une fonction, nous pouvons la déplacer vers n'importe quel nouveau fichier source du package. Si ce n'est pas le bon type de méthode, nous pouvons créer deux nouveaux types et séparer la logique du type d'origine. Avec ceux-ci, nous n'avons pas à craindre de rencontrer d'étranges problèmes de dépendance cyclique puisque nous n'avons qu'un seul package.

Une autre bonne raison d'envisager des structures plates est qu'à mesure que la complexité de votre application augmente, il devient beaucoup plus facile de faire évoluer la structure. Lorsqu'il est évident que vous pourriez bénéficier de la division de votre code dans un package distinct, tout ce que vous avez à faire est généralement de déplacer certains fichiers source dans un sous-répertoire, de modifier son package et de mettre à jour toutes les références pour utiliser le nouveau préfixe du package de programme. Par exemple, si nous avions SqlUser et décidions de bénéficier de la gestion de toute la logique liée à la base de données dans un package sql distinct, nous mettrions à jour toutes les références pour utiliser sql.User将类型移动到新软件包后 maintenant. Je trouve que les structures comme MVC sont plus difficiles à refactoriser, mais pas aussi difficiles ou difficiles que d'autres langages de programmation.

La structure plate est particulièrement utile pour les débutants qui sont souvent trop rapides pour créer des packages. Je ne peux pas vraiment dire pourquoi cela se produit, mais les débutants sur Comprendre la structure du projet Go flat aiment créer des tonnes de packages, ce qui conduit presque toujours à un bégaiement (user.User), à des dépendances cycliques ou à un autre problème.

Dans le prochain article sur MVC, nous explorerons les façons dont ce phénomène de création de trop de packages fait que MVC semble impossible dans Comprendre la structure du projet Go flat, même si ce n'est pas le cas.

通过推迟创建新程序包的决定,直到我们的应用程序增长一点并更好地了解它,发芽的Comprendre la structure du projet Go flatphers犯此错误的可能性就大大降低了。

这也是为什么很多人会鼓励开发人员避免过早将其代码分解到微服务中的原因-您通常没有足够的知识来真正知道应该和不应该将哪些内容分解为微服务以及抢先式微服务( 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 Comprendre la structure du projet Go flat 1.13 thing that I haven't really
    // tested out, so let me know if I'm using it wrong

相关学习推荐:编程视频

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer