Привет, Хабр! На связи снова Юрий Никулин. В первой части статьи я рассказывал, почему в Cloud.ru решили перейти на doc as code и какой технологический стек мы выбрали. В этой части поделюсь самим процессом — расскажу, как настраивали, тестировали и внедряли новую систему и что из этого вышло.

На старте

Итак, напомню, что для реализации docs as code мы выбрали такой технологический стек: 

  • reStructuredText — язык разметки.

  • GitLab — система версионирования исходников.

  • Visual Studio Code — редактор исходников.

  • Sphinx — система сборки для генерации статических страниц HTML.

Всё, что было у нас на тот момент — горящий дедлайн 4 недели, руководитель документирования (я), 5 техписателей и двое разработчиков на парт-тайм. И нам был нужен план ????

План

Чтобы структурировать процесс и уложиться в срок, мы наметили план. Он отражал ключевые этапы перехода:

  1. Знакомимся с Git / GitLab

  2. Собираем и тестируем прототип системы

  3. Настраиваем окружение и деплой на прод

  4. Настраиваем тему

  5. Конвертируем Word в reStructuredText

  6. Делаем гайды для писателей

В реальности, конечно, часть процессов мы выполняли параллельно. Как всё было — рассказываем дальше.

Знакомимся с Git / Gitlab 

Раньше техписатели хранили пользовательскую документацию по всем сервисам локально на своих компьютерах в формате Word. А для публикации на сайте переводили Word в PDF и загружали на сервер. 

Теперь же нас ждал принципиально новый подход к документированию. Чтобы переход на docs as code был максимально прозрачным и безболезненным, мы начали знакомить техписателей с новыми инструментами на самых ранних этапах — еще до разработки и тестирования системы. 

Начать решили со знакомства с Git и GitLab. Успех на этом этапе помог бы решить сразу две прикладные задачи: 

  • освоить работу с системой контроля версий;

  • перенести документы Word в репозиторий GitLab — для сохранения документов, инвентаризации и подготовки к этапу конвертации документов из Word в reStructuredText. 

Погружение техписателей началось с лекции-ликбеза про систему контроля версий (СКВ) — поговорили о том, зачем нужна СКВ и почему без нее не получится построить docs as code. 

Для практических занятий мы завели тестовый репозиторий в GitLab и пригласили разработчика. Он провел несколько воркшопов по теме — показал, как создавать рабочие ветки, работать с основными командами в консоли (add, commit, push), как выглядят самые частые ошибки и как их побеждать. Мы записали воркшопы и сделали тайм-коды к каждому, чтобы было удобно к ним возвращаться.

Техписатели тренировались загружать документы Word в тестовый репозиторий. Они сразу учились работать с Git только через командную строку — это уберегло нас в будущем от множества багов, которые часто возникают при работе с клиентами Git. К тому же в консоль выводится лог операций, что дает +100 к прозрачности процесса и удобству траблшуттинга. Полученные навыки работы с консолью также пригодились при конвертации Word в RST — об этом дальше в статье. 

После «лабораторных» работ на тестовом репозитории, мы завели боевой репозиторий и техписатели перенесли в него все документы Word со своих компьютеров.

Что в итоге:

Техписатели освоили Git и перенесли в репозиторий 100+ документов Word. Достижение этой промежуточной цели прибавило ребятам уверенности на следующих уровнях — при изучении языка разметки, системы сборки и редактора кода. 

Собираем и тестируем прототип системы

Пока техписатели переносили документы в GitLab, я занялся прототипом системы документирования. 

Настраивать и тестировать прототип решили на Linux. В этот момент мы еще не до конца понимали, как будет выглядеть архитектура системы документирования. Но было очевидно, что в целевой картине сборка должна проходить на серверах под Linux. 

Немаловажная деталь — по корпоративному стандарту техписатели работали только на Windows. Мы понимали, что то, что сейчас протестируем на Linux, под Windows и Mac может работать немного иначе (кэп). Но разбираться с Windows было некогда и мы приняли эти риски.

Совет: если у вас есть возможность и достаточно времени — настраивайте и тестируйте прототип сразу на целевой ОС. Так вам не придется разбираться со странными багами, которые точно будут, если ОС для тестирования и основная ОС отличаются.

Шаг 1. Разбираемся в reStructuredText и Sphinx 

Я не буду здесь подробно рассказывать о языке и системе сборки — вся документация есть в открытом доступе. Остановлюсь на некоторых особенностях Sphinx, из-за которых наш механизм сборки в итоге стал немного нестандартным. 

reStructuredText

У reStructuredText (RST), в отличие от Markdown, богатый синтаксис и есть фундамент логической разметки. Чтобы быстро обучиться языку и передать знания техписателям, мы придумали образцовый документ. 

Образцовый документ — это сверстанный пример использования основных элементов языка RST (ролей и директив). 

Из обширной спецификации RST в образцовый документ попал ограниченный набор директив и ролей. Например, маркированные списки у нас обозначаются только дефисами «-». В то время как спецификация разрешает использовать разные символы  — «*», «+», «●», «▶», и в вебе это один и тот же маркированный список. Мы не стали использовать всё многообразие синтаксиса RST, так как хотели добиться однозначности и логической связности элементов в исходниках. 

Образцовый документ создавался не в вакууме, а во время конвертации документов из Word в RST. Мы взяли 4 документа по самым популярным сервисам, конвертировали и параллельно дополняли образцовый документ. На этих же документах, переведенных в RST, потом тестировали прототип системы и сборку. 

Образцовый документ мы разместили в отдельном проекте GitLab и опубликовали на внутреннем домене компании. Но он стал не только методическим руководством по языку — его можно было клонировать и поработать с ним локально. Например, поиграть с разметкой, чтобы лучше ее понять, протестировать новые директивы и роли. 

Sphinx

Sphinx генерирует HTML из RST. При этом у механизма сборки есть ряд особенностей:

  • Параметры сборки определяются в конфигурационном файле conf.py.
    При сборке Sphinx смотрит, где находится conf.py и от него рекурсивно вниз по каталогам ищет файлы с расширением .rst — так собирается документ.

  • Sphinx умеет собирать только один проект с одним файлом conf.py.
    В терминах Sphinx «проект» — это документ, например, руководство пользователя.

  • Генерация внешних и кросс-документных ссылок подключается через расширение intersphinx.
    При сборке генерируется специальный файл objects.inv — он содержит список объектов, на которые ссылаются из документа.

Эти особенности Sphinx повлияли на структуру хранения исходников и подход к настройке механизма сборки.

Шаг 2. Продумываем структуру хранения исходников и механизм сборки

Sphinx отчасти диктовал нам структуру хранения исходников — в корне проекта (документа) должен лежать конфиг-файл conf.py, а во вложенном каталоге на этом же уровне — файлы с расширением .rst.  

Если эту логику применить не к одному, а к 100+ документам по разным сервисам на русском и английском языке, то на выходе получается такая структура: 

documents — корневой каталог. 

source — каталог с разбивкой по языкам документации (ru/en).

ru/en — каталог с документацией по всем сервисам на русском и английском языке.

product — каталог с файлом conf.py и с RST-исходниками документации по определенному сервису.

Но, как мы помним, Sphinx умеет собирать только 1 документ в один момент времени — такая механика нам не подходила. Готовые расширения Sphinx для сборки нескольких документов тогда найти не удалось. Так нам сразу представился шанс написать свой алгоритм сборки ????

Требования к сборке были такие:

  • собирать документы по предопределенному списку;

  • документы должны быть связаны между собой — ссылками и переиспользованием;

  • собирать документы все вместе, чтобы все ссылки и связи работали, и были актуальными.

Чтобы собирать документы по предопределенному списку, мы написали скрипт и создали файл со списком путей до каталогов с нужными документами. Скрипт брал conf.py документов из списка и последовательно запускал сборку каждого.

Файл со скриптом (build.sh) и файл со списком документов (docs-to-build.txt) разместили в корне репозитория. 

Теперь Sphinx умел собирать несколько документов. Профит! Оставалось разобраться с синтаксисом ссылок. 

В Sphinx расширение intershpinx отвечает за генерирование ссылок на внешние ресурсы и кросс-документные ссылки. 

С настройкой внешних ссылок проблем не было — в пути достаточно указать нужную директиву и URL внешнего ресурса. 

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

Sphinx предлагал не самый простой синтаксис относительных ссылок, а в сумме с нашей вложенной структурой хранения исходников пути получались очень длинными — не ошибиться было невозможно. Тогда мы написали скрипт, который подставлял часть пути автоматически — теперь техписатели прописывалив conf.py только путь до целевого документа. 

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

Итак, мы собрали структуру исходников, написали скрипт для сборки документов по списку и разобрались с путями для кросс-документных ссылок. 

Sphinx при сборке документа считывает исходные файлы RST, создает дерево, а затем генерирует файлы HTML в каталоге out. Там же создается файл objects.inv, в котором хранится список объектов, на которые ссылаются из документа. При сборке система обращается к этому файлу и формирует ссылки. 

Нюанс — когда запускаешь сборку нескольких документов, они собираются последовательно, один за другим. Файлы objects.inv для части документов в этот момент просто не существуют — так и появляются битые кросс-документные ссылки.

Решением проблемы стал, возможно, не очень изящный, но рабочий способ — скрипт, который запускал сборку документации два раза подряд.  

Идея в том, что при первой сборке формировались файлы objects.inv для всех документов. При этом в каталоге out появлялись HTML-файлы с битыми ссылками, но это не страшно — ценность этого этапа в том, что создавались objects.inv. Вторая сборка перезаписывала HTML-файлы в out, но ссылки уже были рабочими, так как objects.inv для документов уже существовали. 

Двойная сборка точно удлинила процесс, но и дала ощутимый профит — список  objects.inv и остальной контент всегда были актуальными.

Что в итоге:

  • Sphinx собирал все документы по предопределенному списку с помощью скрипта.

  • Двойная сборка решила проблему с битыми кросс-документными ссылками. 

Настраиваем окружение и доставку на прод

Мы настроили и протестировали на Linux прототип системы сборки. Теперь нужно было настроить правильное окружение на Windows-ноутбуках техписателей, сделать удобный инструмент сборки, а также наладить процесс доставки документов в прод. 

Окружение

Для настройки правильного окружения на Windows-ноутбуках нужно было установить: 

  • Python правильной версии;

  • Sphinx правильной версии;

  • расширения для Sphinx.

Важно было не просто один раз установить это окружение, а сделать так, чтобы оно одинаково работало у всех техписателей, а версии Python, Sphinx и расширений обновлялись на всех устройствах своевременно.

Для решения этих задач мы выбрали Docker — положили всё, что нужно для сборки в Dockerfile и загрузили его в репозиторий к исходникам. 

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

  • Git

  • VS Code

  • Docker Desktop

При клонировании репозитория ребята получали на свой локальный компьютер всё, что нужно для работы: исходники RST, файл со скриптом сборки, файл со списком документов для сборки и Dockerfile. А при каждом git pull из мастера — свежую версию окружения.

Сборка

Сборка запускалась вызовом скрипта build.sh через командную строку. Мы решили упростить процесс — сделать так, чтобы техписатель запускал сборку нативно в VS Code и не переключался между окнами. Это оказалось несложно.

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

В репозитории мы создали каталог .vscode, где разместили файл tasks.json с описанием задач и команд для запуска сборки.

Теперь сборка запускалась через VS Code простой комбинацией клавиш Ctrl + Shift + P.

А благодаря расширению Docker для VS Code при запуске сборки автоматически поднимался контейнер и собранная документация становилась доступна на локальном хосте. 

Доставка

Итак, окружение на Windows-ноутбуках настроено, документация собирается локально в Docker-контейнере. В первой версии процесс сборки и деплоя документации на прод выглядел так: 

  1. Техписатель работал с документом в VS Code.

  2. Коммитил изменения в локальную рабочую ветку.  

  3. Пушил изменения в ветку на сервере. 

  4. Сливал изменения в мастер. 

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

  6. Запускал сборку мастера через VS Code.

  7. После окончания сборки переносил содержимое из каталога out репозитория Source в каталог out репозитория Build, где лежала предыдущая сборка. 

  8. Отправлял изменения на сервер в репозиторий Build. 

  9. На файловой системе прода 1 раз в минуту с помощью Cron запускался git pull из мастера Build. Если изменений в репозитории не было — ничего не происходило. Если были — обновленная документация публиковалась в прод.

В этом процессе нет автоматизации и достаточно много ручного труда, но он быстро настраивался и доказал свою надежность — мы жили по нему примерно год без каких-либо проблем. Такой алгоритм доставки может подойти, если у вас есть задача запустить docs as code быстро или нет ресурсов на автоматизацию (или она вам просто не нужна — такое тоже бывает). 

Спустя год мы настроили автоматический пайплайн в GitLab с покоммитной сборкой на dev-стенде и выкладкой в прод. Все эти 3 года занимаемся автоматизацией: настроили линтер для отслеживания стоп-слов в документации, инструмент для поиска похожих фрагментов текста и много чего еще — обязательно расскажем про это в следующих статьях. 

Что в итоге:

  • Настроили окружение на Windows-ноутбуках с помощью Docker. 

  • Настроили запуск сборки через VS Code.

  • Опубликовали первую версию документации в проде. 

Настраиваем тему

Sphinx как система сборки имеет большое количество готовых тем оформления — мы выбрали Read the Docs. Она достаточно популярна, а значит при необходимости мы могли рассчитывать на помощь сообщества и советы по траблшуттингу в сети.  

На кастомизацию темы не пришлось тратить много времени — фронтенд-разработчик всего за 5 часов пропатчил ее под корпоративные цвета и добавил логотип.

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

Что в итоге:

Настроили внешний вид портала документации с помощью темы Read the Docs. Все было готово — мы запустились в прод с первыми четырьмя документами ???? 

Конвертируем Word в reStructuredText

После настройки темы и выкатки портала в прод, все новые документы по продуктам мы уже создавали по принципу docs as code.  

Но у нас все еще оставалось около 100 документов Word, которые нужно было конвертировать в RST. Ручная конвертация первых четырех документов, которую мы делали, когда писали образцовый документ, заняла много времени. Хотелось хоть немного автоматизации.

Быстрый поиск в Google предложил Pandoc — бесплатный универсальный конвертер документов. У него подробная документация и несложный синтаксис команд. Всё, что было нужно для работы, — командная строка и установленный Pandoc. 

В итоге процесс конвертации выглядел так:

  1. Запускаем Git Bash. 

  2. Переходим в каталог с файлом Word, который нужно конвертировать:

$ cd Documents/2convert/ug_vdc
  1. Выполняем команду:

pandoc -f docx --extract-media . -t rst -o index.rst vdc.docx

В результате внутри каталога с документом Word формировался один документ в формате RST (index.rst) и каталог media, содержащий все картинки, которые встретились в документе.

Конечно, результат конвертации был далек от идеала. Pandoc неправильно строил таблицы, нумерованные списки отмечались неверно, встречались лишние элементы в виде рамок. Но все же какая-то часть разметки была правильной: заголовки, маркированные списки, деление на абзацы.

Техписатель разбивал этот длинный index.rst на отдельные файлы, правил верстку и пушил в репозиторий. На этом этапе очень пригодился образцовый документ — с его помощью ребята быстро изучили и запомнили язык разметки.

Pandoc при конвертации документа отправлял скриншоты в отдельный каталог. Мы избавлялись от большей части скриншотов — оставляли их только в тех местах документации, где у пользователя с большой долей вероятности могли возникнуть сложности. Этому принципу мы следуем до сих пор — не подкреплять каждый шаг в инструкциях скриншотами. Их избыточность, на наш взгляд, вредит восприятию материала, а также увеличивает размер репозитория и затрудняет его обслуживание.

Также Pandoc автоматически присваивал скриншотам и схемам в качестве имен номера. Для экономии времени в первой итерации мы их не меняли и загружали в репозиторий как есть. Но в техдолг первой очереди завели задачу сделать для всех картинок семантически значимые имена.   

Что в итоге:

Немного ускорили ручную конвертацию из Word в RST с помощью Pandoc. Но нам потребовалось еще около двух месяцев, чтобы окончательно забыть про Word. 

Делаем гайды для писателей

В реальности отдельного этапа подготовки гайдов не было. Мы начали копить материал по новой системе документирования с самого начала — когда знакомились с Git и записывали воркшопы. 

Дальше на каждом этапе настройки, тестирования и внедрения системы мы не ленились писать инструкции. Делали это сразу, как только добивались успеха в настройке инструмента и процессов. Конечно, настройка системы и параллельное документирование — это трудозатратно. Но если бы отложили это на потом, точно упустили бы много важных нюансов и усложнили работу техписателей с системой.

Инструкции стали основой нашей будущей базы знаний по техстеку системы документирования. Со временем база превратилась в большой портал на Confluence, где можно найти всё про корпоративный docs as code и не только.

Что в итоге:

К моменту запуска портала у нас были все основные материалы по методологии и инструкции: 

  • Инструкция по скачиванию и настройке софта для работы с системой документирования.

  • Записи воркшопов по Git/GitLab с таймлайнами.

  • Образцовый документ — для освоения языка разметки.

  • Инструкции по конвертации Word в RST.

  • Инструкции по сборке и деплою.

Итог

Мы перешли на docs as code за 4 недели???????????? — настроили систему и запустили портал с 4 документами. Все новые документы по сервисам уже писали в RST. Дальше команду техписателей Cloud.ru ждали 2,5 месяца конвертации остальных документов и отработки техдолга по скриншотам. Началась новая жизнь ????

Несколько мыслей для тех, кто планирует переезд на docs as code: 

Выбирайте техстек под себя

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

Мы хотели и собрали техстек только из open source решений — было важно в будущем не тратить время на закупки лицензий и согласования бюджета. А также иметь возможность кастомизировать систему, что почти недоступно при использовании проприетарных решений. 

Sphinx + RST — возможно для кого-то не самое очевидное и популярное сочетание  для реализации docs as code. Но Sphinx написан на Python — языке, на котором в основном ведется разработка продуктов в нашей компании. Благодаря этому мы можем дорабатывать и настраивать систему под себя силами разработчиков Cloud.ru. К тому же у Sphinx и RST обширное сообщество и много советов в сети. 

Тестируйте прототип в целевой среде

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

Включайтесь в догфуддинг

Не поддавайтесь соблазну взять какие-то готовые решения и без тестирования внедрить в процессы отдела. Например, мы могли бы не писать образцовый документ, а дать техписателям ссылку на спецификацию RST. Но нам было важно в будущем сделать работу отдела комфортной и эффективной, а не просто в моменте поставить галочку в списке to-do.

Будьте прозрачны и открыты с вашей командой

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


Что еще есть в блоге Cloud.ru:

Комментарии (6)


  1. krakenkaken
    17.10.2023 14:37
    +1

    4 недели - это сильно! Про техническую часть понятно, любопытно узнать процессные нюансы:

    1. Как долго онбордите новичков без опыта в dac? Быстро втягиваются?

    2. Как готовите драфты статей? Если писать сразу в языке разметки, фокус уходит в оформление, а не смысл. Есть ли централизованный подход?

    3. Как проводите ревью? Через мерж реквесты?

    4. Где и как решаете конфликты? Прямо в гитлабе?

    5. Что делают техписы, когда возникают ошибки? У вас в команде остался инженер или ребята сами справляются?


    1. guitarman Автор
      17.10.2023 14:37

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

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

      3. Ревью техническими писатели — через mr-ы, владельцами знаний — через mr, конфлюенс-аутпут, комментариями в баг-трекере. Подбираем инструмент под удобство и навыки вычитывающих.

      4. Конфликты решаем на локальной машинке, используем стандартные средства гита+редактор (в нашем случае — vs code).

      5. Если ошибки на уровне пайпов в гитлабе/инфраструктуры — привлекаем девопса. Если на уровне сборки — ребята справляются сами или с помощью внутреннего сообщества технических писателей.


  1. techWriter007
    17.10.2023 14:37

    Юра, спасибо большое за статью, было очень интересно читать эдакий process journey.

    Решением проблемы стал ,возможно, не очень изящный, но рабочий способ — скрипт, который запускал сборку документации два раза подряд.

    Если сможешь, поправь, пожалуйста, запятую, опосля **стал**.

    Еще такой вопрос, почему был выбран именно RST, а не asciidoc в качестве формата?


    1. guitarman Автор
      17.10.2023 14:37

      Спасибо за комментарий!

      Отчасти раскрывал вопрос в комментариях к предыдущей статье:

      Основное — отсутствие встроенного локализационного контура (в rst это генерация po из коробки) и большая распространенность rst, включая поддержку сообщества (субъективно на базе доступных расширений и ответов на наши вопросы на просторах интернета).


  1. nikolay_karelin
    17.10.2023 14:37

    Спасибо, было очень интересно, буду перенимать ;)

    Вопрос и пара дополнений:

    А можете ли вы поделиться образцовый документом?

    Кстати, Sphinx отлично собирается и на Винде, без докера. Но это скорее вопрос удобства.

    Тексты кстати могут быть и на Markdown, Sphinx через расширение умеет его читать.

    Ну и на выходе можно сделать отлично брендированный PDF и даже экзотику типа CHM ;)


    1. guitarman Автор
      17.10.2023 14:37

      Пока поделиться образцовым документом не готовы, но, возможно, решимся в будущем.