Какова хорошая практика кода, когда создавать функцию / метод для небольших повторяющихся сегментов кода?

12

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


источник

Ответы:

29

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

Например, в «Чистом коде» Роберт С. Мартин приводит следующий пример: какой из них вы бы предпочли увидеть? Эта:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
    (employee.age > 65))

Или это?

if (employee.isEligibleForFullBenefits())

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

Я никогда не жалел, что что-то вставил в функцию, и если вы беспокоитесь о производительности, то сначала профиль.

omrib
источник
2
Следование этой простой практике в конечном итоге позволит вам написать код приложения на относительно высоком уровне. Маленькие функции собираются в маленькие классы, и вскоре вы превращаете функциональные спецификации в код почти дословно.
Кевин Клайн
11
Мне понравился этот пример. Внезапно вам больше не нужен этот комментарий. Это практическое правило : если ваш комментарий можно преобразовать в имя переменной или функции, сделайте это!
Кароли Хорват
Я согласен с omrib здесь, это часто касается очистки кода - что делает его более читабельным, чем любое другое практическое правило. Если я в конечном итоге что-то использую, я извлечу это в метод. Тем не менее, моя IDE и инструменты часто помогают в этом, поэтому это легко и быстро сделать.
Трэвис
+1 Этот код может быть даже быстрее, по крайней мере, если он должен быть JIT-Ed - вы платите только за то, что вы используете.
Работа
1
также известный как Намерение раскрытия имен .
Rwong
13

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

Ли Райан
источник
1
Посмотрите, на что пойдут программисты, чтобы не писать комментарии?
Алджер
1
@ Алжир, как они должны
MatrixFrog
6

Если он используется более чем в одном месте, и

  • это может измениться, или
  • это сложно получить право

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

Фред Фу
источник
3
Вопрос в том, почему бы вам не написать функцию для часто повторяющегося фрагмента кода, даже если было не сложно получить правильные или вероятные изменения? (Мое эмпирическое правило: если оно повторяется и дольше, чем вызов функции, сделайте ее функцией)
Уинстон Эверт
Я бы пошел еще дальше. Как программист, вы должны устранить все виды повторений . Будь то в базе данных (нормализация), ручное тестирование (замена на модульные тесты) или развертывание (автоматизация).
Кароли Хорват
@Winston: это зависит от используемого языка. Не каждая конструкция может быть естественным образом захвачена как функция, функция может занимать больше места, чем исходный код (например, C и возвращаться по указателю), вызовы функций могут повлечь за собой дополнительные затраты.
Фред Фу
@ larsman, мне любопытно, что ты имеешь в виду под «(подумай С и вернись по указателю)». Но то, что вы говорите, - это то, к чему я стремился, используя свое эмпирическое правило. Вызов функции должен быть проще (т.е., естественно, захватывать и занимать меньше места), чем реализация содержимого функции.
Уинстон Эверт
Если фрагмент кода вычисляет несколько значений, скажем float x, int yи double density, тогда настройка этих вычислений как функции C может быть сложнее, чем просто повторять код, поскольку вам нужно найти способ получить все три значения. Если сами повторяющиеся вычисления тривиальны, иногда лучше просто оставить их встроенными.
Фред Фу
4

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

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

Никола Мусатти
источник
Остерегайтесь утиной типизации, если на данный момент реализация похожа, но функциональность фактически различна, то объединение этих двух компонентов делает это раздражающим, как чертовски неприятно разделяться. Особенно на языках с плохой поддержкой IDE (эй, я работаю на C ++ ...)
Матье М.
С другой стороны, держа их отдельно, у вас есть две функции, которые выполняют одно и то же для тестирования, половина шансов на выполнение вашего кода, два места, в которых может появиться одна и та же ошибка, и вы должны не забыть исправить ту, в которой ошибка еще не обнаружена. Я хотел бы все еще работать в C ++, несмотря на плохую поддержку IDE ;-)
Никола Мусатти
1

Поиск « рефакторинга » приведет вас ко многим ресурсам отраслевых «лучших практик» для этого очень распространенного процесса. Несколько известная статья, « Однажды и только один раз», является отличным историческим справочником, объясняющим то, что некоторые считают «лучшими практиками» для вопросов, поднятых вашим вопросом. Кроме того, еще более общая концепция известна как « Не повторяйся» (СУХОЙ) . Чтобы получить действительно исчерпывающий набор ответов на ваш вопрос, прочитайте замечательную классику Мартина Фаулера « Рефакторинг: улучшение дизайна существующего кода» , которая охватывает некоторые из самых известных советов по рефакторингу , и это то, что вы интуитивно пытаетесь выполнить. !

Джон Тоблер
источник
0

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

Стивен Д.
источник
1
если это изменится, еще больше причин для его рефакторинга. Тогда вам придется изменить его только один раз
Шуг
0

Это зависит от характера сплоченности повторяющегося кода. Если повторяющаяся часть кода выполняет определенную функцию, то она является отличным кандидатом на включение в метод, частично из-за принципа СУХОЙ , частично потому, что если функцию необходимо оптимизировать или исправить, то существует только один раздел кода для решения.

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

Смотрите статью в Википедии о концепции связности кода .

Джей Элстон
источник
если связь выглядит случайной, вполне вероятно, что эти два процесса имеют общую идею, и вам, вероятно, следует выяснить, действительно ли два процесса являются двумя аспектами одного и того же. Чаще всего это так.
Ли Райан
0

Вы должны различать функции в смысле структурированного программирования и методы класса.

В вашем примере вы показали, что метод как таковой не должен быть закодирован как in-line.

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

Это различие особенно важно в крупных проектах.

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

Без шансов
источник