Ранее сегодня пользователь с идентификатором / aliezsid сделал сообщение на Reddit с просьбой о проверке кода. Мне нужно было чем-то заняться во время перерыва на кофе, поэтому я подумал, почему бы и нет.

Алиезсид просит провести обзор кода для своего нового проекта commitlog. Я посетил его GitHub, чтобы узнать, о чем был проект, кажется, это инструмент для создания журналов изменений на основе истории коммитов для репозитория на GitHub. Мне очень нравится его идея, поэтому я решил сделать небольшой обзор.
О его проектах можно прочитать здесь.

Разведка

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

README.md указывает, что эта библиотека находится в интенсивной разработке, и сообщает об отсутствии тестов, которые можно было бы считать нестабильными. Второе, что я обычно делаю во время проверки кода, - это проверяю тесты, чтобы увидеть примеры использования. Тесты - это не только отличная вещь, чтобы убедиться, что что-то не сломается, но я нахожу их полезными и для понимания использования библиотек.

Но, как написал сам Алиезид, он знает, что на данный момент тестов нет, так что оставьте это.

Анализ кода

Следующее, что я делаю, это беру код.

mkdir codereview-gitcommit
cd codereview-gitcommit
git init
git pull https://github.com/barelyhuman/commitlog

Давайте откроем main.go. Я собираюсь посмотреть, что происходит в программе, и пройти ее шаг за шагом.

Первое, что мы видим, это то, что он ожидает входной аргумент программы. Затем он воспользуется go-git, чтобы открыть репозиторий GitHub. Если мы проверим, что делает PlainOpen, мы увидим следующее.

Итак, программа ожидает путь к репозиторию GitHub, а не URL-адрес. Это полезно знать, поэтому давайте немного изменим это, чтобы было понятнее.
Давайте воспользуемся пакетом golang Flag, чтобы помочь нам. Причина, по которой я хочу использовать флаги, заключается в том, что они помогают нам генерировать пользовательскую ошибку, а также более масштабируемы.

Теперь пользователям легче понять, как его использовать, при выполнении программы мы теперь увидим

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

Теперь этот код изолирован от основного пакета и довольно неясно, что происходит. Я бы хотел немного разобрать это на части. Я собираюсь создать новую структуру под названием Repository, которая будет содержать эти функции. Это значительно упростит тестирование, а код станет более чистым и масштабируемым.

Следующее, что он делает, это извлекает из репозитория последние теги. Это делается путем извлечения последнего тега с помощью пакета utils. Фактически, сейчас мы можем удалить пакет utils и вставить его в функцию в структуре репозитория. Поскольку utils содержит только эту одну функцию, я считаю более подходящим вставить логику в нашу структуру репозитория.

Затем он проверяет, совпадает ли latestTag с HEAD репозитория.

Я также хотел бы удалить проверку tillLatest и вместо этого сделать ее собственной функцией. Это сделано для того, чтобы его было легче тестировать, а также легче повторно использовать в случае роста пакета. Он также повторно использует тот же самый код в функции isCommitToNearest позже, в строке 116, каждый раз, когда мы используем код более одного раза, разбиваем его на отдельную функцию, чтобы избежать дублирования кода. Нам нужно увидеть, что требуется в обоих случаях, и убедиться, что мы можем использовать нашу новую функцию в обоих случаях.

isCommitToNearestTag также содержит небольшую ошибку. Он дважды проверяет ошибку и использует log.Fatal. Вторая проверка ошибок фактически никогда не доступна, поскольку первая проверка ошибок будет отменена с момента использования log.Fatal. Кажется, что логический флаг tillLatest используется для принудительной проверки на latestTag.Hash (). Таким образом, код фактически выполнит эту проверку один раз, только чтобы принудительно выполнить ее позже. Это то, что мы можем удалить, чтобы это выполнялось только один раз, не потому, что у нас есть проблема с оптимизацией, но нет причин для повторного запуска кода.

Я собираюсь полностью удалить код, который выполняет первую проверку до последней версии, на самом деле он не имеет никакого смысла (строки 58–79). И при его удалении мы заметим, что можем полностью удалить получение последнего тега. Оставим это на потом.

Наша новая функция будет называться IsCommitLatest и будет принимать указатель на object.Commit.

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

Это также очень маленький пакет, такой как был утилит. Фактически, это одна структура с одной прикрепленной функцией.

Итак, начнем со структуры. Очень редко можно увидеть в структурах имена с заглавной буквы, последнее место, где я видел, что это регулярно используется, было в Java. Может наш автор старая акула java? В этом нет ничего плохого, мне это нравится, но я знаю, что не всем нравится. Оставим так, как хочет автор.

Функция GenerateMarkDown просматривает длину всех своих фрагментов и создает на их основе строки вместе с небольшим заголовком. Он использует обычную конкатенацию строк (oldString + = hello + world). В этом случае это работает, потому что строки довольно простые, но я бы действительно рекомендовал использовать String.Builder. Вы можете прочитать про эффективные струны.

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

И теперь GenerateMarkdown будет выглядеть так:

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

Я также рекомендую, чтобы основная функция была чистой и удобной для просмотра, поэтому давайте также создадим файл с именем repository.go. Весь код, относящийся к структуре репозитория, помещается туда.

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

Мне сложно тестировать то, что находится в основном. Я рекомендую всегда разбирать вещи, чтобы их было легче найти в тестах.

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

Вот как выглядит наш финальный main.

Наконец, он упоминает, что в настоящее время создает собственный журнал изменений в действиях git. Итак, давайте изменим .github / workflows / create-binaries.yml, поскольку мы изменили способ выполнения программы. Помните, мы добавили флаг -path?

Line 30: ./commitlog . > CHANGELOG.txt
// Replaced with
.commitlog -path=. > CHANGELOG.txt

Так! Я закончил.

Надеюсь, вам понравился мой небольшой обзор кода и мой процесс его создания.

Запрос на PR отправлен.