
una palabra persa que significa "pequeño" o "li'l". A menudo se usa para referirse a una chica al coquetear (con el significado, niña)
Diccionario urbano
Bienvenido a KooChooloo : un proyecto elegante y práctico diseñado para racionalizar el desarrollo de aplicaciones de Golang. Con una arquitectura bien organizada, KooChooloo integra características vitales como el manejo de bases de datos y la gestión de la configuración, ejemplificando las mejores prácticas en la construcción de aplicaciones de descanso robustas con GO.
init : evita los globales y las complejidades de las funciones init para mantener las cosas simples. Aprovechando fx Como nuestro marco de inyección de dependencia, Koochooloo ofrece:
fx en las pruebas con la misma facilidad que en la producción.Embárcate en un viaje con Koochooloo y redefine tu enfoque para crear aplicaciones tranquilas en GO. Ya sea que esté expandiendo su conjunto de habilidades o construyendo una base sólida para aplicaciones complejas, Koochooloo es su socio en un diseño de software eficiente, limpio y escalable.
En primer lugar, el paquete cmd contiene los binarios de este proyecto con el uso de Cobra. Es bueno tener un simple binarios para tareas como migraciones de bases de datos que se pueden ejecutar en la fase de inicio del proyecto. Cada binario tiene su main.go en su paquete y se registra con una función Register . En la root.go Se llaman a las funciones Register cmd los subcom-comandos. Aquí hay un ejemplo para la función de registro:
// 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 ()
},
},
)
} Nuevamente, cada comando registra su bandera por sí solo, por lo que tenemos separación de otros comandos. A veces necesitamos tener banderas compartidas entre comandos, entonces es mejor tenerlos en la configuración. Para el caso posterior, koanf puede ayudarnos con la estructura como se muestra a continuación:
func Register ( fs * pflag. FlagSet ) {
fs . StringP (
"url" , "u" ,
nats . DefaultURL ,
fmt . Sprintf ( "nats server url(s) e.g. %s" , nats . DefaultURL ),
)
}Esta función registra los indicadores compartidos, y luego cargamos la configuración en función de ellos con la siguiente función:
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 parte principal de cada aplicación es su configuración. Hay muchas maneras de tener configuración en el proyecto desde el archivo de configuración hasta las variables de entorno. Koanf los tiene a todos en un paquete único. Los puntos principales aquí son:
config y se lo pasará en su inicio.PS KOANF es mucho mejor que Viper para tener una configuración escrita. Por configuración escrita, quiero decir que tiene una estructura definida para la configuración y luego cargue la configuración de muchas fuentes en ella.
Para instalar Koanf, puede usar los siguientes comandos:
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 Los paquetes y servicios que se definen en el paquete domain solo usan otros paquetes desde domain sin usar paquetes de terceros. Estos paquetes y servicios especifican los conceptos de dominio central.
Hay un paquete db que es responsable de conectarse a la base de datos. Este paquete utiliza la configuración de la base de datos que se define en el módulo config y crea una instancia de base de datos. Es una buena idea hacer ping a su base de datos aquí para tener completamente confiado en la instancia de su base de datos antes de seguir adelante. También por tener una información en Database Health, puede llamar a esta función de ping periódicamente e informar su resultado con métricas (que no hice aquí).
Los modelos de proyecto se definen en el paquete model . Estos modelos se usan internamente, pero se pueden usar en el paquete response o request . No hay estructura para comunicarse con la base de datos en este paquete.
Los repositorios son responsables de la commnunicación con la base de datos para almacenar o recuperar modelos. Los repositorios son interface y hay una implementación concreta y burlada para ellos. La implementación concreta se usa en el código principal y se usa simulado para las pruebas. Tenga en cuenta que las pruebas de repositorios son delicadas y se realizan con la base de datos real.
El controlador HTTP se define en el paquete handler . Echo es un increíble marco HTTP que tiene algo que necesitas. Cada controlador tiene su estructura con un método Register que registra su ruta en un grupo de ruta dado. Route Group es un concepto del marco Echo para agrupar rutas bajo una ruta de los padres específica. Cada manejador tiene lo que necesita en su estructura. La estructura del controlador se crea en main.go y luego registra en su grupo.
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 )
} Todas las métricas se recopilan utilizando Prometheus basado en la televisión abierta. Cada paquete tiene su metric.go que define una estructura contiene las métricas y tiene métodos para cambiarlas. Para migrar de Prometeo a otro servicio, solo necesita cambiar telemetry . Las métricas no son globales y crearon para cada instancia por separado gracias al diseño de telemetría abierta. Para tener un mejor controlador en el punto final de métricas, hay otro servidor HTTP que se define en el paquete de telemetry para el monitoreo.
Es bueno tener paquetes separados para solicitudes y respuestas. Estos paquetes también contienen lógica de validación. Una de las buenas pakcages de validación en GO es Ozzo-Validator. Después de proporcionar un método de validación, después de obtener una solicitud, puede validarlo con su método con facilidad.
Registro de uno la parte más importante de la aplicación. Al principio no hay necesidad de tener algo más que simples registros de stdout. Pero en el futuro necesita que se registre y los registra en un sistema de agregación porque cuando su sistema crezca detectar problemas a partir de registros de texto será posible.
ZAP es uno del mejor registrador para el registro de la estructura. zap lo obliga a pasarlo al módulo de su hijo y también nombra registradores con el método Named . Al usar el Logger con nombre, puede encontrar fácilmente los registros de módulos en su agregador de registro.
Este proyecto solo requiere MongoDB, y puede ejecutarlo con docker-compose proporcionado.
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