«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Практический пример общих библиотек в монорепозитории

Практический пример общих библиотек в монорепозитории

Опубликовано 9 ноября 2024 г.
Просматривать:265

A practical example of shared libraries in a monorepo

Одним из самых мощных аспектов работы в монорепозитории является возможность совместного использования кода между пакетами/командами/иерархиями. В этом посте я попытаюсь объяснить очень простой сценарий из реальной жизни

Пример сценария

Представьте, что вы хотите разработать библиотеку, отображающую размеры файлов в мегабайтах, которая, по вашему мнению, может быть полезна для других частей вашего монорепозитория. Библиотека принимает размер как целое число (например: 2048 байт) и может возвращать гуманизированную строку (например: 2 МБ). Чтобы добавить некоторую гарантию качества, мы также напишем для него тест.

Как Bazel позволяет совместно использовать код?

Из приведенного выше сценария мы понимаем, что нам нужно разработать эту функцию как общую библиотеку, которую затем можно будет импортировать в другой пакет для использования. Bazel делает это чрезвычайно простым, позволяя нам определить функцию в библиотеке и экспортировать ее в другие службы, которым она понадобится. Как объяснялось в моем предыдущем посте, ссылка на который приведена в конце этого поста, мы также можем контролировать, каким другим библиотекам также можно разрешить импортировать его для использования.

Давайте займемся кодированием

Для организации кода у нас будет каталог библиотек в корне нашего рабочего пространства с дочерним каталогом с именем humanize_filesize, в котором мы будем писать код нашей библиотеки.

Давайте напишем очень простой код Go в 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"
}

Этот код просто принимает int32 в качестве входных данных и возвращает вычисленную читаемую строку в мегабайтах с точностью до 4 десятичных знаков.

Эта функция определенно не является всеобъемлющей и ее определенно можно улучшить, но это не является целью данного упражнения.

Также убедитесь, что наша логика работает так, как задумано. Мы добавим очень элементарный тест вместе с нашим кодом go в файл с именем 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
}

Очень простой тест с базовыми тестами на nil, int32 и 0 в качестве входных данных

Теперь самое интересное: как экспортировать эту функцию, чтобы ее можно было импортировать в другие пакеты или службы. Здесь нам нужно определить файл 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"],
)

Здесь мы определяем два основных правила. Один для реальной библиотеки и один для тестового файла, который мы написали.

go_library определяет, что целевой объект humanize_filesize использует humanize_filesize.go в качестве одного из своих источников, который можно импортировать по пути, указанному в importpath, и он доступен публично в рабочей области для импорта другими пакетами. В следующем посте мы узнаем, как управлять видимостью.

Go_test определяет цель теста, в которую встраивается код из выходных данных go_library.

На этом этапе мы сможем протестировать библиотеку, запустив наш набор тестов следующим образом

bazel build //... && bazel run //libraries/humanize_filesize:humanize_filesize_test

Вы должны увидеть следующие результаты теста, указывающие на то, что все тесты пройдены.

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

? Вауу!!! ? Теперь мы знаем, что наша библиотека работает как задумано.

Теперь давайте использовать эту библиотеку в сервисе service1 в каталоге сервисов, который мы создадим в корне рабочей области, со следующим кодом go и файлом BUILD.bazel.

service1.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"],
)

Код go довольно прост: он импортирует нашу библиотеку, которую мы объявили ранее, использует функцию GetHumanizedFilesize из нашей библиотеки, передает случайное целочисленное значение и печатает выходные данные.

Теперь при выполнении bazel build //services/service1 , bazel разрешит все зависимости для нашей цели, включая разработанную нами библиотеку, и соберет их.

service1 теперь можно выполнить с помощью bazel run //services/service1, поскольку у нас определена только одна двоичная цель. Если у вас есть более одной двоичной цели, например: serviceX, вы можете выполнить ее с помощью bazel run //services/service1:serviceX. По умолчанию, если цель не указана, bazel всегда будет пытаться найти двоичную цель с тем же именем, что и каталог, и запустить ее.

Итак... вот и все. Мы создали вашу первую общую библиотеку, которую могут использовать другие части нашего монорепозитория.

Весь код этого примера можно найти по адресу https://github.com/nixclix/basil/pull/3/commits/61c673b8757860bd5e60eb2ab6c35f3f4da78c87

Если вам нравится содержание этого поста, поделитесь им. Также, пожалуйста, подпишитесь и оставляйте комментарии о том, что вы думаете об этом посте, и есть ли что-то, что вы хотели бы, чтобы я улучшил.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/nikhildev/a-practical-example-of-shared-libraries-in-a-monorepo-2548?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с [email protected] удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3