Привет, на связи Марина и Катя (@lieutkat) — технические писатели Cloud.ru. За четыре года наша команда составила больше 30 правил по написанию технической документации и… прочувствовала на себе весь масштаб усилий на проверку и запоминание получившейся редакционной политики.
Год назад мы решили автоматизировать проверку этих правил. В статье расскажем, что из этого вышло, какие шишки мы набили по пути, а также детально рассмотрим линтер Vale, который стал нашей палочкой-выручалочкой.
«А» и «Б»: с чего начинали и куда хотели прийти
В нашей команде больше 20 технических писателей, мы используем подход docs-as-code — подробнее об этом рассказывали в другой статье. Исходные файлы пишем в разметке reStructuredText, собираем их в документационный портал с помощью Sphinx, а для сборки используем GitLab CI/CD.
У нас есть редакционная политика, которую мы продолжаем развивать. Сейчас в ней около 30 правил: от использования буквы «ё» до постановки точек в таблицах. Чтобы отслеживать верное написание, у нас отлажен процесс кросс-ревью — когда коллеги-писатели вычитывают тексты друг друга.
В какой-то момент мы поняли, что хотим настроить автоматизацию. Мы уже пробовали автоматизировать проверку правил, но без регулярной и запланированной активности удалось прийти только к Python-скрипту, который мы практически не поддерживали. Он на if-else’ах проверял, есть ли в файле слова, запрещенные редакционной политикой.
Чтобы решить, стоит ли нам углубляться в тему автоматизации, мы ответили на несколько вопросов:
Есть ли необходимый фундамент из ручных процессов? Да. У нас уже были рабочая редакционная политика и процесс ревью, без которого документация не попадала в продакшн.
Велика ли потребность в автоматизации? Да. Хоть сейчас организация процесса и «не горела», мы предвидели, что правил и документации в будущем станет еще больше.
Есть ли на это ресурсы? Да. Мы начали с минимума ресурсов для изучения существующих инструментов и их использования. Соотнеся сложность и наши умственные возможности, решились выделить ресурсы на дальнейшую работу.
Когда поняли, что собрали «за» по всем трем пунктам, то приступили к поискам оптимального инструмента.
Ищем подходящий инструмент
Далее столкнулись с выбором: стоит ли докручивать собственный скрипт, превращая велосипед в мопед? Или мопед уже существует, и будет проще его найти и настроить? Чтобы определиться, мы составили критерии подходящего инструмента:
Он может «съесть» правила нашей редакционной политики и не подавиться.
Он бесплатный.
Его несложно настроить и использовать.
Предугадывая возможные вопросы про инструменты с AI — мы решили, что оптимальнее начать с самого простого варианта и сделать по-максимуму с минимумом затрат, а к идее с AI вернуться позже, в рамках решения более сложных задач. В итоге самым простым вариантом оказался линтер — программа для анализа текста на предмет орфографических, грамматических и стилевых ошибок, а также других недочетов.
Классификация линтеров
Пока искали подходящий линтер, вывели их неформальную классификацию. Выделили три группы:
Проверка орфографии (анг. Spell Checkers) — эти инструменты анализируют правильность написания отдельных слов. Примеры: aspell, PySpelling, Hunspell.
Проверка разметки (анг. Style Checkers) — анализируют корректность использования элементов в языках разметки. Примеры: doc8, restructuredtext-lint, sphinx-lint.
Проверка стиля (анг. Style guide Checkers) — анализируют орфографию и разметку, а также оценивают специфические комбинации слов, предложений и элементов. Примеры: Vale, Textlint, Typerighter.
В процессе мы поняли, что нам подходит группа Style guide Checkers, ведь именно им можно «скормить» редакционную политику. Стали выбирать из трех вариантов. Первым выбыл Typerighter — из-за сложного процесса интеграции в проект и недостаточно подробной документации. Затем отпал Textlint — для его конфигурации нужно знать JavaScript, а привлекать ресурсы разработчиков мы не планировали. В итоге победителем стал Vale с его возможностям:
поддержка RST-разметки;
кроссплатформенность;
встраиваемость в CI/CD;
наличие плагина для VScode.
Линтер Vale — почему его выбрали
Vale — open source инструмент, достаточно гибкий в настройке. Главное, что в нем можно настроить правила проверки. Vale хранит правила в формате yaml-файлов, где ключи — это параметры проверки. Среди них, например, область применения правила и выводимое сообщение. Само правило записывается в формате регулярного выражения.
Отдельно стоит упомянуть параметр с уровнем серьезности правила. Есть три уровня по возрастанию их критичности:
suggestions (предложения),
warnings (предупреждения),
errors (ошибки).
Этот параметр помогает не только различать критичность правила, но и управлять сборкой документации в пайплайне. Можно настроить Vale так, чтобы джоба блокировала пайплайн, если найден определенный уровень. Например, сборка документации не пойдет дальше, если найдены ошибки или ошибки с предупреждениями.
Конфигурация линтера и его правила хранятся как файлы в репозитории с исходниками документации. Это отлично вписывается в парадигму docs-as-code.
Готовимся к запуску: примеры автоматизированных правил
Мы автоматизировали около десятка правил редполитики. Начали с тех, которые проще запрограммировать в регулярные выражения. Вот три примера:
-
Между блоками примечаний есть текст:
-
Слишком сложное предложение. Пока мы определили его как предложение, в котором больше трех запятых:
-
На главной странице раздела есть текст, а не только ссылки на вложенные страницы:
Пусть и не с первого раза, но правила мы закодировали. Правда, это оказалось самой легкой частью.
Тестируем линтер: на чем все поломалось
Иногда нужно начинать с тестирования на проде — вот чему нас научил линтер. Когда мы писали правила для Vale, мы составляли тестовые файлы с примерами корректных и некорректных выражений, а потом запускали линтер на них. Хотели как лучше предусмотреть все пограничные случаи, а получили линтер, не работающий на исходниках нашей документации. При запуске Vale в командной строке наступало затишье длиною в вечность. Как так-то? Методом тыка выяснилось, что какие-то исходники линтер обрабатывает, а на каких-то зависает.
У нас около 6 000 исходников и мы занимаемся автоматизацией, значит… надо написать скрипт для решения этой проблемы! Скрипт должен был:
запускать Vale на каждом исходном файле;
записывать результат работы линтера — найденные ошибки — в отдельный файл;
находить зависающие файлы и записывать их файловый путь.
Список зависающих файлов собирали, чтобы на конкретных примерах понять причину такого поведения линтера.
В чем была проблема — расследование
Само зависание мы определили как период больше пяти секунд, за которые линтер не успевает обработать файл. Величину таймера выбирали экспериментально. Искали золотую середину, при которой время обработки всех файлов не улетает в бесконечность и количество зависших файлов не стремится туда же. В итоге получилось, что скрипт отрабатывает около 45 минут и находит 120 зависающих исходников.
А теперь к самому интересному — почему Vale может зависнуть на файлах? Любимым методом тыка выяснили: чем больше вложенность элементов в файле, тем больше отступов и тем дольше отрабатывает линтер. Если вообще отрабатывает ?.
Теперь в ближайших планах — разобраться, как проверять линтером зависающие файлы. Вероятно, будем писать еще один скрипт, который будет, например, удалять отступы из файлов.
Наши планы и выводы
На этом наша история не заканчивается, дальше — больше. Нас ждут:
обработка зависающих файлов;
встраивание линтера в пайплайн сборки документации;
исследование о влиянии линтера на процесс ревью.
Мы не призываем автоматизировать всё и вся в угоду трендам — только если уже сформированы ручные процессы, назрела потребность и появились ресурсы. А что до инструментов проверки текста — отталкивайтесь от оптимального решения конкретно для вас и в конкретный момент времени. В нашем случае оптимальным оказался линтер Vale. Вам он тоже может подойти, если хотите проверять редакционную политику и ищете бесплатный инструмент с несложной настройкой.
Если будут вопросы — задавайте их в комментариях. Будем рады ответить и пообщаться о схожих проектах.
Интересное в блоге: