Как бы это назвать: принципы хорошего именования в базе кода
Хорошие названия внутри базы кода действительно имеют огромное значение. Давать классам и методам правильные имена становится все сложнее и сложнее по мере того, как растет база кода. Похоже, что все в той или иной мере сталкивались с проблемой именования, но я никогда не встречал даже попытки решить эту проблему. Конечно, нельзя просто решить ее один раз за всех, но в этой статье я хочу поделиться некоторыми принципами, которые помогают подбирать хорошие названия в базе кода моей команды.
Называйте объекты своими именами
Самая простая идея — назвать объекты так, как их уже называют пользователи вашей системы. Например, можно с большой долей уверенности сказать, что где-то внутри базы кода «Твиттера» есть сущность с названием Tweet. Этот принцип звучит просто, однако требует правильного подхода к архитектуре. Если вы все проектируете правильно, то внутри базы кода будут в основном те объекты и сущности, которыми оперирует конечный пользователь. И во многих случаях все они уже имеют сложившиеся названия.
Эта стратегия действует при Object Oriented Design (OOD) подходе. Хороший OOD имеет максимальное количество классов, которыми может оперировать и которые может понять конечный пользователь, и минимальное количество классов, которые он не может видеть. Названия всех объектов, которые видит конечный пользователь, должны диктоваться им самим.
Например, представим, что внутри вашего проекта есть понятия «Article» и «Email». У обоих есть заголовок — header. Но для статьи пользователи назовут его «Title», а для имейла — «Subject». Принцип следования за пользователем требует дать этим заголовкам разные названия на уровне кода, что упростит коммуникацию и уменьшит трудности в общении, которые опишу ниже.
Следует заметить, что это не единственный принцип именования. Может быть несколько причин, по которым вы можете назвать объекты не своими именами внутри кода. Расскажу о них ниже.
Также есть проблема Legacy: по мере развития проекта названия меняются по разным причинам. Однако переименовать объекты в коде не всегда возможно. Иногда приходится создавать таблицы терминов, в которых для каждого актуального термина будет не только описание, но и список его старых Legacy названий.
Не используйте похожие названия, только чтобы упростить
Если вы изобретаете новое понятие, о котором ваши пользователи еще не слышали, постарайтесь дать ему имя, которое еще не использовано. Человек всегда стремится к упрощениям. Поэтому мы часто используем одно название для совершенно разных вещей. Например, «Коса». Мы просто уже все к этому привыкли. Однако если вы назовете объекты одинаковыми именами в своем софте, вам придется объяснять вашим пользователям или разработчикам, что это разные объекты.
Вот пример из жизни. Представим, что в системе пользователям доступны 2 действия: «Subscribe to newsletter» и «Unsubscribe from all email notifications». Поскольку мы имеем обыкновение все упрощать, кому-то может показаться, что эти два действия противоположны друг другу, так как «unsubscribe» противоположно «subscribe». Но это не так — на практике это могут быть независимые действия: например, вы можете быть подписаны на рассылку и не подписаны на прочие оповещения. Или, например, вы не можете быть подписаны на рассылку, если отписались от всех оповещений.
Для того чтобы избежать «автоматического упрощения», вы можете назвать эти действия по разному: «Opt in for newsletter» и «Unsubscribe from all email notification». Таким образом, ошибка станет менее вероятной, поскольку «opt in» не явно противоположно «unsubscribe». Идея в том, чтобы закрепить «opt in» за «newsletter subscription» и «unsubscribe» — для «email notifications».
В ежедневном общении люди говорят очень быстро, сокращая ненужные слова. Это означает, что многие действия будут использованы без описания объекта действия. Например: «How many subscribed people do we have?» будет восприниматься неоднозначно, если «subscribe» будет ассоциироваться и с «newsletter», и с «email notifications».
Разным понятиям давайте разные названия
Начну с хорошего примера путаницы именований в моей команде: в английском языке есть слова «Campaign» и «Company», которые имеют разные значения. А по-русски они звучат одинаково — кАмпания, хотя и пишутся по-разному. В нашем бизнесе используются оба слова, поэтому при разговоре в русскоязычной части команды возникает путаница — «Кампания, то есть маркетинговая кампания» или «Компания, то есть наш клиент». Это ситуация, с которой нам пришлось жить, так как индустрия, в которой мы работаем, уже имеет устоявшиеся названия и для того, и для другого понятия.
Но есть проблемы уникальности имен, которых можно было избежать. Представим, что в проекте есть понятия «WebPageSnapshot» и «ServerSnapshot». Когда члены команды разговаривают быстро, то скорее всего будут использовать слово «Snapshot» для обоих понятий. Это может привести к проблемам понимания. Фраза «I made a patch that touches a snapshot source code, please take a look» неточно определяет, куда именно нужно смотреть. Подобные фразы почти гарантированно будут вести к потере времени, потому что собеседники будут полагать, что понимают друг друга, а на самом деле — не совсем. Или автор, или слушатель в данном случае могут вообще не знать о том, что в системе есть 2 разных вида Snapshot, и для них может быть даже неочевидна неточность высказывания.
Отсюда следует правило: используйте уточняющие слова, чтобы разделять понятия, только если эти понятия имеют одно и то же значение на каком-то уровне абстракции. Например, «VideoFile» и «ImageFile» — оба просто «File» на более обобщенном уровне. Другими словами, VideoFile и ImageFile имеют общее поведение и код, который их обрабатывает или реализует. Если такой общности нет — нужно дать понятиям совершенно разные имена.
Убедитесь, что сокращенные версии названий удобны
Использование одинаковых уточняющих слов, с другой стороны, может быть хорошей идеей. Давайте рассмотрим бизнес-правило: «„Affiliate Member“ can participate in „Affiliate Campaign“». При таких названиях не будет никакой путаницы. Без уточнений фраза по-прежнему остается понятной: «This member has joined the campaign 2 days ago».
Напротив, бизнес-правило «„Member Affiliate“ can participate in „Campaign Affiliate“» может стать настоящим оружием массового поражения при коммуникации.
Поэтому всегда проверяйте, чтобы сокращенные версии названий были удобны в ежедневном общении.
Используйте длинные или странные названия для внутренних объектов
Под словом «внутренний» я имею ввиду что-то, что невидимо для конечного пользователя.
Во-первых, всегда убеждайтесь в том, что внутренние объекты не забирают хорошие названия у внешних (видимых) объектов. Это очень важно: оставляйте хорошие имена для тех вещей, с которыми ваши пользователи сталкиваются чаще всего.
Во-вторых, лучше дать внутренним объектам более длинные имена. Это помогает передать больше информации об их функции, которая, в отличие от внешних объектов, менее очевидна. Если название внутренних объектов будет коротким, разработчик может полагать, что знает, что делает объект только по его названию, но это не всегда плюс: внутренние объекты выполняют более специфичную, не очевидную работу. Поэтому им стоит давать более длинные описательные названия.
Пример из MVC приложений — UsersController. В данном случае название состоит из двух частей: Users — указание на реальный видимый объект, которым оперирует класс, и общий для всех контроллеров суффикс Controller. И это правильный подход: все контроллеры MVC приложения имеют общее поведение и код. К тому же это внутренние объекты, которые не важны для конечного пользователя. Их названия должны указывать на видимые объекты, связанные с ними.
Иногда уместно дать объекту странное, ничего не значащее имя. Таким образом, каждый посмотрит, что делает этот объект или метод перед его использованием. В моем проекте есть функция, которая называется fuck_short_url(text). В ней больше комментариев, чем строчек кода. Она делает очень специфическую обработку ссылок внутри текста-аргумента, объяснить которую названием невозможно. Для самых любопытных привожу здесь полный исходный код метода.
Выводы
Можно выделить три типа названий по функции:
- Прямое имя — как ваши пользователи называют понятие.
- Описательное имя — длинное и описывающее в большей степени функцию объекта.
- Странное имя — не вызывающее никаких предположений о функции до того, как кто-то не заглянет в реализацию.
И вот несколько принципов именования:
- Используйте имена, уже данные пользователями вашего приложения или сообщества/индустрии в целом.
- Старайтесь соблюдать уникальность названий для несвязанных объектов.
- Связывайте объекты, добавляя одинаковые слова к названиям, только если они действительно связаны по смыслу.
- Избегайте совпадения названий в случае их сокращения.
- Давайте более длинные названия для более сложных объектов.
- Давайте более короткие названия объектам, которые используются часто.