Mientras desarrollo, me he estado encontrando con problemas cada vez más recurrentes, y uno de ellos es la reutilización de módulos entre proyectos. Esto es algo que se puede aprovechar muy bien en Go, ya que es un lenguaje diseñado para trabajar de manera modular.
En Go, un paquete es una forma de organizar y reutilizar código. Un paquete puede contener uno o más archivos fuente de Go y puede ser importado en otros programas de Go para usar sus funciones, variables y tipos exportados. Es un concepto fundamental en la programación de Go y ayuda a crear código modular y reutilizable.
Para esto, plantearemos la siguiente situación:
Trabajamos en un equipo de más de 20 desarrolladores y nuestros proyectos necesitan una forma más homogénea de manejar los Logs, pero la naturaleza de nuestros proyectos nos obliga a ofuscar información sensible en nuestros Logs.
Este es un caso perfecto para aplicar el uso de paquetes privados. Podríamos proceder de la siguiente forma:
Asignamos el proyecto del registro a un desarrollador específico (el que tenga más experiencia en el tema).
El equipo de desarrolladores llega a un acuerdo para modelar la interfaz del Logger.
Comienza la fase de desarrollo de nuestro proyecto de Logging. Ahora pondremos un ejemplo de cómo podría verse nuestro paquete de Go.
Como pueden apreciar, nuestro paquete cuenta con dos subpaquetes: uno llamado Logger en la raíz del proyecto y otro llamado Obfuscator dentro de la carpeta Internal.
Tip 💡: Todo el código dentro de la carpeta internal hace que sea imposible de importar. De esta manera, podemos mantener funcionalidades ocultas para la exportación en otros proyectos donde se usará el paquete.
Ahora desarrollamos nuestros dos paquetes (lo haré lo más breve y simple posible ya que el enfoque de este artículo no es enseñarles a hacer un logger)
~package logger import ( "fmt" "private-packages-go/internal/obfuscator" ) type Logger interface { Debug(msg string) } type CompanyLogger struct { obfuscator *obfuscator.Obfuscator } func NewCompanyLogger() *CompanyLogger { o := obfuscator.NewObfuscator() return &CompanyLogger{ obfuscator: o, } } func (c *CompanyLogger) Debug(msg string) { nMsg := c.obfuscator.Obfuscate(msg) fmt.Println(nMsg) }
Si pueden notar algo, es que el ofuscador se inicializa y asigna dentro del "constructor" del logger, y no se puede asignar desde el "constructor". Esto permite que nadie pueda cambiar la lógica de qué cosa se oculta o no.
Si tu paquete necesita alguna otra parte de tu proyecto, como un ofuscador personalizado, lo ideal es pasar una interfaz en el constructor que los ofuscadores deban cumplir, en lugar de una implementación.
En nuestro caso, el ofuscador será único y controlado por el paquete de Logging.
Es hora de cargar nuestro paquete en un repositorio privado en GitHub y comenzar a usarlo en otros proyectos.
Para esto necesitamos tener configurado nuestra SSH Key de Github en nuestra computadora.
Cambiarémos el URL de Git usando el siguiente comando:
~git config --global url.git@github.com:.insteadOf https://github.com/
Para estar seguros revisarémos si la configuración se cambio de forma correcta.
~cat ~/.gitconfig
$ [url "git@github.com:"] $ insteadOf = https://github.com/
Agregamos el módulo en la variable GOPRIVATE.
~export GOPRIVATE=github.com/private/repo
Ahora simplemente usamos la herramienta get
de Go para traer el paquete a nuestro proyecto.
~go get github.com/private/repo
Momento de usar nuestro paquete de Go.
~package main import "github.com/solrac97gr/private-packages-go/logger" type Service struct { logger logger.Logger } func NewService(l logger.Logger) *Service { return &Service{ logger: l, } } func (s *Service) DoSomething() { msg := "I am secret 🤫, I am not a secret 😎" s.logger.Debug(msg) } func main() { lggr := logger.NewCompanyLogger() srv := NewService(lggr) srv.DoSomething() }
$ I am not a secret 😎
Podemos notar que estamos usando la interfaz y no la implementación, lo que nos permitirá usar mocks en el futuro para mejorar las pruebas. Además, debemos considerar que los paquetes deben tener sus propias pruebas, lo cual no es opcional.
En conclusión, la reutilización de módulos entre proyectos es un problema común en el desarrollo de software, pero en Go, este problema puede ser abordado de manera efectiva gracias a su diseño modular. Al aprovechar los paquetes privados, podemos compartir código de manera más eficiente y mejorar la reutilización de módulos entre proyectos. De esta manera, podemos mejorar la productividad y reducir el tiempo de desarrollo en nuestra empresa.