Версионирование языка домена до изменений API
Узнайте, как версионирование языка домена помогает сохранять стабильные бизнес-термины в коде, чтобы изменения партнёров, продукта и API вызывали меньше хаоса.

Содержание
Почему внешние изменения ломают внутренний код
Большинство продуктов описывают одну и ту же бизнес-идею разными словами. Продажи говорят «клиент». Биллинг — «аккаунт». Партнёр называет то же самое «подписчиком». Когда разработчики копируют эти внешние ярлыки в код, код начинает отражать каждую беседу, а не сам продукт.
Поначалу это кажется безобидным. Класс называется PartnerAccount, потому что первая интеграция использовала этот термин. Через несколько месяцев маркетинг меняет тексты на сайте на «Организация», а новый партнёр предоставляет документацию с «Workspace». Бизнес почти не изменился, но теперь три имени указывают на одну идею. Люди тратят время, выясняя, означают ли эти имена разное.
Внешний язык меняется быстрее, чем внутренняя логика. Документация партнёров пересматривается. Копирайт продукта переписывается. Команды продаж переименовывают тарифы, чтобы их было проще продавать. Код не должен впитывать каждое такое изменение, но команды часто встраивают эти ярлыки прямо в модели, эндпойнты, перечисления и поля базы данных.
Когда это происходит, каждое переименование распространяется дальше, чем ожидалось. Оно просачивается в имена тестов, админские экраны, события аналитики, шаблоны поддержки и внутреннюю документацию. Даже если поведение остаётся тем же, люди всё равно правят десятки файлов только ради совпадения имён. Работа скучная и всё равно создаёт баги. Одно пропущенное переименование в отчёте или проверке прав может запутать поддержку или сломать тест.
Глубже проблема не в самом переименовании. В кодовой базе отсутствует защищённый внутренний словарь. Когда внешние термины становятся внутренними, система теряет устойчивый центр. Поэтому версионирование языка домена часто важнее, чем версионирование API. Если в коде есть одно надёжное имя для каждой бизнес-концепции, команды могут отображать изменяющие слова партнёров и ярлыки продукта на краях системы, где это уместно.
Что должно оставаться стабильным внутри кода
Названия, которые описывают ваш бизнес, должны меняться как можно реже. Если ваша компания продаёт подписки, оставьте такие слова, как «подписка», «продление» и «отмена» неизменными в коде. Вендор может называть то же самое «планом», «ценой» или «контрактом». Ваш код не должен гоняться за этими ярлыками.
Это важно, потому что внешние термины меняются по причинам, никак не связанным с вашим продуктом. Платежный провайдер переименовал поле. Партнёр поменял имена вебхуков. Команда продаж обновила тексты на сайте. Если ваши внутренние модели отражают эти слова, одно небольшое изменение разойдётся по тестам, отчётам, админским инструментам и заметкам поддержки.
Некоторые команды называют это единым языком предметной области. Сам ярлык менее важен, чем правило: один термин должен нести одно значение повсюду. Если «клиент» означает платящую компанию, не используйте это слово также для конечного пользователя, владельца аккаунта и регистрации на пробный период. Выберите разные слова и держите их раздельно.
Короткие определения помогают больше, чем многие ожидают. Когда слово вызывает хотя бы один спор, запишите простое определение в репозитории. Коротко: «Account: запись компании, которая платит нам.» «User: человек, который входит в систему под аккаунтом.» Маленький глоссарий сокращает путаницу до того, как она дойдёт до кода.
Держите внутренние термины отдельно от имён полей запросов и ответов. Рассматривайте поля API как перевод, а не как истину. Ваш слой на границе может сопоставлять поле провайдера current_price_id с вашим термином, например «активный тариф подписки», а остальная часть приложения останется нетронутой.
Простой тест помогает: если вы смените поставщика в следующем месяце, какие имена должны остаться? Эти имена и должны быть в ваших доменных моделях, сервисных методах, событиях и тестах. Всё остальное должно жить на краях, где изменение дешевле.
Версионируйте язык раньше, чем версионируете API
Бизнес-термины — это продуктовые решения. Если относиться к ним как к случайным ярлыкам, код начнёт копировать каждое переименование от продаж, поддержки или API партнёра. Тогда одно небольшое внешнее изменение будет казаться большим.
Версионируйте слова первыми. Версионируйте API только когда смысл действительно изменился. В этом суть версионирования языка домена. Переименованное поле не должно требовать новой внутренней модели, если бизнес-идея осталась прежней.
Предположим, долгие годы в продукте использовался термин «customer». Затем биллинг начинает называть того же человека «account owner». Если оба слова означают одну и ту же роль, оставьте одно внутреннее имя в кодовой базе и сопоставьте новый внешний ярлык с ним. Это избегает цепной реакции по сервисам, тестам, документации и дашбордам.
Добавляйте новый термин только когда смысл действительно изменился. Обычно это видно по конкретным признакам: у нового объекта другие правила, им могут обладать другие люди, отчёты считают его иначе или на него влияютцена и права доступа. Если ничего из этого не произошло, скорее всего это переименование, а не новая концепция.
Старые имена должны продолжать работать какое-то время во время перехода. Это не значит, что их нужно держать навсегда, а значит — дать команде время мигрировать без сбоев в работе. На практике команды часто оставляют старое имя как псевдоним в адаптерах, мапперах запросов или сериализаторах, пока внутренняя модель остаётся стабильной.
Вывод старого имени требует даты, а не расплывчатого плана. Отметьте старый термин в коде и документации. Напишите рядом замену, укажите дату удаления и назначьте одного ответственного за очистку. Если этот шаг пропустить, старые и новые имена будут жить рядом годами.
Внимательные команды уже работают так, даже если не называют это «версионированием языка домена». Они в первую очередь защищают смысл бизнеса, а меняют края. Такой порядок экономит время, снижает риски и сохраняет читаемость кода через месяцы.
Простой метод, который работает
Не нужен тяжёлый процесс. Начните с тех слов, которые команда уже использует в тикетах, демо, чатах поддержки и звонках продаж. Цель не сделать язык звучащим умно. Цель — выбрать имена, которые будут понятны через шесть месяцев, даже если партнёры, поставщики или поля API изменятся.
Маленькая команда обычно справляется за одну рабочую сессию и поддерживает это в ходе обычной продуктовой работы.
- Запишите существующие сущности и действия, которые появляются каждый день. Сосредоточьтесь на терминах продукта, а не на именах таблиц БД. Если ваш продукт работает с заказами, возвратами, котировками, одобрениями и продлениями — начните с них.
- Найдите дубликаты и выберите одно внутреннее имя для каждой идеи. Часто используют два или три слова для одного и того же: customer, client и account. Выберите один термин для кодовой базы и держите остальные в качестве псевдонимов только в заметках или адаптерах.
- Сопоставьте каждое внешнее имя с внутренним термином. Платёжный провайдер может присылать
payer_id, а ваша команда называть этоcustomerId. Оставьте внешнее поле на краю и переведите его один раз до того, как остальной код с ним поработает. - Добавляйте короткую заметку, когда смысл меняется. Пишите просто: что изменилось, когда это случилось и какое старое имя или правило ещё существует для старых данных.
- Проверяйте именования перед выпуском API-обновлений. Если новый эндпойнт заставляет переименовывать внутренную концепцию, остановитесь и спросите почему.
Простой пример иллюстрирует идею. Если один партнёр говорит subscriber, другой — member, а ваша команда имеет в виду paying user, выберите одно внутреннее имя, например subscriber. Затем переводите внешние ярлыки на границе. Одно такое решение сэкономит часы правок позже.
Небольшой пример из продукта для бронирований
Команда, работающая над приложением для бронирований, столкнулась с проблемой, которая распространялась по коду. Один и тот же человек появлялся как «guest» на одном экране, как «traveler» в данных бронирования и как «customer» в платежах и инструментах поддержки.
Сначала это казалось безобидным. Затем начали появляться баги. Разработчик менял правила для «guest» и забывал, что платёжный поток использует «customer». Скрипт поддержки считал «travelers» и пропускал людей, которые заплатили, но не заполнили форму поездки.
Путаница усугубилась, когда команда добавила второго платёжного партнёра. Один партнёр присылал payer_id. Другой — user_id. Оба поля значили одно и то же: человек, оплативший заказ.
Вместо того чтобы пропускать имена партнёров по всему приложению, команда выбрала одно внутреннее имя и придерживалась его. В ядре система стала использовать paying_customer.
На границе системы payer_id и user_id оба превращались в paying_customer.id. Приложение сохраняло «guest» и «traveler» только там, где они действительно означали участника поездки. Одно такое решение убрало много шума. Ядру было всё равно, какой партнёр прислал событие, ему было важно только, существует ли paying_customer и к какому бронированию относится платёж.
Тихая победа пришла позже. Когда один партнёр переименовал поле в обновлении API, команда поменяла только адаптер, оставив остальную систему без изменений. Отчёты остались понятными. Скрипты поддержки продолжали использовать одно внутреннее имя. Новые разработчики читали код без догадок, означают ли «customer», «guest» и «traveler» одного и того же человека.
Команды часто торопятся с версионированием эндпойнтов. Часто лучшим первым шагом является версионирование слов внутри кода. Если эти слова стабильны, внешние изменения причиняют гораздо меньше вреда.
Где команды обычно ошибаются
Команды попадают в ловушку, когда позволяют каждой новой интеграции переименовывать их внутренний мир. Партнёр называет клиента «account», другой — «organization», и вскоре код следует за обоими. Через несколько раундов одна бизнес-концепция получает три имени, и каждое обновление API проливается в модели, тесты, отчёты и заметки поддержки.
Другая, ещё более распространённая проблема: одно слово означает разное для разных людей. Продукт называет «order» покупку пользователя. Инженерия видит в «order» последовательность шагов в рабочем процессе. Поддержка ищет «order» как счёт-фактуру, по которой удобно искать. Команда думает, что договорилась, потому что использует одно слово. На самом деле — нет.
Такая путаница быстро распространяется. Кто-то меняет ярлык в приложении и обновляет несколько классов, но документация всё ещё использует старое имя. Шаблоны поддержки держат старую формулировку. Дашборды аналитики используют третье имя, потому что никто не хочет ломать отчёты. Потом приходит баг-репорт, и три команды тратят полчаса, чтобы понять, говорят ли они вообще об одном и том же.
Команды также меняют имена слишком резко. Удалили старое имя в понедельник, внесли новое во вторник и ждут, что все сразу подстроятся. Это обычно создаёт больше хаоса, чем исходное переименование. Короткий период перекрытия работает лучше: держите старое и новое имена рядом, отметьте одно как устаревающее и дайте людям время обновить код, документацию и привычки.
Худшие случаи — это отсутствие единого источника правды. Правила именования живут в чатах, комментариях к тикетам и в головах людей. Стартап может решить, что «workspace» теперь значит «client account», но если это решение останется в Slack, пол-репозитория будет всё ещё говорить «workspace» в следующем месяце. Новички учат неправильный термин из старых файлов и дублируют ошибку.
Накопление дрейфа легко заметить на ранних стадиях. Каждая новая интеграция вызывает внутренние переименования. Продукт, инженерия и поддержка по-разному определяют одно и то же существительное. Старые и новые ярлыки живут рядом без правил. Споры по именам решают поиском в чатах вместо чтения одной общей записи.
Большинству команд не нужен громоздкий процесс. Им нужен один маленький глоссарий, одно чёткое значение на термин и короткий период перекрытия при смене имени.
Быстрая проверка перед релизом
Релиз — плохое время обнаруживать, что два человека используют одно слово для разных вещей. Десятиминутный обзор может это заметить.
Выберите самого нового участника команды и попросите объяснить каждое основное бизнес-слово простыми словами. Если он сомневается или двое дают разные ответы, термин ещё расплывчат. Эта неясность попадёт в обработчики, таблицы, события и документацию.
Держите предрелизную проверку простой:
- Каждое основное слово соответствует только одному бизнес-значению?
- Оставили ли вы имена вендоров на границе системы, а не в доменном коде?
- Записал ли кто-то, что изменилось, когда это случилось и какое старое имя ещё существует в период перекрытия?
- Если два имени должны жить рядом пару релизов, корректно ли работают чтения, записи, логи и аналитика?
Небольшой пример показывает, почему это важно. Платёжный провайдер переименовал trial_end в grace_period_end. Ваша команда всё ещё говорит о пробном периоде. Хороший код хранит «trial» внутри приложения и переводит поле провайдера в одном адаптере. Плохой код распространяет новое имя провайдера по сервисам, джобам и дашбордам.
Малые команды часто пропускают это, думая, что все уже знают язык. Именно тогда накапливается дрейф. Если один человек может объяснить термин, одна запись фиксирует изменение, а один адаптер обрабатывает внешние имена, то откат и выпуск пройдут безопасно.
Как стабильный язык помогает всей команде
Когда команды сохраняют одни и те же бизнес-термины внутри кодовой базы, ежедневная работа становится тише. Меньше встреч превращаются в споры об именах. Меньше тикетов перескакивают между поддержкой, продуктом и инженерией из‑за разных значений одного и того же слова.
Документация становится более надёжной. Если код говорит «customer», документация API и ответы поддержки тоже используют «customer», — люди быстрее понимают систему. Они перестают тратить время на выяснения, означают ли «account», «organization» и «workspace» одно и то же или это три разные вещи.
Малые команды ощущают эффект быстрее. Поддержка пишет более понятные ответы, потому что язык продукта совпадает с кодом. Продажи перестают обещать одно, а продукт показывать другое. Инженеры оценивают работу с меньшей долей догадок, потому что имена не меняются в середине спринта. Рефакторинги становятся меньше, потому что команды сначала меняют адаптеры, полезет и текст UI, а уже потом трогают ядро модели.
Планирование тоже улучшается. Если фича начинается как «team billing», а потом превращается в «organization billing», оценки обычно ломаются по простой причине: никто не понимает, к какому объекту это относится. Один разработчик думает, что это принадлежит группе пользователей, другой — что это юридическое лицо, а поддержка считает, что это сопоставимо с платным планом. Код следует этой путанице.
Стабильный внутренний язык решает проблему на ранней стадии. Вы можете переименовывать поля на краю, сопоставлять старые термины с новыми и держать бизнес-модель стабильной внутри приложения.
Это особенно важно в маленьких продуктовых командах, где один человек за день делает продукт, поддержку и доставку. Если команда выберет одно имя и защитит его, передачи станут проще. Бэклог читается лучше. Документация API перестанет уходить от продукта. Когда изменения приходят, они попадают сначала на границу, а не раскалывают всю кодовую базу.
Следующие шаги для маленькой команды
Вам не нужен полный рефакторинг, чтобы это заработало. Выберите один поток, который уже вызывает путаницу, и приведите в порядок язык вокруг него. Регистрация, биллинг и заказы — хорошее место для начала, потому что мелкие ошибки в именах там быстро распространяются в поддержку, документацию и API.
Используйте практическое правило: исправляйте те термины, которые отнимают у вас время каждую неделю. Если продукт говорит «customer», поддержка — «account», а код — «user», люди тратят энергию на перевод вместо того, чтобы строить. Выберите одно внутреннее имя, держите его стабильным и переводите внешние ярлыки на границе.
Хороший первый проход прост: выберите один проблемный поток, перечислите слова, используемые в продукте, коде, API и БД, затем выберите одно внутреннее имя для каждой бизнес-концепции. Переименуйте самые болезненные конфликты сначала и запишите сопоставления в короткой заметке для команды. Этого достаточно, чтобы начать. Цель не в идеальном именовании в первый день — цель — остановить появление новой путаницы с каждым новым фичером.
Малые команды получают наибольшую выгоду, когда проверка имен становится частью планирования, а не уборкой, которую никто не планирует. Когда продукт и инженерия обсуждают фичу, потратьте пару минут на три вопроса: как это называется в бизнесе, как это называется в коде и что увидят внешние системы? Эта короткая проверка может предотвратить недели дрейфа.
Биллинг часто демонстрирует проблему особенно ясно. Команда может использовать «plan», «subscription» и «contract» для одной и той же идеи в зависимости от того, кто писал фичу. Потом приходит изменение API, и все спорят о смысле, прежде чем кто-то тронет код. Стабильные внутренние имена делают такие изменения гораздо дешевле.
Если после первого прохода сопоставление всё ещё кажется спутанным, короткий обзор с Олегом Сотниковым может помочь распутать язык домена, границы API и более широкие CTO-решения по ним. Внешний взгляд часто быстрее, чем ещё месяц исправления имён по одному.
Начните с малого, держите внутренние слова стабильными и защищайте их при каждом изменении продукта.
Часто задаваемые вопросы
Что означает версионирование языка домена?
Это значит: внутри кода вы храните по одному устойчивому имени для каждой бизнес-концепции, даже если партнёры, поставщики или тексты интерфейса используют разные слова. Смысл версионируют аккуратно, а внешние ярлыки переводят на границе системы.
Зачем это делать до версионирования API?
Потому что формулировки меняются чаще, чем бизнес-правила. Если сначала защитить внутренние термины, переименование провайдера или правка копирайта останется в адаптере, а не распространится по моделям, тестам, отчётам и документации.
Как отличить переименование от реально новой сущности?
Спросите, появилось ли у сущности новое поведение: другие правила, иные права доступа, отличающийся учёт в отчётах или иная цена. Если ничего этого не изменилось, скорее всего это переименование, а не новая концепция.
Где должны жить термины поставщиков и партнёров?
На границе системы. Сопоставляйте поля типа payer_id или current_price_id один раз в маппере запросов, сериализаторе или адаптере, а в остальной части приложения используйте свои доменные термины.
Как маленькая команда может начать без большого процесса?
Начните с одного запутанного потока: биллинг, регистрация или заказы подойдут. Запишите используемые слова, выберите одно внутреннее имя для каждой бизнес-идеи и положите короткое определение в репозиторий.
Как долго хранить старые имена при переименовании?
Держите старое и новое имя рядом на короткий, запланированный период. Поставьте дату удаления для старого ярлыка и назначьте ответственного, чтобы оба термина не висели годами.
Что делать, если одно слово означает разное для разных команд?
Остановитесь и опишите каждое значение простыми словами. Если продукт, поддержка и инженерия используют одно слово для разных вещей, выберите разные термины и применяйте их последовательно в коде и документации.
Это действительно упростит повседневную работу?
Да. Устойчивые термины сокращают количество шумных переименований: имена в тестах, дашбордах, админках и макросах поддержки меньше расходятся. Новым сотрудникам читать код проще, когда одна концепция имеет одно имя.
Что стоит проверить перед выпуском?
Короткая проверка имён перед релизом. Попросите новичка объяснить ключевые бизнес-термины простыми словами; если он сомневается или ответы различаются, исправьте формулировки до релиза.
Когда стоит попросить внешнего CTO посмотреть?
Привлекайте внешнего CTO, когда та же проблема с именами постоянно возвращается через продукт, API и поддержку. Короткий внешний обзор часто быстрее и эффективнее чем месяц поштучного патчинга терминов.


