Статьи

Что в имени? Анти-паттерны к сложной проблеме

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

Если вы хотите сделать яблочный пирог с нуля, вы должны сначала изобрести вселенную. Карл Саган

Мы называем и имя и имя. И имя. Как известно, называть сложно, но мы не начинаем с нуля каждый раз. У нас есть привычки, условности и личный стиль.

Часто мы мало думаем о названии, и все равно делаем разумную работу. Конечно, иногда наша первая идея ужасна.

Нет формулы для выбора имени. В некоторых ситуациях наши привычки не годятся. Наши стратегии — невысказанные или нет — терпят неудачу. Наименование чревато двусмысленностью. Хорошее имя отвечает на важные вопросы. Что это содержит? Почему это существует? Почему это важно? Что это означает? Как бы я использовал это? Какую роль это играет? Но вряд ли он может ответить на все важные вопросы сразу. Плохое имя сбивает с толку или бесполезно. Это дезинформирует и вводит в заблуждение.

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

Анти-паттерн — это обычная реакция на повторяющуюся проблему, которая обычно неэффективна и рискует быть крайне контрпродуктивной. -Wikipedia

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

Базовые типы и структуры данных

Если вы видите имя, которое кодирует базовый тип, такой как word_string или new_hash , почти всегда лучшее имя ждет своего часа.

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

 def anagrams(string, string_array) string_array.each do |str| str != string && same_alphagram?(string, str) end end 

Этот код прост. Имена правильные, но бесполезные.

Один вопрос, который вы можете задать себе, столкнувшись с непринужденной коллекцией типов данных:

Что это содержит?

В случае анаграмм он содержит слова.

 def anagrams(word1, words) words.each do |word2| word1 != word2 && same_alphagram?(word1, word2) end end 

Теперь у нас другая проблема. Мы формулируем слова, чтобы мы могли слово. Нет никакого значимого различия между words , word1 и word2 . Нам нужно что-то сказать о том, как слова соотносятся друг с другом в контексте обнаружения анаграмм.

Оригинальное слово или фраза называется предметом анаграммы. -Wikipedia

Таким образом, word1 является предметом . words которые мы повторяем, могут быть или не быть анаграммами. Они potential_anagrams anagram , но немного раздражает повторять anagram в названии. Другое слово для потенциального соответствия — candidate .

 def anagrams(subject, candidates) candidates.each do |candidate| subject != candidate && same_alphagram?(subject, candidate) end end 

При вычислении баллов Scrabble мы сталкиваемся с одним и тем же.

 def compute_score(chars) chars.inject(0) {|num, char| num + char_to_num[char] } end 

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

 def compute_score(tiles) tiles.inject(0) {|score, tile| score + points[tile] } end 

Использование типа данных в имени не всегда является анти-паттерном.

Когда область действия мала, может быть избыточным, чтобы дать переменной более выразительное имя. Контекст уже отвечает на важные вопросы об этом. Там нет причин, чтобы раздуть код с дополнительными описаниями. Просто используйте тип, например, s для строки или i для int.

Иногда название структуры данных помогает уточнить важные детали. queue — это концепция, знакомая программистам. Название jobs может отражать ваши намерения. Но, возможно, нет. Если аспект FIFO (первым job_queue , первым job_queue ) имеет решающее значение, то job_queue может быть лучше. Он выражает то, что содержит вещь, а также как ее использовать.

структурная

Другая распространенная стратегия — назвать вещи для их роли в программе. Это вход или выход. Это повторяющаяся фраза или среднее предложение. Это памятка или сумма или результат.

Вот некоторый код, который подсчитывает различия, упрощение алгоритма, известного как расстояние Хэмминга .

 def self.compute(first, second) first.length.times.count { |i| first[i] != second[i] } end 

Алгоритм достаточно выразителен, но имена first и second кажутся довольно произвольными. Это первый и второй параметры, но имеет ли значение порядок? Неясно. И first и second что?

Первая и вторая цепи ДНК. Duh.

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

Название strand отвечает на вопрос, что это такое. Достаточно простого суффикса для различия между ними. Нам не нужно рассказывать больше истории, чем это. Мы могли бы использовать A и B , которые не подчеркивают порядок так же, как 1 и 2 .

 def self.compute(strandA, strandB) strandA.length.times.count { |i| strandA[i] != strandB[i] } end 

Вот метод оценки Scrabble от более раннего, со структурными именами.

 def compute_score(input) input.inject(0) {|sum, x| sum + lookup[x] } end 

Интересно то, что входные данные не передаются методу в качестве аргумента. Интересным является то, что он содержит , в данном случае это плитки Scrabble. Точно так же sum не старая, а чья-то оценка. Неоспорим тот факт, что мы что-то ищем, но lookup ничего не объясняет. Вопрос в том, что ты смотришь вверх ? Точки. Здесь есть драма, если вы ищете ее.

Фрагмент идеи

Это заманчивая ловушка в Ruby, и как только вы ее увидите, вы не сможете ее увидеть. Это везде

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

«Чего ждать?»

Да жаль. Дело не в том, что маленькие методы плохие. Все дело в компромиссе. Оказывается, есть более важные вещи, чем SLOC (исходные строки кода). Кто знал?

Вот метод из некоторого кода для планирования встреч:

 def prev_or_next_day(date, date_type) date_type == :last ? date.prev_day : date.next_day end 

Имя метода повторяет условие, которое он содержит.

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

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

Фрагмент реализации

Иногда метод выделяет полную мысль, но имя метода не попадает в точку.

В некотором коде для генерации текста песни 99 The Bottles of Beer есть этот метод.

 def bottle_or_bottles(quantity) if quantity == 1 "bottle" else "bottles" end end 

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

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

 def container(quantity) if quantity == 1 "bottle" else "bottles" end end 

Хорошее имя не присоединяется к реализации в сорняках. Он немного поднимает глаза и видит большую картину.

Вот метод, найденный в коде для генерации текста песни «Я знаю старую женщину, которая проглотила муху».

 def swallowed "She swallowed the #{predator} to catch the #{prey}." end 

Хищник и добыча — великие имена. Они объясняют, что содержат переменные, а также как они связаны друг с другом. Но swallowed не очень помогает читателю.

Автор взял небольшой фрагмент реализации и повторил его название.

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

 def motivation(predator, prey) "She swallowed the #{predator} to catch the #{prey}." end 

Вывод

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

Эрудит имеет очки и оценки и плитки.

Анаграммы о словах. Но не просто слова. Слова, которые связаны друг с другом определенным образом. Предмет и кандидаты.

Расстояние Хэмминга между двумя нитями ДНК — это не какая-то старая сумма, это количество мутаций.

Любая песня может иметь первую строку и последнюю строку. Многие песни будут иметь повторяющиеся предложения. Есть разница между песней о питье пива и песней о глотании тварей. Эти различия имеют значение.

Сделайте значимые различия. Удалите ненужные или ненужные детали.

Короче расскажи хорошую историю.