
un mot persan qui signifie "petit" ou "li'l". Il est souvent utilisé pour se référer à une fille lors du flirt (avec la signification, une fille))
Dictionnaire urbain
Bienvenue à Koochooloo : un projet élégant et pratique conçu pour rationaliser le développement des applications de Golang. Bénéficiant d'une architecture bien organisée, Koochooloo intègre des fonctionnalités vitales telles que la gestion de la base de données et la gestion de la configuration, illustrant les meilleures pratiques pour construire des applications de repos robustes avec GO.
init : évite les globaux et les complexités des fonctions init pour garder les choses simples. Tirant l'extraction fx comme notre cadre d'injection de dépendance, Koochooloo offre:
fx dans les tests avec la même facilité que dans la production.Embarquez dans un voyage avec Koochooloo et redéfinissez votre approche pour créer des applications reposantes en Go. Que vous élargiez vos compétences ou que vous créiez une base solide pour des applications complexes, Koochooloo est votre partenaire dans une conception de logiciels efficace, propre et évolutive.
Tout d'abord, le package cmd contient les binaires de ce projet avec l'utilisation de Cobra. Il est bon d'avoir des binaires simples pour des tâches telles que les migrations de base de données qui peuvent être exécutées sur la phase d'initiation du projet. Chaque binaire a son main.go dans son package et s'inscrit avec une fonction Register . Dans le root.go de cmd ces fonctions Register des sous-communs sont appelées. Voici un exemple de fonction de registre:
// Register server command.
func Register ( root * cobra. Command ) {
root . AddCommand (
& cobra. Command {
Use : "server" ,
Short : "Run server to serve the requests" ,
Run : func ( _ * cobra. Command , _ [] string ) {
fx . New (
fx . Provide ( config . Provide ),
fx . Invoke ( main ),
). Run ()
},
},
)
} Encore une fois, chaque commande enregistre son drapeau par lui-même, nous avons donc la séparation des autres commandes. Parfois, nous devons avoir des drapeaux partagés entre les commandes, alors il vaut mieux les avoir dans la configuration. Pour le dernier cas, koanf peut nous aider avec la structure comme ci-dessous:
func Register ( fs * pflag. FlagSet ) {
fs . StringP (
"url" , "u" ,
nats . DefaultURL ,
fmt . Sprintf ( "nats server url(s) e.g. %s" , nats . DefaultURL ),
)
}Cette fonction regarde les indicateurs partagés, puis nous chargeons la configuration en fonction d'eux avec la fonction suivante:
k := koanf . New ( "." )
if err := k . Load ( posflag . Provider ( fs , "." , k ), nil ); err != nil {
log . Errorf ( "error loading config.yml: %s" , err )
}
if err := k . Unmarshal ( "" , & instance ); err != nil {
log . Fatalf ( "error unmarshalling config: %s" , err )
}La partie principale de chaque application est sa configuration. Il existe de nombreuses façons d'avoir une configuration dans le projet du fichier de configuration aux variables d'environnement. Koanf les a tous dans un beau paquet. Les principaux points ici sont:
config et il lui passera dans son initiation.PS Koanf est bien meilleur que Viper pour avoir tapé la configuration. Par configuration dactylographiée, je veux dire que vous avez une structure définie pour la configuration, puis chargez la configuration à partir de nombreuses sources.
Pour l'installation de Koanf, vous pouvez utiliser les commandes suivantes:
go get -u github.com/knadh/koanf/v2
go get -u github.com/knadh/koanf/providers/file
go get -u github.com/knadh/koanf/providers/env
go get -u github.com/knadh/koanf/providers/structs
go get -u github.com/knadh/koanf/parsers/toml Les packages et services définis dans le package domain n'utilisent que d'autres packages à partir domain sans utiliser de packages tiers. Ces packages et services spécifient les concepts de domaine de base.
Il existe un package db responsable de la connexion à la base de données. Ce package utilise la configuration de la base de données définie dans le module config et créent une instance de base de données. C'est une bonne idée de faire un cliquetis sur votre base de données ici pour avoir pleinement confiant votre instance de base de données avant d'aller de l'avant. Aussi pour avoir un aperçu de la santé de la base de données, vous pouvez appeler périodiquement cette fonction de ping et signaler son résultat avec des mesures (ce que je n'ai pas fait ici).
Les modèles de projet sont définis dans le package model . Ces modèles sont utilisés en interne mais peuvent être utilisés dans le package response ou request . Il n'y a pas de structure pour communiquer avec la base de données dans ce package.
Les référentiels sont responsables de la communication avec la base de données pour stocker ou récupérer des modèles. Les référentiels sont interface et il y a une implémentation en béton et moquette pour eux. L'implémentation du béton est utilisée dans le code principal et une moquette est utilisée pour les tests. Veuillez noter que les tests de référentiels sont délicats et sont effectués avec une base de données réelle.
Le gestionnaire HTTP est défini dans le package handler . Echo est un framework HTTP génial qui a besoin de tous les besoins. Chaque gestionnaire a sa structure avec une méthode Register qui enregistre sa route vers un groupe d'itinéraire donné. Le groupe de routes est un concept de Framework Echo pour le regroupement des itinéraires sous un chemin parent spécifique. Chaque gestionnaire a ce dont il a besoin dans sa structure. La structure du gestionnaire est créée dans main.go puis s'inscrivez-vous sur leur groupe.
type Healthz struct {}
// Handle shows server is up and running.
func ( h Healthz ) Handle ( c echo. Context ) error {
return c . NoContent ( http . StatusNoContent )
}
// Register registers the routes of healthz handler on given echo group.
func ( h Healthz ) Register ( g * echo. Group ) {
g . GET ( "/healthz" , h . Handle )
} Toutes les métriques sont rassemblées à l'aide de Prometheus en fonction de la télémétrie ouverte. Chaque package a sa metric.go qui définit une structure contient les mesures et a des méthodes pour les modifier. Pour migrer de Prometheus vers un autre service, vous avez juste besoin de changer telemetry . Les métriques ne sont pas mondiales et ils ont créé pour chaque instance séparément grâce à la conception de la télémétrie ouverte. Pour avoir un meilleur contrôleur sur Metrics Endpoint, il existe un autre serveur HTTP défini dans le package de telemetry pour la surveillance.
Il est bon d'avoir des packages séparés pour les demandes et les réponses. Ces packages contiennent également une logique de validation. L'un des bons pakcages de validation de GO est Ozzo-validator. Après avoir fourni une méthode Validate, après avoir obtenu la demande, vous pouvez le valider avec sa méthode avec facilité.
Enregistrant une partie la plus importante de l'application. Au début, il n'est pas nécessaire d'avoir quelque chose de plus que de simples journaux stdout. Mais à l'avenir, vous devez vous installer des journaux et les expédier dans un système d'agrégation, car lorsque votre système grandit les problèmes de détection à partir de journaux de texte seront invalides.
ZAP est l'un des meilleurs enregistreurs pour la journalisation de la structure. zap vous oblige à le transmettre dans votre module enfant et vous nommez également les journalistes avec la méthode Named . En utilisant le logger nommé, vous pouvez facilement trouver vos journaux de modules dans votre agrégateur de journaux.
Ce projet ne nécessite que MongoDB, et vous pouvez l'exécuter avec docker-compose fourni.
cd deployments && docker-compose up -d
cd cmd/koochooloo/ && go build && ./koochooloocurl -X POST -d ' {"url": "https://elahe-dastan.github.io"} ' -H ' Content-Type: application/json ' 127.0.0.1:1378/api/urls
curl -L 127.0.0.1:1378/api/CKaniA checks.....................: 99.83% ✓ 2995 ✗ 5
data_received..............: 2.0 MB 64 kB/s
data_sent..................: 521 kB 17 kB/s
group_duration.............: avg=649.18ms min=153.18µs med=265.45ms max=30.95s p(90)=1.61s p(95)=2.06s
http_req_blocked...........: avg=14.12ms min=0s med=3µs max=1.65s p(90)=13µs p(95)=147.04µs
http_req_connecting........: avg=6.23ms min=0s med=0s max=1.36s p(90)=0s p(95)=0s
http_req_duration..........: avg=272.98ms min=0s med=127.99ms max=4.81s p(90)=830.93ms p(95)=1.29s
http_req_receiving.........: avg=125.23µs min=0s med=60µs max=11.21ms p(90)=228µs p(95)=363µs
http_req_sending...........: avg=50.78µs min=0s med=22µs max=7.28ms p(90)=86µs p(95)=138µs
http_req_tls_handshaking...: avg=7.86ms min=0s med=0s max=653.63ms p(90)=0s p(95)=0s
http_req_waiting...........: avg=272.8ms min=0s med=127.71ms max=4.81s p(90)=830.87ms p(95)=1.29s
http_reqs..................: 4000 129.093962/s
iteration_duration.........: avg=1.29s min=142.34ms med=1.04s max=30.97s p(90)=2.18s p(95)=2.64s
iterations.................: 1000 32.273491/s
vus........................: 100 min=100 max=100
vus_max....................: 100 min=100 max=100