Делай нейминг как сеньор

в 7:50, , рубрики: dodoengineering, dodopizzaengineering, Анализ и проектирование систем, Блог компании Dodo Engineering, нейминг, Программирование, Совершенный код, управление разработкой, чистый код
Делай нейминг как сеньор - 1

В чём разница между сочинением третьеклассника и статьёй в крупном таблоиде? Любой из нас сходу определит, что есть что. Даже если оба текста описывают одно и то же событие. А чем отличается код сеньора от кода мидла?

Разница в мелочах. В мелочах, которые при взгляде сверху дают совершенно другую картину. Лид статьи от профессионального редактора притянет внимание, структура и ход повествования доведут нас до последнего абзаца. Наш взгляд не споткнётся, мы буквально пролетим по тексту, улавливая суть каждого предложения. Так же и код сеньора нам покажется незамысловатым, словно прописные истины. Мы почти не приложим усилий, чтобы понять его. Невозможно написать качественный, читаемый, поддерживаемый код без навыка давать хороший нейминг. 

Нейминг — часть архитектурной работы. Наименования классов и переменных мигрируют в названия таблиц баз данных, улетают с событиями, проникают в другие системы через API. Проще сменить имя в паспорте, чем исправить контракт, который имеет тысячи использований. Ошибки в нейминге быстро масштабируются, увеличивая сложность системы на ровном месте. Зачастую их исправление стоит колоссальных усилий и средств. Не стоит забывать про документацию, тест-кейсы, аналитику.  

Что касается самого кода, то это отражение того, как мы поняли предметную область. Понимание предметной области, её задач и проработка решений — это то, что делает инженер в IT. Чтобы отразить предметную область, мы используем нейминг, даже если специально об этом не задумываемся.

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

Второй проблемой является отсутствие под рукой лёгких инструментов, чтобы быстро и понятно называть, каких-то простых приёмов. И в этой статье я поделюсь такими приёмами. Здесь не будет очередной теории нейминга, которую нужно разбирать и доносить до коллег. Я описываю простой процесс, позволяющий одинаково понимать домен, а все инструменты вы сможете использовать сразу же после прочтения. Их эффективность оказалась для меня поразительной — надеюсь, вы испытаете те же чувства, когда примените в своей команде.

Распространённые ошибки

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

Название переменной ничего не говорит о её предназначении

let data = {} // FIXME rename to requestPayload
let n = 1; // FIXME rename to startIndex
let var1 = "Something"; // FIXME rename to eventName
let value = {...data}; // FIXME rename to user
let array = [var1]; // FIXME rename to firedEvents
let info = var1 + " happened"; // FIXME rename to alertMessage

Переменная — это какие-то данные, какое-то значение, но не стоит её так и называть. Конкретизируйте. Что за значение мы хотим в ней хранить? Так и назовём переменную. Даже если мы пишем дженерик, то можно дать более конкретное название.

Избыточные названия

const addedDateTime = new DateTime(); // FIXME rename to addedAt
const basket = {
	basketId: 0, // FIXME rename to id
    items: []
}

В название добавляется тип переменной или избыточный префикс названия объекта. В итоге мы читаем код как «добавлено дата время» или «корзина — айди корзины». Код должен читаться без таких запинок «добавлено в 12:00», «корзина: айди: 4, элементы: […]».

Названия без контекста

const user = {
	id: 11,
	source: "linkedin", // FIXME rename to leadSource
	state: "Philadelphia", // FIXME rename to countryState
	status: "unemployed" // FIXME rename to employmentStatus
}

Только благодаря значениям  мы поняли, что за source имеется в виду, в каком смысле употреблены state, status. Без значений всё усложняется — придётся отвлекаться и уточнять, о чём идёт речь.

Неправильный перевод

public enum TravelMode // FIXME rename to TransportType
{
	Driving = 0, // FIXME rename to Vehicle
	Walking = 1, // FIXME rename to OnFoot
	Bicycling = 2 // FIXME rename to Bicycle
}

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

Калька со своего языка

var orderHandoverTime = {
	preparationTime: 651, // FIXME rename to cookingTime
    heatedShelfTime: 30,
	pizzeriaId: 3, // FIXME rename to unitId
}

var staffMember = {
	id: 52,
	medicalBookEnd: false, // FIXME rename to isHealthPermitExpired
	INN: "" // FIXME rename to taxIdentificationNumber
}

var employeeDinner; // FIXME rename to staffMeal
var salary; // FIXME rename to incentives

Иногда в русском одно и то же слово может обозначать разные объекты или действия, но в английском нет. Более того, некоторые заимствованные слова обрели разный смысл. Самым популярным примером может быть пара магазин — magazine. Смысл слов совпадает, если мы говорим про магазин к винтовке, но магазин с товарами мы уже переведём как shop (здесь стоит отметить, что magazine является заимствованием для обоих языков).

В примере разработчик перевёл «приготовление» как preparation, хотя речь о готовке еды. Ошибки можно избежать, если подобрать синонимы. Более специфичное слово «готовка» показало бы точный перевод.

Отдельной темой стоит бизнесовая или нишевая терминология, перевод которой совсем не прост. Гугл-транслейт, с большой вероятностью, приведёт нас не к тем переводам. Например, то, что мы называем «зарплата», в других странах даже формулируется иначе. В общем случае это «вознаграждения». 

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

Недостаточно точный термин

var avgWaitingTime = 2000; // FIXME rename to avgHeatedShelfTime
var avgServiceTime = 5000; // FIXME rename to avgDeliveryOrderFulfillmentTime
var avgDeveliryTime = 3000; // FIXME rename to avgOrderTripTime
var orderType: "restaurant" // FIXME rename to salesChannel
                			// also rename "restaurant" to "Dine-in"

Здесь мы видим неудачный нейминг в области с метриками времени у доставки заказов. В каждой строке возникают уточняющие вопросы «время ожидания чего?», «в какой момент отсчёт этого времени начался и в какой закончился?», «сервисное время? что имелось в виду?», «доставка — это от момента приёма заказа или от момента его готовности?». Такой нейминг порождает баги. Не все дотошно выясняют точное назначение каждой переменной.

Как правило, такой нейминг возникает от низкой погружённости в предметную область. Все мелкие нюансы выясняет инженер: от какого момента считать время на тепловой полке, от какого момента считается время доставки и тд.

Отдельный разговор про orderType. Один и тот же объект можно характеризовать с разных сторон. Заказ может быть отложенный или требующий немедленного приготовления, может быть отменённый или доставленный вовремя. Type может обозначать что угодно, лучше конкретизировать.

Абстрактные названия

var unitDeliveryEfficiency = {
	onePerTaskRate: 2, // FIXME rename to tripsWithOneOrderCount
	twoPerTaskRate: 4, // FIXME rename to tripsWithTwoOrdersCount
	threePerTaskRate: 0, // FIXME rename to tripsWithThreeOrdersCount
    fourPerTaskRate: 1, // FIXME rename to tripsWithFourOrdersCount
    morePerTaskRate: 0 // FIXME rename to tripsWithFiveOrMoreOrdersCount
}

По названию свойств сложно догадаться, о чём идёт речь. Почему бы не назвать свойства именем метрики, которую они несут? Не нужно придумывать лишние обозначения, которые не применяются в реальной жизни.

Но проблемный нейминг создал здесь ещё один прецедент — внимание на последнее свойство в объекте. Мы решили группировать те редкие случаи, когда курьер берёт более 4 заказов в одну поездку. Если чуть-чуть изменить наши правила, например, добавить поездки с 5 заказами, то все метрики поедут. А такую ошибку совершить очень просто, ведь название свойства ни к чему не привязано. 

На этом проблемы не закончились. Разработчик пошёл дальше и вывел на UI метрику в колонку «Более 4 заказов за поездку». «Более 4» — это 5. Надо так и писать: «5 и более заказов за поездку». Это лишнее действие в уме для разработчика и пользователя, которое появилось в результате такой ошибки.

Несколько вариантов для одного термина

В нашей системе можно встретить варианты нейминга одних и тех же терминов.

Заведение: Pizzeria, Restaurant, Store, **Unit**
Самовывоз: Pickup, **Takeaway**, Carryout
Заказ в ресторан: Stationary, **Dine-in**, Restaurant
Выручка: **Sales**, Revenue
Управляющий: **StoreManager**, Manager, Supervisor
Чек: Check, Cheque, Receipt

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

Игнорирование конвенций нейминга языка программирования или компании

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

Нейминг — это понимание предметной области

Представим, что наш домен — хирургический набор. Это сейчас он аккуратно разложен перед нами на изображении ниже. Мы можем учесть все предметы и спроектировать домен. Мы не бросимся орудовать термином scissors налево-направо, так как понимаем, что ножниц много, они предназначены для разных операций. У нас будет всё так, как в жизни: BandageScissors, DissectingScrissors и так далее.

Набор хирургических инструментов.
Набор хирургических инструментов.

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

 проблемы с неймингом → проблемы с пониманием предметной области.

Плохой нейминг — это работа, оставленная на потом. В моменте мы не уделили ему достаточно внимания, значит, будем уделять его потом — каждый раз, когда придётся работать с кодом или другими артефактами. Это похоже на захламлённую комнату. Подходя к неймингу несистемно, мы увеличиваем беспорядок. И нам становится всё сложнее ориентироваться, придётся держать много особенностей в голове.

Выведем остальные следствия плохого нейминга: 

требуется больше усилий → больше вероятность ошибки;

увеличивается энтропия → код сложнее поддерживать;

разработка идёт медленнее и труднее с нарастающим итогом.

Помимо прочего, так мы тратим собственные когнитивные ресурсы на ориентирование в коде. Тут дело даже не в эффективности. Это бесполезно упущенные время и энергия, которые нам ничто не компенсирует. И эти потери драматичны, поскольку неудачный нейминг прописывается единожды, но проявляет себя многократно и замедляет каждого, кто с ним сталкивается.

Как выстроить работу с неймингом в команде

Перед нами новый проект или уже существующий, которым мы плотно займёмся. До того как мы распишем нейминг, нужно погрузиться в предметную область. Для этого есть разные инструменты: от простого интро или экскурсии на производство до Event Storming или совместного составления User Story Map. Понять предметную область для инженера критически важно. Возможно, вы не раз слышали утверждение, что разработчик точнее знает бизнес-процесс, чем эксперт из бизнеса. Именно потому, что он его не только представляет, но и реализует до мельчайших подробностей. И каждый новый участник команды должен проходить погружение.

После погружения нужно составить словарик. В парадигме DDD это будет Ubiquitous Language. Для составления словарика собирается встреча — максимально все, кто будет участвовать в работе над проектом. Важнейшим критерием должно быть то, что в группе есть и бизнес, и технические эксперты. Драйвит составление словарика и его владение технический эксперт. Примерный состав группы:

  • менеджер продукта,

  • разработчик,

  • инженер по качеству,

  • дизайнер,

  • аналитик,

  • стейкхолдер,

  • эксперт со стороны бизнеса.

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

Во время встречи происходит выравнивание картины у всех участников. На нашей практике обнаружилось, что даже у разработчиков одной команды, которые не первый месяц поддерживали продукт, было совершенно разное понимание одних и тех же вещей. Мы были очень рады, что заранее всё это проговорили. Помимо синхронизации на поверхность всплывает множество мелких деталей и вопросов, которые были в голове у кого-то одного, но теперь будут вписаны в общую картину. Более того, мы впервые можем показать бизнесу то, что собираемся делать, ещё не сделав ничего! Наше видение будущей системы уже может быть сопоставлено с ожиданиями стейкхолдеров. Для представителей бизнеса важно и интересно быть вовлечёнными в создание продукта, которым они же и будут пользоваться, который станет их активом.

Так выглядит словарик после нескольких встреч с командой
Так выглядит словарик после нескольких встреч с командой

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

Что делать, если идёт тяжело, термины для словарика не генерируются? Во-первых это нормально. Работа над неймингом — это часть архитектурной работы. Размышляя над терминами и их значением, мы прикидываем архитектуру нашей системы. Опыт тоже играет роль. Но, как правило, это показатель слабой погружённости в предметную область. Погрузитесь сильнее, выясните больше деталей.

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

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

Для перевода мы не пользуемся гугл-транслейтом. Наши инструменты:

Если вам сложно выбрать из двух-трёх терминов, вбивайте в поиск термины как в примере: staff member vs employee и вы попадёте на форумы, где носители языка помогают разобраться с контекстом употребления.

Глоссарий с переводами бизнес-терминов.
Глоссарий с переводами бизнес-терминов.

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

Следующий шаг — это контроль, за это отвечает код-ревью. В процессе код-ревью по неймингу учитываем следующее:

  • верифицируем все новые термины;

  • смотрим на нейминг так, словно вы никогда не работали с этим доменом;

  • из названия должно быть сразу понятно, что это;

  • у термина не должно быть нескольких трактовок.

Как это назвать? Практические советы

Давать наименования — это навык, и на старте может быть сложно. Однако есть два простых правила, которыми можно пользоваться всегда:

  1. Отталкивайтесь от значения. Выпишите его. Как бы вы это назвали? Начните с русского наименования. Совместите значение и название — должно звучать складно, без лишних слов, на которых «спотыкаешься» — как человеческая речь.

  2. Не можете назвать лаконично — назовите предложением, потом сокращайте:

Количество заказов на курьера в час 
→ ordersCountPerCourierPerHour 
→ ordersPerCourierLabourHour

Пример. Назовём массив с объектами. Для начала просто выпишем структуру:

стоп-продажи по причине нехватки ингредиентов:
- ингредиент, из-за которого остановлены продажи: халапеньо
- продажи были остановлены в: 2023-01-05T10:00
- остановка продаж закончилась в: 2023-01-05T15:00
- сотрудник, который остановил продажи: Мельников А.
- сотрудник, который возобновил продажи: Мельников А.
- точка продаж: Сыктывкар-1

Теперь переведём:

var stopSalesByIngredients = [{
	ingredientName: "jalapeno",
	startedAt: "2023-01-05T10:00",
	endedAt: "2023-01-05T15:00",
	staffNameWhoStopped: "Melnikov A.",
	staffNameWhoResumed: "Melnikov A.",
	unitName: "Syktyvkar-1"
}]

Дополнительные советы, которые помогут сделать нейминг лучше

  1. Явное > неявное. Отвлекитесь на секунду и представьте, что прошёл год. Пронеслась череда событий и вы снова вернулись к этому коду. Вспомните ли вы все нюансы, которые не отразили в названии? Представьте, что видите этот код в первый раз и что не выясняли с болью всякие мелкие особенности, которые могут скрываться за этой конструкцией. Например, переменная содержит время окончания всего цикла или только какой-то стадии цикла. Укажите это явно в обоих случаях. Сколько возможностей для багов можно посеять, если не уточнить и оставить загадку другому разработчику или даже самому себе!

  2. Не стремитесь называть максимально коротко. Нейминг из 3-4 слов — это нормально. Передать конкретику одним словом, чаще всего, нельзя.

  3. Одна переменная — одна цель. Например, вы хотите записать дату и время окончания смены и одновременно по этой же переменной понимать, закончилась ли смена. Никогда так не делайте! Только явное обозначение в другой булевой переменной. ShiftEndedAt, IsShiftEnded.

  4. Отрицание только усложняет, а также это пример неявного поведения. Используйте явные наименования. Не «недоступно», а «доступ запрещён».

  5. Вырабатывайте единую структуру. Например, используйте одинаковые суффиксы и префиксы:
    Avg, Count, Percentage, Total, At, Name
    unitName, productName
    tripsDuration, couriersShiftsDuration

  6. Используйте глаголы или прилагательные для уточнения контекста:
    addedIngredients, removedIngredients, lateOrdersCount

  7. Стандартизируйте нейминг для времени. Если система фиксирует какое-то событие, то используйте глагол в прошедшем времени + суффикс At: happenedAt, startedAt.
    Если по умолчанию храните время в UTC (что рекомендуется делать), а в контракте отдаёте локальное, то добавляйте ещё один суффикс Local: happenedAtLocal.

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

Что делать с легаси

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

Но если мы приходим всерьёз и с большими задачами на легаси, то:

  1. Составляем словарик с новой единой терминологией.

  2. Делаем фасады для всего нового кода, чтобы локализовать область, где останется старый нейминг.

  3. Применяем правило бойскаута — каждый раз понемногу рефакторим нейминг.

Как работать с возражениями

Нам так удобнее называть, нам такие названия понятны.
Я не эксперт в бизнесе, а задачу надо делать сейчас.
Так уже было в проекте.
Проверил в Google Translate, там такой перевод.
Это не так важно, главное качество кода.

Я придерживаюсь мнения, что в IT нет правильных или неправильных решений. Мы стремимся выбирать оптимальное, исходя из наших возможностей и обстоятельств. Порой срезание углов делается преднамеренно, например, когда у нас каждый час на счету и мы готовы потом разгребать все долги. Здесь я сошлюсь на Technical Debt Quadrant Фаулера. Сложно в двух словах объяснить коллегам важность работы с неймингом, особенно если это не тема встречи и об этом раньше сильно не задумывались. Но если мы понимаем, что их аргументы попадают в область Reckless Deliberate (преднамеренное безрассудство), то соглашаться с ними, конечно, не стоит, и начать разговор нужно именно с этого.

Квадрат технического долгаИсточник — https://martinfowler.com/bliki/TechnicalDebtQuadrant.html
Квадрат технического долга
Источник — https://martinfowler.com/bliki/TechnicalDebtQuadrant.html

Ещё одна рекомендация — не обсуждайте нейминг текстом (во время ревью или составляя словарик), старайтесь делать это синхронно. Иначе это вымотает всех.

Как объяснить ценность бизнесу

Зависимость скорости выпуска фич от техдолгаИсточник — https://martinfowler.com/articles/is-quality-worth-cost.html
Зависимость скорости выпуска фич от техдолга
Источник — https://martinfowler.com/articles/is-quality-worth-cost.html

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


Язык определяет мышление — так формулируется гипотеза лингвистической относительности. Выше мы разбирали проблемы и решения, которые вытекают из этой простой формулировки. К современному инженеру предъявляются гораздо более высокие требования по коммуникативной грамотности, чем к инженерам ещё несколько десятилетий назад. И в IT это особенно чувствуется, ведь всё, что мы делаем — это текст. Осознание значительной гуманитарной составляющей в профессии инженера существенно изменило мой подход к делу.

Конечно, чтобы «третьекласснику» дорасти до «редактора» нужен не только навык крутого нейминга. Мелочи, из которых складывается общая картина, разбросаны по множеству книг, статей, проектов. Однако чистый и понятный код даёт уже очень много. Ещё больше про мелочи в коде рассказывает Роберт Мартин в книге «Чистый код». Если вы ещё не открывали эту книгу или делали это давно, то сейчас самый подходящий момент.

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

Автор: Арсений Мельников

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js