Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Разрабатывая API, наверняка не раз появлялись сложности с документацией: то её нет, то она не отображает поведение, описанное в коде.
С точки зрения разработчика, написание документации (одной только внутренней) занимает не меньше времени, чем написание самого кода. Знакомо? Тогда добро пожаловать под кат.
А проблема-то есть?
Наша команда давно разрабатывает API, который является основой нашего продукта, но живых пользователей у него, на тот момент, не было, поэтому и необходимости документировать что-то для внешнего использования никто не видел. Как и все команды, мы начали с внутренней документации — сначала один метод, потом другой. В нашем пространстве в Confluence можно найти десяток другой страниц, где отображена довольно шаблонная информация – что за метод API, какой у него query path, какие параметры и что мы получим на выходе.
Все бы ничего, но код постоянно меняется и растет, меняются потребности бизнеса. Вместе с изменениями кода, могут меняться и интерфейсы API, что неизбежно приводит к изменению на этих страницах. Хорошо, если это одна страница и всего 1 раз. А если изменений больше?
Мы придумали решение (собственный велосипед), как можно, занимаясь обычной деятельностью разработчика, не задумываться о написании и актуализации внутренней документации.
Немного решений
Есть разные варианты, как могут быть взаимосвязаны код и спецификация кода, но я для себя выделяю два:
- Code first, specification next
- Specification first, code next
Начну со второго, как с варианта, который нам меньше всего подходил.
Specification first, code next — это про генерацию кода, на основе спецификации, то есть кода не существует, пока вы не напишите спецификацию.
Самый простой пример — Swagger Codegen.
В нашей компании есть команды, которые в своем продукте используют данный подход, но в нашем случае он не очень подходил. На момент, когда столкнулись с нуждой, у нас уже было написано немало методов API, поэтому нам не хотелось ради документации кардинально менять процессы разработки — сначала мы пишем драфты, потом кодим и только затем описание спецификации.
Code first, specification next — тут всё просто, сначала пишем код, потом спецификацию. Но тут встал вопрос — а если нам не хочется делать лишних движений, чтобы генерировалась спецификация?
В ряде приложений в нашей компании используется этот подход, но он не особо автоматизирован — методы API обвешиваются всевозможными аннотациями, на основе которых генерировалась спецификация. Но эти же аннотации часто не соответствуют реальности, ведь потребности и возможности приложения растут и изменяются.
«Ты ж программист» — сказал я себе и решил написать небольшой прототип, который позволит не писать всю эту рутинную фигню.
Делая очередную задачу и написать n-ый функциональный тест, я понял, что вся информация для спецификации у нас уже есть.
У нас есть функциональные тесты, которые содержат практически всю нужную нам информацию:
- Что вызывается
- С чем вызывается (параметры, тело, заголовки и пр.)
- Какой результат ожидается (статус код, тело ответа)
Почему бы не сделать собственный велосипед?
По сути, всё практически всё, что мы обычно пишем в спецификации у нас есть. Дело за малым — закодить это дело.
Поскольку наше приложение на php, то на помощь мне пришла рефлексия. Используя немного магии рефлексии, собираем все доступные нам методы API, из функциональных тестов берем данные, извлекаем данные об авторизации и её типе. Из обычных аннотаций к методам, мы достаем само описание метода. Смешав всё это, приправив специфичными фичами для используемого в наших решениях фреймворка, мы за пару недель получаем решение, которое практически не требует дополнительного времени от разработчика.
Генерация спецификации только первый шаг — из спецификации нужно получить документацию, которую можно предоставить внешним разработчиком. Одно из требований, которые предъявляются к документации — она должна быть представлена на нескольких языках, но на данный момент, мы генерируем документацию только на английском. Пока хватает, но нужно будет подключать к нашей схеме генерации спецификации механизм получения переводов.
Проблему, которая была изначально, мы решили. Но с таким решением есть немало рисков:
- Цена поддержи собственного велосипеда
- Расширение необходимого функционала
- Актуализация и синхронизация переводов
Эти риски нужно иметь в виду и, если они начинают срабатывать, то принимать меры.