[Перевод] Длина функции

632cbf8d817649f88b9388ecb1a83c50.jpg


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


Когда я стал применять такой принцип, я развил в себе привычку писать очень маленькие функции — обычно не больше нескольких строк. Любая функция длиннее шести строк уже попахивает. Вполне обычное дело для меня — иметь функцию с одной строчкой кода. Кент Бек показал мне когда-то пример из оригинальной системы Smalltalk, и это помогло мне по-настоящему понять, что размер — это не важно. Smalltalk в те годы работал на черно-белых машинах. Если нужно было подсветить текст или графику, то приходилось реверсировать видео. Класс в Smalltalk, отвечающий за графику, содержал метод 'highlight', и в его реализации была лишь одна строка — вызов метода 'reverse'. Название метода было длиннее реализации, но это не имело значения, потому что между намерением и реализацией этого кода — большое расстояние.


Некоторые люди волнуются по поводу коротких функций, потому что их заботит влияние вызовов на производительность. Когда я был молод, это иногда имело значение, но сегодня это редкость. Оптимизирующие компиляторы часто работают лучше с короткими функциями, потому что их легче кэшировать. Как обычно, в оптимизации производительности имеют смысл в первую очередь рекомендации общего характера. Иногда правильное решение это вернуть код из функции обратно в прежнее место. Но зачастую наличие маленьких функций позволяет найти другие способы оптимизации. Я помню, когда люди были против наличия метода isEmpty для списков. Стандартным способом было aList.length == 0. Но здесь как раз тот случай, когда название функции указывает на намерение, и это может помочь с производительностью если существует более быстрый способ определения пустоты коллекции, нежели проверкой длины.


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

Комментарии (3)

  • 2 декабря 2016 в 13:11

    +1

    Хотя не всегда можно уместить функцию в десяток строк, тем не менее присоединюсь к автору — компактные функции читаются легче, и с ними код выглядит аккуратней. ИМХО.
    • 2 декабря 2016 в 13:42

      0

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

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

  • 2 декабря 2016 в 13:28

    0

    «Оптимизирующие компиляторы часто работают лучше с короткими функциями, потому что их легче кэшировать» — что имелось в виду? что значит кэшировать функции?

    + В С/С++ если мелкие функции разбросаны по разным единицам трансляции, то лишь применение IPO/LTO заинлайнит такие вызовы. А оно примеряется далеко не всегда.

© Habrahabr.ru