Виммельбух, 3, перетяжка
Виммельбух, 3, перетяжка
Виммельбух, 3, перетяжка

IInterface — нужен ли префикс I в названиях интерфейсов?

Исследование на тему: кто и для чего придумал префикс I в названиях интерфейсов. Увлекательное путешествие в историю программирования.

309 открытий4К показов
IInterface — нужен ли префикс I в названиях интерфейсов?

Предыстория

Наверное каждый разработчик на Typescript сталкивался с тем, что в некоторых источниках информации перед названием интерфейса ставится префикс I, например: IUserINews. В начале своей карьеры я какое-то время подражал авторам (ведь они точно знают, что делают, раз публикуют обучающие материалы). Казалось бы, если добавить префикс, мы сделаем код более понятным, ведь уже из названия видно, что тут мы имеем дело с интерфейсом. Но меня не покидало чувство, что в таком подходе к наименованию идентификаторов нет системы: почему только интерфейсы? Почему к названию типов мы не добавляем префикс T, к объектам О и т.п.? Да и вроде без префикса I не возникает трудностей в понимании, что мы имеем дело с интерфейсом. В итоге я перестал добавлять I к названиям интерфейсов.

Еще раз к этому пришлось вернуться, когда мы с коллегами стали прорабатывать соглашения между разработчиками. Я настаивал на том, чтобы не использовать префиксы обозначающие типы данных в названиях идентификаторов, и в тот момент задумался, а прав ли я? Каковы были причины появления такого способа наименования? Может быть от меня что-то ускользает? Тогда-то я и решил разобраться и найти ответы на поставленные вопросы.

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

  • в названии переменной sClientName s — это обозначение типа данных string,
  • в bIsEmpty b обозначает boolean,
  • в TObject T обозначает type,
  • в IDispatch I обозначает interface.

При этом вопрос: «Какую проблему решает данный способ именования идентификаторов?» — остается открытым. Ведь в современной разработке мы используем умные редакторы, IDE, которые выделяют разными цветами различные сущности, а также при наведении показывают подсказки, в том числе о типе данных. И кажется, что нет необходимости хранить тип данных в названии переменной.

История

Венгерская нотация получила такое название благодаря ее создателю Чарльзу Симони (венг. Simonyi Károly), имеющему венгерское происхождение. Произношение именованных предложенным им способом переменных вызывало трудности у его коллег и напоминало родной для Чарльза венгерский язык, поэтому вскоре за соглашением закрепилось название «Венгерская нотация». Для понимания предпосылок разработки определенного способа именования идентификаторов следует сказать, что Чарльз Симони начинал работать в Microsoft во время первых версий MS-DOS.

Для справки

Роберт Мартин в своей книге «Чистый код. Создание, анализ и рефакторинг», описывая причины возникновения Венгерской нотации, напоминает нам, что в те дни компиляторы не поддерживали проверку типов, и программистам были нужны «подсказки» для понимания, с каким типом данных они сейчас работают, в особенности при разработке системного API.

При дальнейшем изучении темы открывается очень примечательный факт — существует 2 типа Венгерской нотации.

  • Системная Венгерская нотация (Systems Hungarian notation) — префикс представляет фактический тип данных идентификатора. То, что мы привыкли называть Венгерской нотацией.
  • Венгерская нотация приложений (Apps Hungarian notation) — префикс содержит семантическую информацию, «функциональный тип» идентификатора. То, что действительно предлагал Симони.

Apps Hungarian notation — такое название получила оригинальная Венгерская нотация, когда использовалась в Microsoft в подразделении приложений, в котором работал Чарльз Симони. Systems Hungarian notation использовалась же разработчиками Windows. Скорее всего Systems Hungarian notation появилась в результате ошибки, непонимания сути того, что предлагал Чарльз.Авторы документации в команде Windows увидев в статье Чарльза Симони, посвященной Венгерской нотации, слово тип, интерпретировали его буквально, несмотря на дальнейшие разъяснения автора. На сегодняшний день команда разработчиков Windows API отказалась от использования Systems Hungarian notation. Так, в статье, рассказывающей о соглашениях по написанию кода в Windows, в примечании прямо об этом сказано: «Internally, the Windows team no longer uses it. But its use remains in samples and documentation.» (Внутри команда Windows больше не использует её. Но примеры ее использования остаются в коде и документации.)

Во время разработки системы соглашений именования идентификаторов Чарльз Симони пытался решить встающие перед любым программистом проблемы, когда тот пытается придумать название переменной:

  1. идентификатор должен иметь мнемоническое значение, чтобы можно было легко запомнить имя;
  2. понятное, ассоциативное (suggestive) значение, чтобы другие могли понимать код;
  3. «консистентность» — часто рассматривается как эстетическая идея, но также несет смысловую нагрузку. Грубо говоря, мы хотим похожие названия для похожих сущностей;
  4. скорость принятия решения - мы не можем тратить слишком много времени на размышления о названии одного идентификатора, а также нет времени на ввод и редактирование чрезвычайно длинных имен переменных.

Больше контекста

Прежде чем рассказать о моих выводах из проведенного исследования, хочу познакомить читателя с Джоэлом Спольски (англ. Joel Spolsky) и его статьёй «Making Wrong Code Look Wrong».

В начале своей карьеры Джоэл поработал в команде Excel, затем в 2000 году стал соучредителем Fog Creek Software — компании создавшей много крутых продуктов, таких как FogBugz, Trello и Glitch. Также Джоэл работал над созданием Stack Overflow и занимал должность генерального директора Stack Overflow с 2010 по 2019 год. Сейчас является председателем совета директоров Glitch и соучредителем вместе новой компании под названием HASH.

Теперь можно вернуться к статье, т.к. компетенция автора не должна вызывать вопросов. Джоэл вывел 4 этапа развития навыка написания качественного кода у программиста:

  1. не отличает чистый код от грязного,
  2. имеет поверхностное представление о чистом коде, в основном на уровне соответствия принятым соглашениям,
  3. замечает потенциально проблемные места в коде и исправляет их,
  4. специально пишет код так, чтобы неправильный код выглядел неправильно, т.е. сам придумывает соглашения - самый высокий уровень, которому и посвящена статья.

Идея Джоэла заключается в том, чтобы, добавляя к идентификаторам метаданные, писать код так, чтобы ошибки обнаруживались уже при написании. В качестве примера в статье приводится имя переменной usName,где us означает unsafe (не безопасное). В то время как sName означает безопасное имя. Читая в коде названные таким образом переменные легко понять, с какими данными мы сейчас работаем, и легче заметить ошибку. Например, когда мы на бэкенде получаем данные от пользователя, нам важно помнить о сериализации, и было бы хорошо отличать сериализованные данные от не сериализованных.

По большому счету то, что предлагает Джоэл Спольски — это Apps Hungarian notation, только рассмотренная под другим углом.

Используемый в статье Джоэла пример названия идентификаторов как usName и sName решает все 4 задачи программиста обозначенные Чарльзом Симони. Ведь если в соглашениях команды зафиксировать, что значат префиксы s и us, то:

  1. будет легко запомнить что sName значит безопасное имя, а usName - не безопасное;
  2. при чтении кода не возникнет проблем, так как все будут понимать, что префиксы -  это сокращения от safe и unsafe;
  3. эти же префиксы могут и должны применяться к данным из других полей формы, например sEmail или usPassword;
  4. разработчику не нужно долго думать над названием переменной, ведь часть названия уже унифицирована.

Приведу пример из фронтенда. Называя кнопку отправки данных формы SubmitButton, текст кнопки submitText, функцию-обработчик события отправки данных — submitHandler мы следуем правилам Apps Hungarian notation. Добавив к идентификаторам префикс submit, мы тем самым обозначили, что они связаны между собой. И если в коде мы увидим, что событию нажатия на кнопку сброса формы назначено событие onSubmit, то мы сразу поймем что тут ошибка. Как советовал Джоэл: неправильный код выглядит неправильно. 

			<ResetButton onClick={submitHandler} />
		

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

Выводы

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

Основные минусы Systems Hungarian notation, которые упоминают разработчики, сводятся к списку:

  • при смене типа придется переименовывать идентификатор везде, где он используется, что добавляет вероятность возникновения ошибки;
  • кодирование имени усложняет чтение;
  • бессмысленность применения, ввиду степени развития поддержки языков в современных IDE.

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

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

Следите за новыми постами
Следите за новыми постами по любимым темам
309 открытий4К показов