Что в имени? то, что мы называем розой
Любым другим словом пахло бы так же сладко;

Вильям Шекспир

Вы замечали, как некоторые люди небрежно относятся к именам? У меня есть друг, который просто не может (или, возможно, не будет) помнить имена людей, которых он встречает. Это часто приводит к очень неловким моментам, когда ему нужно познакомить их, поскольку он не знает, как эти люди называются. Прискорбная реальность разработки программного обеспечения заключается в том, что значительное число разработчиков придерживаются такого же невмешательства в отношении именования. Мне никогда не удавалось понять людей, которые не обращают пристального внимания на имена, именование - это то, что имеет фундаментальное значение для человеческого мифа и для нас как компьютерных ученых.

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

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

Кодирование, тогда и сейчас

Когда я только начал кодировать, память была крайне дефицитным ресурсом, маленький компьютер ZX Spectrum, который я программировал с помощью ZX-BASIC, имел только 16 КБ ОЗУ. Когда я говорю 16 КБ ОЗУ, я имею в виду всего 16 КБ ОЗУ для хранения программы и данных, а также для рабочего хранилища. Как следствие этого, интерпретатор BASIC разрешил именам переменных иметь только один символ в начале имени, за которым следуют несколько цифр и, наконец, символ $, чтобы пометить его как имя переменной. Это привело к относительно бессмысленным именам переменных, поскольку Q1 $ на самом деле не передает такого большого значения. (это улучшилось в последующих версиях ZX-BASIC).

Когда я перешел на реальный язык, которым был Microsoft C версии 2.0 для DOS, я почувствовал себя раскрепощенным, потому что символы можно было называть как угодно, с именами любой длины и с любым количеством букв и цифр. Конечно, в отличие от сегодняшнего дня, не было переполнения стека, не было Интернета, и у меня не было наставников, которые бы научили меня более тонкому искусству программирования. Поскольку я работал на IBM PC, который содержал (для меня) огромный объем памяти (640 КБ), я вскоре писал действительно большие программы с переменными и функциями, распределенными по десяткам различных исходных файлов. Вскоре у меня возникли проблемы, так как у меня не было стандартов именования и, следовательно, механизма для логической организации моего кода. Вскоре меня осенило, что разработка стандартного способа называть вещи и придерживаться его сквозь все тонкости - это единственный способ преодолеть этот новый вызов. Пока я думал о том, как это сделать, я прочитал статью о технике под названием венгерская нотация. Это включало в себя добавление к именам всех переменных маркеров для обозначения типов значений (впоследствии я понял, что подобный подход неверен, но в тот момент я был в отчаянии). Я ухватился за это, как тонущий, и с тех пор я использовал венгерские обозначения для обозначения всех своих символов. Это помогло, но все еще не решило основную проблему, заключающуюся в последовательном и значимом назывании вещей.

Пока я работал над этой проблемой, у меня было несколько осознаний, которые остались со мной до конца моих лет программирования:

  1. Трудно правильно назвать символы
  2. Стандарт работает, только если вы его придерживаетесь без каких-либо изменений
  3. Длинные имена работают лучше, чем короткие
  4. Я на самом деле правильно называл вещи для себя, а не для других программистов
  5. Ясность важнее краткости
  6. Действительно сложно избавиться от вредных привычек программирования

Я тоже столкнулся с примером кода, в котором использовались бессмысленные имена, такие как lbl, i, j, v, x, и мне потребовались годы, чтобы отучиться от всех вредных привычек, которые я приобрел из списков кодов в журналах и книгах. С годами я разработал конкретные стратегии для решения каждого из этих вопросов. Я разработал эти стратегии специально, чтобы противостоять проблемам, с которыми я столкнулся с моими первыми большими кодовыми базами, и для решения вопросов, которые я изложил выше.

Стратегии именования

Я адаптировал ряд этих принципов из Руководства по дизайну Swift API, поскольку считаю, что они чрезвычайно надежны и воплощают многие принципы, которые я стараюсь использовать.

Назвать сложно, так что делайте правильно

Помимо архитектуры, именование - самая сложная часть написания приложения. Правильное имя делает все проще для понимания, делая имя, лишенное значимого значения (например, использование типов для имен, таких как массив, строка, коллекция), затрудняет усвоение кода для кого-то, кто простужается. Это означает, что нужно приложить значительные усилия, чтобы найти правильное имя для определяемого символа. Если это означает пробовать разные имена, а затем менять их, это то, что нужно делать. Иногда, когда я кодирую правильные имена, просто выпадают по мере ввода, в других случаях я обнаруживаю, что постоянно возвращаюсь к имени и меняю его, потому что внутренне знаю, что имя недостаточно хорошее или недостаточно проясняет ситуацию. . Лень - не оправдание и не выход. Сегодняшние IDE предлагают превосходные инструменты для рефакторинга и переименования - одной из поддерживаемых функций, так что используйте ее.

Добавить ценность в точке использования

Еще один важный момент, о котором следует помнить, - это то, что имя символа должно добавлять значение в момент использования этого символа, а не в точке определения. Если вы подумаете об этой эвристике, то увидите, что она имеет смысл: тип, переменная или метод всегда определяются только один раз, но они используются десятки, если не сотни, а возможно, даже тысячи раз по всей системе. Обычно контекст, в котором определяется символ, делает его цель или роль очевидными, но часто это не тот случай, когда используется символ. Термины искусства (или жаргон) часто могут усложнить ситуацию, потому что то, что сразу становится очевидным для знающего человека, может быть полной загадкой для того, кто не обладает таким же уровнем знаний в предметной области, как исходный кодировщик.

Называйте типы и переменные после их роли, а НЕ их типа

Я знаю, что эта эвристика кажется очевидной, но вы не поверите, как часто я вижу классы, названные по их типу, а не по их роли. Примером неправильного именования является то, что разработчики добавляют суффиксы, такие как класс, объект, строка, модель или bean, на концах своего типа или переменной. имена, просто назовите класс или переменную после того, как они есть. Разработчики назовут класс CreditCardModel или BankBranchModel, тогда как на самом деле это должно быть просто CreditCard или BankBranch. Это модель в силу того, что она моделирует настоящую вещь. Могут возникнуть ситуации, когда вы захотите намеренно добавить суффикс типа к типу, чтобы различать группы типов, например, в вашем приложении могут быть DTO, модели, памятные вещи и активные записи. Таким образом, определение CreditCardDTO, CreditCardModel, CreditCardMemento и CreditCardActiveRecord допустимо, потому что в этом случае тип фактически помогает различать роль и, следовательно, его использование приемлемо.

Назовите методы после их побочных эффектов

Принцип здесь очень прост, но помогает разработчикам быстро понять действие метода. Если метод что-то возвращает (в идеале он не должен иметь побочных эффектов), его имя должно быть существительным или существительной фразой. Хорошие имена для методов, возвращающих значения, могут выглядеть примерно так: -

  • имя
  • dateFormattedAsDDMMYYYY
  • Дата рождения
  • printableDateOfBirth
  • в настоящее времяActiveScreen
  • selectedNameIndex
  • customersKeyedByName (например, для словаря)
  • customersOrderedByFirstName (например, для массива клиентов)

Избегайте неоднозначных имен, например вызов метода display неоднозначен, потому что display может быть как глаголом, так и существительным. , в этом случае неясно, действительно ли метод что-то отображает или возвращает отображение. Если метод действительно отображает что-то в диалоговом окне, например, было бы лучше явно задокументировать это в имени, вызвав метод displayUsingCurrentDialog. Если метод возвращает экранный объект, тогда явно укажите существительное, например, вы можете вызвать метод currentActiveDisplay.

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

  • calculateExpectedValueOfPrices
  • CalculAndCacheExpectedValueOfPrices
  • resetExpectedValueOfPricesCache
  • sortCustomersByName
  • offsetScreenPositionByPoint:
  • configureBasePrices

Если у вас есть два метода, которые делают одно и то же: один возвращает значение, а другой изменяет состояние, тогда назовите тот, который меняет состояние императивно. Например, метод, который возвращает массив-получатель в отсортированном виде, может называться sorted, а метод с побочными эффектами может называться sort . Это также следует парадигме именования существительных и глаголов.

Именование протокола или интерфейса

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

  • Карта,
  • Коллекция,
  • Список,
  • OrderedList,
  • IНеизвестно

Называйте протоколы, описывающие возможности чего-либо, используя суффикс способный, ible или ing (т. е. герундий), например

  • Сортируемый
  • Составление отчетов
  • Расходный материал
  • Сценарий
  • Представляя

Будьте откровенны

Всегда стоит четко указывать, что содержит переменная или что делает метод или функция. Например, если у типа Array есть метод сортировки массива, может быть допустимо просто вызвать метод sort. Однако сразу возникает вопрос, как сортируется Массив. Какой вид сравнения используется при сортировке, если массив содержит значения, не имеющие естественного порядка сортировки, как принимается решение о сортировке значений? Было бы лучше явно указать как можно больше в имени, чтобы избавить разработчика, использующего этот метод, от необходимости прибегать к документации, чтобы выяснить эти ответы. Следовательно, такое имя, как sortByNaturalOrder или sortUsingDescriptor, более эффективно.

Я часто вижу карты или словари с именами, похожими на клиентов или остатки или подобные, однако это было бы далеко Для другого разработчика более значимым и очевидным явным образом определяется способ ввода словаря, поэтому вызов словаря, содержащего клиентов с ключом по фамилии customersByLastName, более значим, потому что он более явный. Обзвонить группу клиентов, упорядоченных по дате рождения customersOrderedByDateOfBirth, лучше, чем клиентам или orderCustomers.

Ясность также означает отказ от сокращений или акронимов, если это возможно, за исключением случаев, когда они используются универсально (что не является обычным явлением). Например, что-то вроде SMS приемлемо, потому что оно довольно универсально, как LTE, HERV (эндогенный ретровирус человека), с другой стороны, очень специфично. к домену, и поэтому, вероятно, его не следует использовать. Тем не менее, при необходимости, соблюдение прецедента - хорошая идея.

Уважайте идиомы языка программирования

Одна из самых распространенных ошибок, которые я вижу, - это перевод программистов идиом между языками. Примером этого является перенос идиом именования из Java в Objective C. В Java есть соглашение о префиксе методов доступа с помощью get или set, в зависимости от того, является ли метод получателем или установщиком. Например, получателем для свойства с именем firstName будет getFirstName, а для этого свойства будет установщик setFirstName () . В Objective C, однако, есть соглашение о префиксе установщика с помощью set и оставлении имени получателя таким же, как имя рассматриваемого свойства. Используя то же имя свойства, что и выше, в Objective C метод получения будет называться firstName, а метод установки будет называться setFirstName: . Swift имеет то же соглашение, что и Objective C. Я не могу сказать вам, как часто я вижу код Objective C и Swift, в котором геттеры имеют префикс get.

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

Ясность важна, а не краткость

Имена символов должны быть настолько длинными, насколько это необходимо, чтобы четко задокументировать, что они собой представляют. За самое короткое имя символа приз не предоставляется. Используйте достаточно длинное имя, чтобы четко определить значение символа, но удалите из имени слова, не добавляющие ценности, например стоп-слова (a, the, an и т. Д.), Если они не действительно необходимы.

Например, вызов метода canonicalizeAfterRemovingStopWords имеет такое же значение, как и canonicalizeTheStringAfterRemovingAllTheStopWordsFromIt. Если, однако, существует различие между методом, удаляющим ВСЕ стоп-слова, и методом, удаляющим НЕКОТОРЫЕ стоп-слова, поясните это в названии.

Классический пример плохой практики в Objective C - это имена методов, содержащие слова и и then. Я видел такие имена методов, как createCustomer: AndCapitalizeName: AndThenInsertIntoDatabaseCalled:, тогда как этот метод правильнее называть createCustomer: mustCapitalizeName: insertInDatabaseNamed:

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

  • использование lbl вместо метки
  • используя я для индекса
  • используя j для второго индекса
  • используя btn вместо кнопки

и так далее. Лень - плохая черта программиста.

Мои годы становления в качестве разработчика прошли в финансовых учреждениях, поэтому, когда я вижу i как имя переменной, я инстинктивно предполагаю, что это процентная ставка в той или иной форме, не индекс. Даже название процентной ставки i может быть неоднозначным, поскольку оно не определяет четко период начисления сложных процентов. Использование i и j в качестве имен индексов вполне может быть допустимым в некоторых обстоятельствах, например, при умножении векторов или матриц, но использование i и j в качестве имен индукционных переменных чрезвычайно сбивает с толку, может затруднить усвоение кода, но это очень Общая практика.

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

Стандарт - это стандарт - это стандарт

Последовательное применение стандарта именования без исключений

Стандарт именования может быть только один, и он неизменен. Из этого не может быть исключений (если только это не определено самим стандартом), даже если стандарт неверен, его всегда следует последовательно применять ко всей кодовой базе. Стандарт имеет ценность только потому, что это просто Стандарт, поэтому, даже если кто-то не согласен со Стандартом, он должен его соблюдать. Даже в тех случаях, когда кто-то объективно знает, что Стандарт содержит ошибку, придерживайтесь Стандарта, слишком поздно начинать исправлять Стандарт на полпути реализации, если вы не готовы исправить все предыдущие ошибки. Более ценно быть последовательным, даже если это неверно, чем нет. Я знаю, что это может быть сложно, потому что каждый раз, когда в Стандарте встречается что-то, что, как известно, неверно, это оскорбляет, но Стандарт есть Стандарт есть Стандарт.

Последовательное применение стандарта помогает рефакторингу и ассимиляции

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

Определение стандарта именования

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

Мне очень нравится использовать шаблон Lightweight Architecture Decision Records для управления архитектурными документами. Использование этого шаблона включает создание небольшого документа (используйте HTML, возможно, сгенерированный из Markdown, или обычный текст, не используйте документы Word, так как у многих из нас нет доступа к Word, это дорогой и проприетарный формат, тогда как HTML или простой текст можно просмотреть практически на ЛЮБОЙ платформе) для каждого архитектурного решения и хранения этих документов в исходном репозитории. Включение ссылок на именование стандартных документов как часть записей об архитектуре важно, поскольку стандарты являются частью архитектуры системы.

Если нет стандарта именования, определите его.

Если вы обнаружите, что работаете над проектом, который не имеет определенного и / или задокументированного стандарта именования, в процессе обучения может быть полезно определить или задокументировать этот стандарт. Это будет полезно для других разработчиков, которые будут работать над проектом, и документирование существующих практик (сколь бы нерегулярными они ни были) поможет вам понять, как устроен проект. Если вы оказались в такой ситуации, поспрашивайте, прежде чем приступить к определению стандарта. Во многих случаях стандарт существует, но он может не быть задокументирован. Вполне может быть, что есть разработчик, который участвовал в проекте с первого дня, и который быстро и легко объяснит вам Стандарт. Вы можете попросить этого разработчика помочь вам в определении стандарта, поскольку вы обнаружите, что этот разработчик часто обладает множеством других знаний о системе, которые могут быть полезны. Никогда не помешает спросить совета у старого человека, люди любят, когда к ним обращаются, и это поможет вам, как новичку, наладить взаимопонимание с существующей командой. После того, как вы задокументировали или определили и задокументировали Стандарт именования, распространите его среди команды. На это есть две причины:

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

Предлагаемое содержание стандарта именования

Как минимум, Стандарт наименования должен четко и просто определять следующие элементы:

  1. Принципы наименования - рассуждения и обоснования
  2. Рекомендации по именованию типов
  3. Рекомендации по именованию методов или функций
  4. Рекомендации по именованию переменных
  5. Правила именования полей (также включает правила именования полей JSON)
  6. Рекомендации по именованию модулей
  7. Примеры каждого правила
  8. Запрещенные методы (например, односимвольные имена переменных)
  9. Разрешенные исключения (если есть) и обоснование

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

Последние мысли

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

  • ваш любимый проект может однажды стать проектом с открытым исходным кодом, а это означает, что ряд других разработчиков могут в конечном итоге поддержать или улучшить ваш код.
  • вы можете сделать его общедоступным на GitHub или другом сайте, и в этом случае потенциальные работодатели могут увидеть его и подумать, что вы плохой разработчик.
  • то, что вы делаете наедине, влияет на ваше профессиональное поведение
  • избавиться от вредных привычек сложно
  • Важно помнить, что через 6–12 месяцев вы вполне могли забыть, о чем думали, когда писали этот код, поэтому соблюдение стандарта именования так же важно для вас, как и для любого другого разработчика.

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

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

Вперед и назовите хорошо!

использованная литература

Рекомендации по Swift API

Соглашения об объективном кодировании на языке C

Соглашения об именах