Работа над общей библиотекой сильно отличается от работы в продуктовой команде. Но разработчики библиотек тоже проходят длинный путь становления своего продукта, причем, в отличие от приложений, часто без помощи менеджеров или бизнес-аналитиков.
Давайте посмотрим, из чего может состоять путь крупной библиотеки, как планировать действия команде разработки и какие челленджи могут встретиться на нем.
Статья написана по опыту разработки фронтовых библиотек и с советами вокруг JS-экосистемы, но часть идей будет полезна и для других направлений.
Посмотреть в формате видео
11 сентября прошел юбилейный MoscowJS 50, где я выступал с одноименным докладом. Запись выступления можно посмотреть на Ютубе. В этой статье я хочу донести те же идеи, но в текстовом формате: выбирайте, что вам ближе!
О чем статья
За последние три года я разработал и выпустил много библиотек: маленькие модули для пары команд, библиотеки для крупного отдела фронтенда, нишевые опенсорсы для решения конкретной проблемы и огромную библиотеку компонентов Taiga UI.
Taiga UI сейчас содержит больше 130 компонентов и еще несколько сотен разных Angular-сущностей. Но выросла она из маленького пакета внутри отдела, плавно развиваясь сначала в нем, а после и во всей компании.
Этот опыт натолкнул меня на мысль, что разработка библиотеки — совсем не однотипный процесс. Пока растет библиотека, у команды может сильно поменяться деятельность, могут появиться нетипичные обязанности, а разработчикам важно продумать и проработать, как перестраиваться под новые условия.
Я разбил путь развития библиотеки на пять этапов. Но для любой конкретной библиотеки их количество может меняться.
Для каждого этапа опишу свое видение, что должна делать команда разработчиков и как планировать движение дальше. Покажу и все потенциальные ошибки и проблемы, которые могут замедлить или вовсе остановить развитие.
Замечу, что описанные в статье наблюдения и советы так или иначе применимы к любому модулю, пакету или библиотеке в компании.
Этап 1. Папка в проекте
Этап отчасти шуточный, но все же существует. Это ситуация, когда вы работаете над проектом и хотите вынести общую логику в какую-нибудь папку с тулингом.
Работа над этой папкой не отличается от работы над самим проектом. Но однажды к вам может прийти другая команда и сказать, что тоже хочет пользоваться вашими инструментами. Тогда эту папку можно превратить в отдельный пакет.
Этап 2. Отдельный пакет
Совет: если вы используете решение для монорепозиториев, то часто с ним идет CLI, позволяющая генерить библиотеки одной командой. Генерация полноценного пакета будет занимать столько же времени, сколько и создание папки. Но так вы будете делать более общее решение, а при необходимости сможете вынести пакет в отдельный репозиторий и потратите не больше пары минут.
На этом этапе у вас есть пакет, который уже используют в соседних проектах. Тут важно грамотно подойти к организации работы с библиотекой. Возможны несколько сценариев.
Плохо: случайные люди контрибьютят, случайные люди ревьюят или никто не смотрит. Это путь в никуда, через некоторое время библиотеку в библиотеку станет невозможно контрибьютить, а после и использовать. Избегайте таких ситуаций.
Нормально: контрибьютят все еще случайные люди по необходимости, но есть заинтересованные ревьюеры. Каждый Pull Request рассматривают люди, которые примерно осознают общую архитектуру библиотеки и заинтересованы в ее развитии.
Хорошо: есть выделенная команда мейнтейнеров библиотеки. Они организуют контрибьютинг, поддерживают библиотеку в едином стиле, смотрят PRы, иногда могут ответить на вопросы или закодить нужную фичу для проектов.
На этом этапе появляется собственный релизный цикл, документация, которая позволяет не отвечать на одни и те же вопросы изо дня в день, а также минимальная поддержка — пока все и так примерно знают, к кому обратиться за помощью.
Еще вы можете спокойно делать ломающие изменения: сильно менять API или заменять одни сущности другими. Надо будет лишь обойти пару команд, может быть, где-то помочь с переездом.
Если же ваша библиотека развивается гармонично и приносит пользу, то ей захочет пользоваться все больше команд. Так она перерастет в решение на отдел.
Этап 3. Решение на отдел
Где-то это может быть этап не отдела, а всей компании, а где-то — одной группы разработки. Для меня ситуация примерно такая:
библиотеку используют 10+ проектов из одной предметной области;
разработчики библиотеки и ее потребители незнакомы;
у библиотеки есть выделенная команда разработки. Не обязательно на фултайм, но важно, чтобы развитие библиотеки было частью их регулярной рабочей деятельности.
Тут разработчики библиотеки должны начать задумываться о кастомизируемости сущностей — делать более общие решения, которые команды смогут гибко подстраивать под свой конкретный кейс. Если не думать об этом, то разработчики проектов будут регулярно приходить и просить докрутить общий инструмент под их конкретный кейс, что отнимает много времени и засоряет кодовую базу.
На этом этапе уже должна быть неплохая документация, чтобы предотвратить рутину с повторяющимися вопросами и организованная поддержка пользователей.
Как организовать поддержку внутри отдела.
Создайте чат в мессенджере, куда сможете постить новости и обновления библиотеки, а пользователи — приходить с вопросами и проблемами. Тут же можно вспомнить практику дежурств: ставить одного члена команды в течение недели разгребать все входящие обращения в чат. На следующей неделе дежурный может меняться.
Проводите демо и показывайте разработчикам проектов, как правильно работать с вашей библиотекой, новые полезные фичи и мастер-классы. Командам будет проще понимать библиотеку, а вы на таких встречах сможете получать обратную связь.
Используйте контрольные опросы. Они показывают, все ли идет в порядке: решает ли библиотека нужные проблемы, удобно ли ей пользоваться, в нужном ли направлении она двигается.
Работа с ломающими изменениями.
На этом этапе ломающие изменения все еще возможны, но должны быть редкими. Командам надо помогать с переездом на новую версию, а может быть, даже начинать автоматизировать этот процесс.
Тут может помочь практика deprecated — когда вы хотите кардинально изменить API-сущность, но вместо изменения маркируете ее как deprecated и добавляете новую сущность с измененным API, которую будете дальше поддерживать.
Такой подход позволяет командам обновлять библиотеку, даже если они пока не готовы к переезду на новые сущности. Когда у них появится время на разбор технического долга — обновятся.
Этап 4. Решение на компанию
На этом этапе библиотека распространилась на всю компанию: ее используют десятки, а может, сотни проектов разной направленности. Библиотеку не нужно пиарить, она стала стандартом: новые люди приходят в компанию и им сразу ее выдают.
Тут разработчики библиотеки уже серьезно думают наперед и делают переиспользуемые решения. И у них появляется деятельность Developer Advocate.
Developer Advocate — целая профессия. Она распространена на западе, но у нас встречается редко. Подробнее о ней можно почитать в статье такого адвоката из Microsoft — Уэссима Чехэма.
Мейнтейнерам пора заботиться о том, удобно ли другим разработчикам использовать их библиотеку. Смотреть взглядом пользователя, искать проблемы, узнавать про сложности и постоянно улучшаться.
К этому моменту и поддержка, и документация должны быть отлично организованы, иначе команда погрязнет в ответах и консультациях. Работа становится более публичной — можно начать вести роадмап, чтобы все понимали, когда ждать крупные фичи.
Здесь же может появиться проблема ранжирования задач по приоритетам: будут приходить люди из разных отделов и объяснять, почему именно их задачу надо сделать быстрее всего. Вам же надо будет как-то организовать этот процесс или просто регулярно выбирать, что приоритетнее.
Для этого этапа я собрал несколько полезных практик.
InnerSource. Часть несложных, но интересных задач можно качественно заспекать и предложить коллегам на InnerSource. Как правило, разработка общей библиотеки сильно отличается от обычной проектной, поэтому разработчикам такое может быть интересно. Польза для библиотеки — люди приходят и делают часть работы. Мотивация контрибьюторов — разнообразить свои рабочие будни и получить новый опыт.
Пример, как было организовано в Taiga UI до опенсорса: краткое описание мотивации для разработчиков и автоматический сбор задач из Jira с лейблом
Автоматизация миграций. Если ломающие изменения на этом этапе и бывают, то мажорные версии готовятся долго и максимально автоматизируются. Без автомиграций даже небольшие изменения в публичном API могут стоить десятки или сотни человеко-часов.
Автоматизировать обновления тоже можно по-разному: мы начинали с простых js-скриптов, которые запускали в проекте через npx, — и они правили файлы силами Node JS и регулярных выражений. Такой же скрипт можно запускать на postinstall новой версии вашего пакета.
Более продвинутый вариант — использовать специализированный тулинг, который позволяет работать с абстракцией над файловой структурой. Например, в Angular-мире существуют Angular Schematics, а если ваши проекты построены как NX-монорепозитории, то можно использовать NX Generators.
Общие рекомендации, как пройти этот этап.
Не пытайтесь угодить каждому. Делайте максимально общие решения и не поддавайтесь на просьбы подкрутить их под потребности одного конкретного проекта.
Не делайте ломающие изменения. А если делаете, то не забывайте сопроводить их автомиграциями.
Будьте готовы к новым обязанностям. Появляется много новых дел, и может показаться, что команде становится тяжелее. Я считаю, что закрывать эти потребности новыми людьми — неправильная тактика. Как правило, работы больше не становится, она лишь становится другой, поэтому если команда открыта новому, то сможет быстро привыкнуть к измененному укладу.
Этап 5. Внешний продукт
Если вашим решением пользуются десятки разработчиков продуктов для разных предметных областей, с большой вероятностью оно будет полезно и людям вне компании.
Потенциал на этом этапе безграничный, количество пользователей может расти кратно и за короткие сроки. Кроме того, внешний продукт может даже стать отдельным бизнесом для вашей компании или просто давать ряд косвенных бенефитов.
На этом этапе сначала нужно задаться вопросом: чего мы хотим от внешнего продукта? С одной стороны, можно сделать платное решение, которое другие компании будут покупать, чтобы справиться с проблемой быстро и дешево. С другой — можно выложить все в опенсорс и развивать публично.
Давайте рассмотрим эти крайности подробнее.
Все продавать. Ситуация, когда мы превращаем наш инструмент в небольшой отдельный бизнес компании. Командой разработки на этом этапе уже точно не обойтись, нужны будут специалисты для b2b-маркетинга и процессы с учетом новых пользователей.
Саму команду разработки тоже придется расширять. Когда компании платят вам деньги, то ожидают собственную линию поддержки, возможность запрашивать новые фичи и так далее. У команды появляется значительно больше работы.
Все опенсорсить. Ситуация, когда мы просто берем и выкладываем наше решение в публичный доступ. Опенсорс дает целый ряд прямых и косвенных бенефитов вашей компании, а работа над ним не будет занимать у команды больше времени, чем занимала прежде. Обо всем этом я подробно написал в своей недавней статье «Пять причин для ИТ-компании полюбить опенсорс».
Пожалуй, единственный момент, который отличает команду разработки крупной внутренней библиотеки от опенсорсной, — все разработчики или большая их часть должны уметь общаться, ревьюить код, отвечать на вопросы и писать документацию на английском. Иначе будет тяжело найти и сохранить пользователей. В остальном все так же: крепкие разработчики и хорошие адвокаты, умеющие объяснить, чем технология полезна, ответить на вопросы и показать примеры.
Рабочий день команды меняется, потому что теперь нужно развивать не только саму библиотеку, но и комьюнити вокруг нее.
Еще возникают дополнительные вопросы приоритизации, потому что на этот раз придется выбирать между запросами из компании и хотелками внешних пользователей. Этот баланс нужно научиться держать и перестраивать по необходимости.
Работа в опенсорсе — это полная публичность вашей деятельности. Тут не получится занести в библиотеку временный «костыль» или сделать минорную фичу не самым красивым образом. Комьюнити плохо воспринимает такие решения.
Все ломающие изменения точно пора автоматизировать. Оно и логично, ведь необходимость поправить буквально одну строчку руками приведет к немыслимому количеству затраченного времени по всему миру. Меня пугает такая мысль.
Среднее решение. Впрочем, необязательно впадать в крайности. Можно и прийти к чему-то среднему между платным решением и опенсорсом.
Например, вы можете иметь полностью бесплатный и открытый исходный код, но предлагать дополнительные платные опции:
консультации, помощь по внедрению, отдельную быструю линию поддержки;
дополняющие продукты. Например, для библиотеки компонентов таким продуктом может быть готовый стартер для админ-панели;
донаты и фича-ханты. На мой взгляд, это самый неудачный способ сколотить капитал, но несколько баксов на подписках получить можно.
А может, сразу в опенсорс?
Не обязательно долго развивать инструмент внутри компании, чтобы потом выкладывать в опенсорс. Это можно сделать в любой момент, если понимаете, что планируемое решение потенциально будет полезно не только в рамках вашей компании. Это рабочая модель, и я бы хотел подсветить пару плюсов и минусов такого подхода.
Минусы:
много работы на старте: вам нужно не только делать саму библиотеку, но и строить комьюнити вокруг нее;
может чуть сложнее развивать библиотеку, потому что при неудачном дизайне или необходимости сменить публичный API можно столкнуться с недовольством внешних пользователей подобными изменениями.
Плюсы:
вы делаете более общие и гибкие решения с расчетом на любой сценарий использования;
обратная связь и помощь от комьюнити помогут сделать библиотеку лучше.
Вместо заключения
Моя идея в том, что нужно регулярно обдумывать, в правильном ли русле развивается ваша библиотека и какими делами заняты ее разработчики.
Совершенно нормально, если вы поняли, что ничего менять и не нужно: некоторым библиотекам лучше развиться до определенного этапа и из-за своей специфики остаться на нем навсегда.
Стоит рассмотреть и вариант опенсорса. Он приносит немного дополнительных хлопот, но дает большое количество преимуществ.