Go и контроль качества проекта

А начну я с громкого заявления: Go – это один из самых лучших языков программирования для командной разработки на данный момент. И дело тут ни в простоте языка, ни в простоте инфраструктуры, хотя и эти пункты очень важны. Основная же причина для такого заявления кроется в инструментах для статического анализа кода. При этом я не знаю ни одного другого языка, который позволял бы провести такой дотошный статический анализ по всем направлениям, начиная от стилистики кода, заканчивая потенциально опасными конструкциями и обработкой ошибок.

Основная проблема в командной разработке – разнородность уровня и, как следствие, разное качество производимого командой кода. Ревью, безусловно, позволяют в той или иной степени сгладить последствия разнородности и даже подтянуть уровень разработчиков, но работают они не так хорошо как хотелось бы. Кому-то может быть лень, кто-то устал, кто-то не заметил и в репозитории оказывается нечто, которому там не место. Можно ли это хоть как-то исправить в C++? Нет, нельзя. Можно ли эту проблему минимизировать в Go? Довольно легко, что я вчера и сделал.

В Git есть замечательный механизм хуков, которые отрабатывают в зависимости от внутренних событий. Меня интересовал pre-commit хук, позволяющий заблокировать коммит по результату выполнения скрипта. Использование этого хука купе с Go Meta Linter, агрегатором линтеров для Go, позволяет автоматически заблокировать коммит до исправления ошибок.

#!/bin/sh

if ! [ -x "$(command -v gometalinter)" ]; then
echo 'Error: gometalinter is not installed. Please install it first and execute `gometalinter -i`'
exit 1
fi

lint_errors=$(gometalinter ./... --vendor -j 5)
if [[ $? != 0 ]]; then
echo 'Error: gometalinter checks had failed. Please execute `gometalinter ./... --vendor` first and fix ALL issues'
exit 1
fi

Дело остается за малым – поместить файл с хуком в директорию .git/hooks проекта, что я сделал при помощи нашего сборочного скрипта. Да, нам пришлось написать такой скрипт поверх стандартных Go команд типа go build так как есть пре- и пост- шаги которые необходимо предпринять в процессе сборки, а никакого CMake-подобного механизма в Go нет. Хотя, что уж тут, поверх CMake писать аналогичный скрипт тоже приходится.