Um dos aspectos mais poderosos de trabalhar em um monorepo é a capacidade de compartilhar código entre pacotes/equipes/hierarquias. Neste post tentarei explicar um cenário muito simples do mundo real
Imagine que você deseja desenvolver uma biblioteca para mostrar os tamanhos dos arquivos em megabytes que você acha que podem ser úteis para outras partes do seu monorepo. A biblioteca aceita o tamanho como Inteiro (ex: 2048 bytes) e pode retornar uma string humanizada (ex: 2 MB). Para adicionar alguma garantia de qualidade, também escreveremos um teste para o mesmo.
A partir do cenário acima, estamos cientes de que precisamos desenvolver esta função como uma biblioteca compartilhada que então será importada por outro pacote para uso. O Bazel torna isso extremamente simples, permitindo-nos definir a função em uma biblioteca e exportá-la para outros serviços que necessitarão dela. Conforme explicado em minha postagem anterior com link na parte inferior desta postagem, também podemos controlar quais outras bibliotecas podem importá-lo para uso.
Para fins de organização do código, teremos um diretório de bibliotecas na raiz do nosso espaço de trabalho com um diretório filho chamado humanize_filesize, onde escreveremos o código da nossa biblioteca.
Vamos escrever um código Go bem elementar em humanize_filesize.go
package humanize_filesize import "fmt" // GetHumanizedFilesize takes size_in_bytes as an int32 pointer and returns the size in megabytes. func GetHumanizedFilesize(size_in_bytes *int32) string { if size_in_bytes != nil { size_in_megabytes := float64(*size_in_bytes) / (1024 * 1024) return fmt.Sprintf("%.4f MB", size_in_megabytes) } return "0 MB" }
Este código simplesmente pega um int32 como entrada e retorna uma string de megabytes legível computada com precisão de 4 decimais
Esta função definitivamente não é abrangente e pode definitivamente ser melhorada, mas esse não é o objetivo deste exercício.
Afirme também que nossa lógica está funcionando conforme o esperado. Adicionaremos um teste muito elementar junto com nosso código go em um arquivo chamado humanize_filesize_test.go
package humanize_filesize import ( "testing" ) func TestHumanizeFilesize(t *testing.T) { tests := []struct { name string size_in_bytes *int32 expected string }{ { name: "nil bytes", size_in_bytes: nil, expected: "0 MB", }, { name: "2048 bytes", size_in_bytes: int32Ptr(2048), expected: "0.0020 MB", }, { name: "0 bytes", size_in_bytes: int32Ptr(0), expected: "0.0000 MB", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetHumanizedFilesize(tt.size_in_bytes) if result != tt.expected { t.Errorf("expected %s, got %s", tt.expected, result) } }) } } func int32Ptr(n int32) *int32 { return &n }
Um teste muito simples com testes básicos para nil, int32 e 0 como entradas
Agora vem a parte interessante de como exportar esta função para que ela possa ser importada dentro de outros pacotes ou serviços. É aqui que temos que definir o arquivo BUILD.bazel.
load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "humanize_filesize", srcs = ["humanize_filesize.go"], importpath = "basil/libraries/humanize_filesize", visibility = ["//visibility:public"], ) go_test( name = "humanize_filesize_test", srcs = ["humanize_filesize_test.go"], embed = [":humanize_filesize"], )
Aqui estamos definindo duas regras principais. Um para a biblioteca real e outro para o arquivo de teste que escrevemos.
A go_library define que o destino humanize_filesize usa humanize_filesize.go como uma de suas fontes que pode ser importada pelo caminho especificado em importpath e é visível publicamente dentro do espaço de trabalho para outros pacotes serem importados. Aprenderemos como controlar a visibilidade em uma postagem futura.
O go_test define um alvo de teste que incorpora o código da saída de go_library.
Neste ponto, devemos ser capazes de testar a biblioteca executando nosso conjunto de testes da seguinte forma
bazel build //... && bazel run //libraries/humanize_filesize:humanize_filesize_test
Você poderá ver a saída do teste conforme a seguir, indicando que todos os testes foram aprovados.
INFO: Analyzed target //libraries/humanize_filesize:humanize_filesize_test (0 packages loaded, 0 targets configured). INFO: Found 1 target... Target //libraries/humanize_filesize:humanize_filesize_test up-to-date: bazel-bin/libraries/humanize_filesize/humanize_filesize_test_/humanize_filesize_test INFO: Elapsed time: 0.392s, Critical Path: 0.24s INFO: 5 processes: 1 internal, 4 darwin-sandbox. INFO: Build completed successfully, 5 total actions INFO: Running command line: external/bazel_tools/tools/test/test-setup.sh libraries/humanize_filesize/humanize_filesize_test_/humanize_filesize_test exec ${PAGER:-/usr/bin/less} "$0" || exit 1 Executing tests from //libraries/humanize_filesize:humanize_filesize_test ----------------------------------------------------------------------------- PASS
? Uau!!! ? Agora sabemos que nossa biblioteca está funcionando conforme esperado.
Agora vamos usar esta biblioteca em um serviço service1 dentro de um diretório de serviços que criaremos na raiz do espaço de trabalho com o seguinte código go e arquivo BUILD.bazel.
serviço1.go
package main import ( "basil/libraries/humanize_filesize" "fmt" "math/rand" ) func main() { v := rand.Int31n(1000000) fmt.Printf(`%d bytes = %s\n`, v, humanize_filesize.GetHumanizedFilesize(&v)) }
BUILD.bazel
load("@rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "service1_lib", srcs = ["service1.go"], importpath = "basil/services/service1", visibility = ["//visibility:private"], deps = ["//libraries/humanize_filesize"], ) go_binary( name = "service1", embed = [":service1_lib"], visibility = ["//visibility:public"], )
O código go é bastante simples, que importa nossa biblioteca que declaramos anteriormente e usa a função GetHumanizedFilesize de nossa biblioteca e passa um valor inteiro aleatório e imprime a saída.
Agora, quando executar bazel build //services/service1 , bazel resolverá todas as dependências de nosso destino, incluindo a biblioteca que desenvolvemos e as construirá.
service1 agora pode ser executado usando bazel run //services/service1, pois temos apenas um destino binário definido. Se você tiver mais de um alvo binário, por exemplo: serviceX, poderá executá-lo usando bazel run //services/service1:serviceX. Por padrão, ao não especificar um destino, o bazel sempre tentará encontrar um destino binário com o mesmo nome do diretório e executá-lo.
Então... aí está. Criamos sua primeira biblioteca compartilhada que pode ser usada por outras partes de nosso monorepo.
Todo o código deste exemplo pode ser encontrado em https://github.com/nixclix/basil/pull/3/commits/61c673b8757860bd5e60eb2ab6c35f3f4da78c87
Se você gostou do conteúdo deste post, sinta-se à vontade para compartilhá-lo. Além disso, inscreva-se e deixe comentários sobre o que você pensa sobre este post e se há coisas que você gostaria que eu melhorasse.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3