Разработка#

В этом документе собрана информация о разработке Trino.

  • Организация Trino

  • Руководство разработчика Trino

  • Стиль кода

  • Дополнительная настройка IDE

  • Сборка документации

  • Сборка Web UI

  • Релизы

Организация Trino#

Изучите информацию о разработке для всех проектов организации Trino:

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

Руководство разработчика Trino#

См. руководство разработчика Trino для сведений о SPI, реализации коннекторов и других плагинов, клиентском протоколе, написании тестов и других низкоуровневых деталях.

Стиль кода#

Мы рекомендуем использовать IntelliJ как IDE. Шаблон стиля кода для проекта находится в репозитории codestyle вместе с общими рекомендациями по программированию и Java.

Чтобы запустить checkstyle и другие проверки Maven перед открытием PR, выполните: ./mvnw validate

Кроме этого, соблюдайте следующие рекомендации.

Читаемость#

Цель правил стиля кода — поддерживать читаемость кода и эффективность разработчиков при работе с ним. Все правила стиля кода, описанные ниже, — хорошие ориентиры, но возможны исключительные ситуации, когда мы сознательно от них отступаем. Если читаемость и правило стиля кода противоречат друг другу, читаемость важнее.

Согласованность#

По возможности сохраняйте код согласованным с окружающим кодом.

Алфавитный порядок#

Сортируйте разделы в исходных файлах документации по алфавиту как в файлах содержания, так и в обычных файлах документации.

Используйте streams#

Когда это уместно, используйте Stream API. Однако помните, что реализация streams не отличается высокой производительностью, поэтому избегайте ее во внутренних циклах и других чувствительных к производительности участках.

Категоризируйте ошибки при выбрасывании исключений#

Категоризируйте ошибки при выбрасывании исключений. Например, TrinoException принимает код ошибки как аргумент: TrinoException(HIVE_TOO_MANY_OPEN_PARTITIONS). Такая категоризация позволяет создавать отчеты и отслеживать частоту разных сбоев.

Добавляйте заголовок лицензии#

Убедитесь, что все файлы имеют соответствующий заголовок лицензии; его можно сгенерировать командой mvn license:format.

Предпочитайте форматирование строк#

Рассмотрите использование форматирования строк в стиле printf с Java-классом Formatter: format("Session property %s is invalid: %s", name, value). Обратите внимание, что format() всегда должен быть статически импортирован. Иногда, если нужно только что-то добавить к строке, можно использовать оператор +. Избегайте format() и конкатенации на критичных к производительности участках кода.

Избегайте тернарного оператора#

Избегайте тернарного оператора, кроме тривиальных выражений.

Избегайте get в именах методов, если объект не должен быть Java bean#

В большинстве случаев заменяйте get более конкретным глаголом, описывающим действие метода, например find или fetch. Если более конкретного глагола нет или метод является getter, опустите get, потому что оно не помогает читателям и удлиняет имена методов.

Определяйте API класса и для private inner classes#

Рекомендуется объявлять члены в private inner classes как public, если они являются частью API класса.

Избегайте mocks#

Не используйте библиотеки mocking. Такие библиотеки поощряют тестирование конкретных последовательностей вызовов, взаимодействий и другого внутреннего поведения, что, по нашему мнению, приводит к хрупким тестам. Они также позволяют mock-ать сложные интерфейсы или классы, скрывая тот факт, что эти классы не являются легко тестируемыми. Мы предпочитаем писать mocks вручную: это вынуждает писать код в тестируемом стиле.

Используйте AssertJ#

Для сложных утверждений предпочитайте AssertJ.

Используйте Assertions из Airlift#

Для вещей, которые трудно выразить с помощью AssertJ, используйте класс Assertions из Airlift, если в нем есть подходящий вариант для вашего случая.

Избегайте var#

Использование var не рекомендуется.

Предпочитайте immutable collections из Guava#

Предпочитайте immutable collections из Guava вместо unmodifiable collections из JDK. Основная причина — детерминированная итерация.

Поддерживайте production-качество тестового кода#

Поддерживайте одинаковое качество production-кода и тестового кода.

Избегайте сокращений#

Избегайте сокращений, сленга и внутренних шуток, поскольку из-за них код сложнее понять людям, для которых английский не родной. Очень известные сокращения вроде max или min, а также уже широко используемые в кодовой базе сокращения вроде ttl, разрешены и приветствуются.

Избегайте default в исчерпывающих switch по enum#

Избегайте предложения default, когда оператор switch должен покрывать все значения enum. Обработка неизвестного варианта после оператора switch позволяет инструментам статического анализа кода, например проверке Error Prone MissingCasesInEnumSwitch, сообщить о проблеме, когда определение enum обновлено, а использующий его код — нет.

Vector API#

Можно безопасно предполагать, что JVM имеет включенный и доступный во время выполнения Vector API (JEP 508), но нельзя безопасно предполагать, что реализация Vector API будет быстрее эквивалентного скалярного кода на любом оборудовании, где запускается движок.

Разное CPU-оборудование может иметь резко отличающиеся характеристики производительности, поэтому важно использовать обнаружение аппаратных возможностей, чтобы определять, в каких сценариях векторизованный подход будет быстрее для каждой реализации. Векторизованный код следует тестировать на CPU AMD, ARM и Intel, чтобы убедиться, что преимущества сохраняются на каждой из этих платформ, прежде чем включать конкретный путь выполнения на каждой из них. Также обратите внимание, что CPU ARM могут существенно отличаться между поколениями оборудования, а также между Apple Silicon и CPU для дата-центров.

При добавлении реализаций, использующих Vector API, предпочитайте следующий подход, если особенности ситуации не требуют другого:

  • Предоставьте эквивалентную скалярную реализацию в коде, если ее еще нет.

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

  • Добавьте тесты, проверяющие совпадение поведения векторизованной и скалярной реализаций.

  • Включите micro-benchmarks, демонстрирующие преимущества производительности векторизованной реализации по сравнению со скалярной эквивалентной логикой. Убедитесь, что преимущества сохраняются для всех CPU-архитектур, на которых включается векторизованная реализация.

Поддерживайте pom.xml чистым и отсортированным#

В проекте есть несколько плагинов, поддерживающих чистоту pom.xml. Сборка может завершиться ошибкой, если:

  • зависимости или XML-элементы расположены в неправильном порядке;

  • общая структура pom.xml некорректна.

Многие такие ошибки можно исправить автоматически следующей командой: ./mvnw sortpom:sort

Дополнительная настройка IDE#

При разработке Trino в IntelliJ мы рекомендуем начать со всех стандартных инспекций с некоторыми изменениями.

Включите следующие инспекции:

  • Java | Class structure | Utility class is not 'final',

  • Java | Class structure | Utility class with 'public' constructor,

  • Java | Class structure | Utility class without 'private' constructor,

  • Java | Control flow issues | Redundant 'else' включая опцию Report when there are no more statements after the 'if' statement,

  • Java | Internationalization | Implicit platform default charset.

Отключите следующие инспекции:

  • Java | Abstraction issues | 'Optional' used as field or parameter type,

  • Java | Code style issues | Local variable or parameter can be 'final',

  • Java | Data flow | Boolean method is always inverted,

  • Java | Performance | Call to 'Arrays.asList()' with too few arguments.

Измените следующие инспекции:

  • Удалите com.google.common.annotations.Beta из JVM languages | Unstable API usage.

Включите errorprone (Error Prone Installation#IDEA):

  • Установите плагин Error Prone Compiler из marketplace.

  • Отметьте профиль errorprone-compiler на вкладке Maven.

Этого должно быть достаточно: IDEA должна автоматически скопировать параметры компилятора из POM в каждый модуль. Если это не сработает, можно сделать это вручную:

  • На вкладке Java Compiler выберите Javac with error-prone как компилятор.

  • Обновите Additional command line parameters и скопируйте туда содержимое compilerArgs из верхнеуровневого POM, кроме -Xplugin:ErrorProne.

    • Удалите XML-комментарии…

    • …кроме тех, которые обозначают проверки, падающие в IDEA; их следует “unwrap”.

  • Удалите все из списка Override compiler parameters per-module.

Обратите внимание: версия errorprone, используемая плагином IDEA, может быть старше версии, настроенной в pom.xml, и может потребоваться отключить некоторые проверки, которые еще не поддерживаются этой старой версией. Если сомневаетесь, всегда проверяйте полной сборкой Maven: ./mvnw clean install -DskipTests -Perrorprone-compiler.

Language injection в IDE#

Чтобы включить language injection внутри IntelliJ IDEA, некоторые элементы кода можно аннотировать аннотацией @org.intellij.lang.annotations.Language. Чтобы она была полезной, рекомендуем:

  • Задать SQL-диалект для всего проекта в Languages & Frameworks | SQL Dialects. Здесь неплохой выбор — “Generic SQL”.

  • Отключить инспекцию SQL | No data source configured.

  • При необходимости отключить инспекцию Language injection | Language mismatch.

Даже если IDE не поддерживает language injection, эта аннотация полезна для документирования намерения API. Учитывая это, рекомендуем аннотировать с помощью @Language:

  • Все параметры API, которые ожидают String с SQL-оператором или любым другим языком, например регулярными выражениями.

  • Локальные переменные, которые иначе IDE не смогла бы корректно распознать для language injection.

Сборка документации#

Информацию о написании и сборке документации можно найти в модуле docs.

Сборка Web UI#

Trino Web UI состоит из нескольких React-компонентов и написан на JSX и ES6. Этот исходный код компилируется и упаковывается в совместимый с браузерами JavaScript, который затем коммитится в исходный код Trino в папку dist. Для выполнения этих команд должны быть установлены Node.js и Yarn. Чтобы обновить эту папку после внесения изменений, просто выполните:

yarn --cwd core/trino-web-ui/src/main/resources/webapp/src install

Если зависимости JavaScript не изменились, то есть нет изменений в package.json, быстрее выполнить:

yarn --cwd core/trino-web-ui/src/main/resources/webapp/src run package

Чтобы упростить итерации, можно также запустить режим watch, который автоматически перекомпилирует код при обнаружении изменений в исходных файлах:

yarn --cwd core/trino-web-ui/src/main/resources/webapp/src run watch

Для быстрой итерации просто пересоберите проект в IntelliJ после завершения упаковки. Ресурсы проекта будут hot-reloaded, а изменения отразятся после обновления страницы в браузере.

Релизы#

Trino стремится к частым релизам, обычно раз в неделю. Это цель, но не гарантия: критические ошибки могут привести к переносу релиза или потребовать дополнительного экстренного релиза для исправления проблемы.

В начале каждого релизного цикла создается pull request (PR) с примечаниями к релизу, который поддерживается в течение недели и отслеживает все слитые PR, чтобы каждое изменение было корректно задокументировано и отмечено.

PR использует шаблон примечаний к релизу и следует рекомендациям по примечаниям к релизам, чтобы использовать и улучшать предложенные записи примечаний к релизу из слитых PR. При необходимости документация и уточнения для записей примечаний к релизу запрашиваются у мейнтейнера, выполнившего merge, и у контрибьютора.

См. примечания к релизу 455 в качестве примера.

Когда приходит время релиза, PR с примечаниями к релизу сливается и процесс запускается. Code freeze объявляется в Trino Slack в канале #releases, после чего мейнтейнер использует release scripts, чтобы обновить Trino до следующей версии.