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

Все началось с простого рефакторинга. Мы разрешаем людям публиковать произвольные URL-адреса в чате Basecamp 3, который мы попытаемся получить и отобразить в строке, будь то изображение, фильм или URL-адрес Twitter. Существует проблема безопасности, когда мы не хотим разрешать внутренние IP-адреса в этих URL-адресах, например 127.0.0.1, а затем заставлять наш класс Downloader запускать внутренний запрос, который может обойти другие меры безопасности.

Конкретная политика не так важна, как тот факт, что это предварительное условие изначально было просто частью класса Downloader, но теперь оно мне также понадобилось в нашем готовящемся к выпуску API webhooks. Потому что, как и в случае с предварительно просматриваемыми URL-адресами чата, веб-перехватчики позволяют пользователям устанавливать URL-адреса, которые затем вызывает наша система. Та же основная проблема безопасности, которую нужно решить.

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

  • PrivateNetworkProtector.protect_against_internal_ip_address (ip)
  • PrivateNetworkProtector.verify_ip_address_isnt_private (ip)

Хм. Мне не понравился ни один из этих вариантов. Оба слишком многословны и содержат негатив. Если подумать, я даже не был в восторге от слова Protector. Это подразумевает что-то вроде защиты от перенапряжения, где просто сводит на нет влияние выброса на входе. Это не совсем то, что здесь происходит. Мы ищем злонамеренные попытки, поэтому лучшее слово будет более убедительным. Больше внимания уделяется угрозе, а не только риску.

Давайте посмотрим, что может предложить лучший друг программиста, тезаурус:

Возможностей там много, но на самом деле мне понравился Guard, как в PrivateNetworkGuard. Отлично. Теперь я могу представить себе какого-нибудь здоровенного парня, проверяющего аттестаты с определенным отношением. Правильное изображение. Итак, вернемся к правильному названию метода. Давайте попробуем два варианта, аналогичные тем, что были у нас ранее:

  • PrivateNetworkGuard.guard_against_internal_ip_address (URL)
  • PrivateNetworkGuard.verify_ip_address_isnt_private (url)

Хм, оба они тоже не правы. Я имею в виду, вы могли бы снова использовать guard, но двойное конфетти этого повторения только раздражало мою чувствительность. Что, если бы мы думали о Guard как о чем-то вроде предварительного фильтра, например, before_action в Action Controller? Это многообещающе:

  • PrivateNetworkGuard.ensure_public_ip_address (url)
  • PrivateNetworkGuard.ensure_no_private_ip_address (url)

Все еще не совсем так. Глагол гарантировать не совсем соответствует убедительной идее Guard. Это слишком кротко. Это не обычная проверка учетных данных. ЭТО ЕСЛИ ЭТО ПРОИСХОДИТ, Я ПОДНИМАЮ ИСКЛЮЧЕНИЕ И ОТКЛЮЧАЮ ЗАПРОС!

Это привело меня к мысли о языке программирования Eiffel и концепции дизайна по контракту. Поэтому я просмотрел статью в Википедии, чтобы найти хорошее слово. Eiffel использует require для определения предварительных условий, что мы и делаем здесь, но это тоже неправильно: PrivateNetworkGuard.require_public_ip. Это больше похоже на то, что вы пишете в спецификации, чтобы сообщить действующим из лучших побуждений, что они должны делать. Речь шла не о типе благонамеренных, а о гнусном.

Поэтому я снова попробовал тезаурус, отказавшись от обеспечения альтернатив:

Здесь нет хороших кандидатов. Я имею в виду, что они все работали бы, но они не чувствовали себя вполне подходящими. И в этом-то и состоит вся эта экспедиция. Не просто найти что-то, что может работать, но и то, что вам нужно: Да! Это идеально! Как насчет чего-нибудь из области Guard?

Неа. Это тоже не работает. Но одно слово выделялось как идея: Police. Guard контролирует входящие IP-адреса, чтобы убедиться, что внутренний IP-адрес не проскользнуть. Это интересно. Давайте продолжим тянуть за эту нить:

ПРИНУДИТЬ! Вот и все. Давай попробуем:

  • PrivateNetworkGuard # enforce_public_ip (url)
  • PrivateNetworkGuard # enforce_no_private_ip (url)

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

Однако в конце концов я выбрал PrivateNetworkGuard # enforce_public_ip (url), потому что мне больше нравилось сохранять положительное имя метода, чем немного более подходящую отрицательную версию. Взвешивая эти два тонких компромисса и выбирая более важную проблему.

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

Basecamp 3 был усыплен тоннами такого рода чрезмерной / навязчивой заботы. Вы никогда не сможете сказать, но можете быть уверены, что мы уделяем такое внимание продукту всеми другими видимыми способами. Приятно возиться с невидимым качеством.