насколько короткой должна быть функция? - PullRequest
6 голосов
/ 14 января 2011

Я провел здесь некоторые поиски и не нашел ничего подобного, так что я собираюсь пойти дальше и спросить. Это действительно больше о семантике, чем вопрос программирования. В настоящее время я пишу что-то на C ++, но язык на самом деле не имеет значения.

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

Первым языком программирования, который я выучил (кроме Applesoft BASIC, который не считается ...), был язык ассемблера 6502, где скорость и оптимизация - это все. В тех случаях, когда несколько циклов подсчитывают сглаживание времени всей вашей программы, часто лучше установить ячейку памяти или зарегистрироваться напрямую, чем переходить к другой подпрограмме. Первая операция может занять 3 или 4 цикла, в то время как последняя может занять в два или три раза больше.

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

В частности, допустим (снова с использованием C ++) у нас есть метод закрытого класса, который выглядит примерно так:

int Foo::do_stuff(int x) {
    this->x = x;
    // various other operations on x
    this->y = this->x;
}

Я видел несколько аргументов, что, по крайней мере, каждый набор операций должен быть своей собственной функцией. Например, do_stuff () в теории должен называться set_x (int x), отдельная функция должна быть написана для набора операций, выполняемых над членом класса x, и третья функция должна быть написана для назначения окончательного значения члена класса. х к ученику у. Но я видел другие аргументы, что КАЖДАЯ операция должна иметь свою собственную функцию.

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

Есть ли лучшая практика для такого рода вещей или это зависит от индивидуального суждения?

Ответы [ 5 ]

8 голосов
/ 14 января 2011

Со времен сборки 6502 произошли две вещи: компьютеры стали намного быстрее, а компиляторы (где это уместно) стали умнее.

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

Вместо этого начните думать о том, чтобы сделать ваши функции достаточно маленькими, чтобы:

  • понятно,
  • проверяемое,
  • для повторного использования, может быть, там, где это уместно.

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

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

5 голосов
/ 14 января 2011

Самое важное при принятии решения о том, где разбить функцию, не обязательно , сколько функция делает .Это скорее определение API вашего класса.

Предположим, мы разбиваем Foo::do_stuff на Foo::set_x, Foo::twiddle_x и Foo::set_y.Имеет ли смысл когда-либо выполнять эти операции отдельно?Произойдет ли что-то плохое, если я поверну x без предварительной настройки?Могу ли я позвонить set_y без звонка set_x?Разбивая их на отдельные методы, даже частные методы в одном и том же классе, вы подразумеваете, что они являются, по крайней мере, потенциально отдельными операциями.

Если это не так, то непременно оставьте их в одной функции.

3 голосов
/ 14 января 2011

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

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

  1. Держите все функции на одном уровне абстракции
  2. убедитесь, что есть без побочных эффектов (для исключительных случаи убедитесь, что явно документировать их)
  3. Убедитесь, что функция не выполняет более одной задачи (принцип SRP). Но вы можете сломать это, чтобы почтить 1.

Другие передовые методы разработки методов

  1. Не заставляйте клиента делать что-либо Модуль мог сделать
  2. Не нарушайте принцип наименьшего Удивление
  3. Fail Fast - сообщить об ошибках как скоро Возможно после того, как они произошли
  4. Перегрузка с осторожностью
  5. Использовать соответствующие параметры и типы возврата
  6. Использовать согласованный порядок параметров Через методы
  7. Избегайте длинных списков параметров
  8. Избегайте возвращаемых значений, которые требуют Исключительная обработка
2 голосов
/ 14 января 2011

После прочтения Чистый код: Справочник по мастерству Agile Software , в котором затрагивались почти все советы на этой странице, я начал писать короче. Не ради коротких функций, а для улучшения читабельности и тестируемости, держите их на одном уровне абстракции, заставляйте их делать только одну вещь и т. Д.

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

0 голосов
/ 14 января 2011

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

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

...