J'aimerais entendre quelques conseils des gourous de Golang. Imaginez que j'ai un package pour la couche de base de données avec de nombreuses tables que je devrais définir des structures et des fonctions pour eux. A titre d'exemple, j'ai une table appelée "MyObject" et je définis une structure pour celle-ci.
var myobjects,err = db.AllMyObjects()
Est-ce pratique pour les fonctions liées à cette table / structure Je définis le récepteur comme ceci: p >
var myobject MyObject var myobjects,err = myobject.AllMyObjects()
De cette façon, au fur et à mesure que mon paquet db s'agrandit par les structures et les fonctions, il semblera plus propre et plus facile d'appeler des méthodes comme celle-ci (bien que je devrais définir 1 ligne supplémentaire): p >
func (o MyObject) AllMyObjects() ([]MyObject, error) { // retreive all MyObjects by query } func (o *MyObject) OneMyObjects() (MyObject, error) { // retreive one MyObject by query }
plutôt que d'appeler des fonctions directement au niveau du package (db est le nom de mon package)
type MyObject struct { RecID int Name string }
Est-ce une manière Go d'organiser le code ou avez-vous d'autres conseils à ce sujet?
3 Réponses :
Si vous pensez à la façon dont cela est utilisé, c'est une façon étrange d'organiser votre code. Les méthodes sont des comportements de leur type de récepteur. Le travail de MyObject
est-il de récupérer d'autres MyObject
s de la base de données? Cela ne semble pas juste. Cela devrait être le travail de quelque chose qui se connecte à la base de données. Cela peut être des fonctions de package ou un objet qui encapsule la connexion à la base de données ou la session de base de données; chacun peut être une approche valable en fonction de votre application, de votre base de données et des besoins de test (les fonctions du package sont beaucoup plus difficiles à tester car elles ne peuvent pas être simulées).
Par exemple, si vos types de modèle sont Foo et Bar, votre package de base de données peut avoir des types FooStore et BarStore, chacun ayant des méthodes pour en obtenir un par ID, obtenir tout, en insérer un, en mettre à jour un, etc. les besoins sont pour chaque type).
Il est souvent important de garder le code de la base de données séparé du modèle de données, afin que les packages qui fonctionnent avec le modèle n'aient pas à importer également le DBAL, ce qui aide à séparer les préoccupations.
Je comprends que mon approche n'est pas correcte, mais elle est propre, je recherche une approche correcte + propre. Je ne sais pas pourquoi je reçois un vote défavorable alors que je demande une solution correcte. Comment puis-je le faire plus propre au lieu de db.Func1 (), db.Func2 (), etc. alors que chacun d'eux retourne des structures différentes ... comment puis-je réaliser quelque chose comme db.Obj1.Func1 (), db.Obj2. Func2 ()? (chacun de Func1 et Func2 renvoie des structures différentes de la base de données)
Vous pouvez utiliser un objet DBAL différent pour chaque type d'objet avec lequel vous souhaitez travailler.
ok, alors FooStore ou BarStore devraient être passés en tant que récepteur à leurs fonctions? correct?
FooStore et BarStore seraient des structures avec des méthodes d'interaction avec la base de données. Vous ne «passez» rien comme récepteur explicitement lorsque vous appelez une méthode dans Go.
Je pense qu'il me manque quelque chose !. Si aucun récepteur, comment puis-je avoir FooStore.Func1 ()? Ne faites-vous pas référence à quelque chose comme ça? golangtutorials.blogspot.com/2011/06/methods-on-structs. html
Les méthodes ont des récepteurs, vous ne les «passez» pas. Cet article pourrait vous être utile: alexedwards.net/blog/organising-database-access a> la section "Utiliser une interface" est essentiellement ce que je propose ici: une ou plusieurs classes chargées d'interagir avec la base de données.
Excellente question. Habituellement, quelle que soit la langue utilisée dans le projet, j'essaie d'appliquer le modèle MVC, dans lequel la méthode de cette base de données doit être séparée des modèles.
Je créerais un autre fichier appelé your_model_controller.go
et donnerais toutes les responsabilités de persistance à ce fichier
En général, le DBAL est considéré comme faisant partie du modèle dans le modèle MVC, mais il doit toujours être séparé des objets du modèle eux-mêmes. Le code de base de données dans les gestionnaires de requêtes est l'un des problèmes que MVC cherche à résoudre. Il en dit autant dans la page à laquelle vous avez lié.
J'aime la méthode de Ben Johnson expliquée ici https://medium.com/@ benbjohnson / standard-package-layout-7cdbc8391fc1
L'idée est d'avoir vos objets de domaine dans votre package de base, puis envelopper la base de données / nosql / redis / quelle que soit la couche de persistance en tant que services dans des sous-packages. Quand je fais ça, je me retrouve avec ce genre de chose:
cela vous permet de transmettre MyObjectService dans votre logique métier et vous ne vous souciez même pas de la manière dont la persistance se produit réellement. Une structure concrète mysql.MyObjectService a tendance à contenir des éléments comme un pointeur vers la connexion à la base de données. Un package de cache peut stocker des éléments en mémoire. Etc.
Donc, en d'autres termes, ne basez pas votre structure servilement sur la base de données, en vous enfermant dans une implémentation particulière. Séparez la logique du code métier de l'acte de persistance et utilisez des interfaces pour permettre à un modèle cohérent d'accéder aux données persistantes.
Une chose que je n'essaie généralement pas de faire moi-même est d'utiliser ou d'écrire n'importe quel type d'ORM réel et dynamique. Dans mon travail, tous ces services utilisent du SQL écrit à la main, par exemple, plutôt que de faire de la réflexion ou de la génération de code. Votre kilométrage peut varier.