Мой босс просит меня прекратить писать небольшие функции и делать все в одном цикле

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

Его аргументы были

  • Написание небольших функций - это боль, потому что она заставляет вас перемещаться в каждую маленькую функцию, чтобы увидеть, что делает код.
  • Поместите все в основной большой цикл, даже если основной цикл больше 300 строк, он быстрее читается.
  • Записывайте только небольшие функции, если вам нужно дублировать код.
  • Не записывайте функцию с именем комментария, помещайте сложную строку кода (3-4 строки) с комментарием выше; Аналогично, вы можете напрямую изменить неисправный код.

Это против всего, что я прочитал. Как вы обычно пишете код? Один основной большой цикл, небольшие функции?

Я использую в основном Javascript. Мне действительно трудно читать сейчас, так как я удалил все свои маленькие четко названные функции и поместил все в большой цикл. Тем не менее, моему боссу это нравится.

Один пример:

 //То, как я буду писать
if (isApplicationInProduction (заголовки)) {
  phoneNumber = headers.resourceId;
} else {
  phoneNumber = DEV_PHONE_NUMBER;
}

функция isApplicationInProduction (заголовки) {
   return _.has (заголовки, 'resourceId');
}

//То, как он это написал
//Возьмем правильный ресурс, если приложение находится в производстве
phoneNumber = headers.resourceId? headers.resourceId: DEV_PHONE_NUMBER;

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

Ну, я бы хотел, чтобы некоторые советы, какой способ /практика лучше писать чистый код?

203 голоса | спросил GitCommit Victor B. 10 42016vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2016 19:43:30 +0300 2016, 19:43:30

16 ответов


210

Сначала возьмем примеры кода. Вы предпочитаете:

 if (isApplicationInProduction (заголовки)) {
  phoneNumber = headers.resourceId;
} else {
  phoneNumber = DEV_PHONE_NUMBER;
}

функция isApplicationInProduction (заголовки) {
   return _.has (заголовки, 'resourceId');
}

И ваш босс написал бы это как:

 //Возьмем правильный ресурс, если приложение находится в производстве
phoneNumber = headers.resourceId? headers.resourceId: DEV_PHONE_NUMBER;

На мой взгляд, оба имеют проблемы. Когда я прочитал ваш код, я сразу подумал: «Вы можете заменить это if тройным выражением». Затем я прочитал код вашего босса и подумал: «Почему он заменил вашу функцию комментарием?».

Я бы предложил оптимальный код между двумя:

 phoneNumber = isApplicationInProduction (заголовки)? headers.resourceId: DEV_PHONE_NUMBER;

функция isApplicationInProduction (заголовки) {
   return _.has (заголовки, 'resourceId');
}

Это дает вам лучшее из обоих миров: упрощенное тестовое выражение, а комментарий заменяется тестовым кодом.

Что касается взглядов вашего босса на дизайн кода, тем не менее:

  

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

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

  

Поместите все в основной большой цикл, даже если основной цикл больше 300 строк, быстрее читать

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

  

Записывайте только небольшие функции, если вам нужно дублировать код

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

  

Не записывайте функцию с именем комментария, поместите сложную строку кода (3-4 строки) с комментарием выше. Подобно этому вы можете напрямую изменить неисправный код.

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

Написание самодокументирующего кода сложно, и иногда необходимы дополнительные документы (даже в форме комментариев). Но мнение «дяди Боба», что комментарии являются ошибкой кодирования, выполняется слишком часто.

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

ответил David Arno 10 42016vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2016 21:32:30 +0300 2016, 21:32:30
221

Существуют и другие проблемы

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

 phoneNumber = DEV_PHONE_NUMBER_WHICH_CAUSED_PROBLEMS_FOR_CUSTOMERS;

или

 phoneNumber = DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY;

Вы хотите добавить еще больше ветвей?

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

Вы спорите со своим боссом о том, как лучше писать плохой код. Вместо этого вы должны исправить неотъемлемую проблему самого кода.

инъекция зависимостей

Вот как выглядит ваш код:

 phoneNumber = headers.resourceId;

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

Если вы хотите иметь DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY в результате, вы должны поместить его в headers.resourceId. Один из способов сделать это - просто вставить другой тег headers для тестовых случаев (извините, если это не правильный код, мои навыки JavaScript немного ржавые):

 функция foo (заголовки) {
    phoneNumber = headers.resourceId;
}

//Создание тестового примера
foo ({resourceId: DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY});

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

ответил null 10 42016vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2016 23:23:48 +0300 2016, 23:23:48
59

На этот вопрос нет «правильного» или «неправильного» ответа. Тем не менее, я предложу свое мнение на основе 36-летнего профессионального опыта проектирования и разработки программных систем ...

  1. Нет такой вещи, как «самодокументирующий код». Зачем? Потому что это утверждение полностью субъективно.
  2. Комментарии никогда не возникают. Что означает , отказ - это код, который не может быть понят вообще без комментариев.
  3. 300 непрерывных строк кода в одном блоке кода являются кошмаром для обслуживания и сильно подвержены ошибкам. Такой блок сильно свидетельствует о плохом дизайне и планировании.

Говоря прямо на примере, который вы указали ... Размещение isApplicationInProduction () в свою собственную процедуру - это умная (э-э) вещь. Сегодня этот тест является просто проверкой «заголовков» и может обрабатываться в тройном (?: ) операторе. Завтра тест может быть намного сложнее. Кроме того, «headers.resourceId» не имеет четкого отношения к заявлению «в статусе производства»; Я бы сказал, что тест для такого состояния нуждается в для разделения из базовых данных; подпрограмма сделает это, и тройной не будет. Кроме того, полезный комментарий будет , почему resourceId - это тест для «в производстве».

Будьте осторожны, чтобы не переходить за борт с «небольшими четко названными функциями». Процедура должна инкапсулировать идею более, чем «просто код». Я поддерживаю предложение amon о phoneNumber = getPhoneNumber (заголовки) и добавляет, что getPhoneNumber () должен выполнить тест «производственный статус» с помощью isApplicationInProduction ()

ответил LiamF 10 42016vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2016 20:38:36 +0300 2016, 20:38:36
47
  

«Не следует умножать события не обязательно».

     

- Бритва Оккама

Код должен быть как можно более простым. Ошибки любят скрываться между сложностями, потому что их трудно обнаружить. Итак, что делает код простым?

Маленькие единицы (файлы, функции, классы) - хорошая идея . Малые единицы легко понять, потому что есть меньше вещей, которые вам нужно понять сразу. Нормальные люди могут только жонглировать ~ 7 концепций за раз. Но размер не просто измеряется в строках кода . Я могу писать как можно меньше кода с помощью «колчана» кода (выбирая короткие имена переменных, беря «быстрые клавиши», разбивая как можно больше кода на одну строку), но конечный результат не прост. Попытка понять такой код больше похожа на обратную инженерию, чем на чтение.

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

Но каждый вызов функции имеет когнитивные накладные расходы : мне не нужно просто понимать код внутри моего текущего фрагмента кода, мне также нужно понять, как это сделать взаимодействует с кодом на вне . Я думаю, справедливо сказать, что функция, которую вы извлекли, вносит больше сложностей в функцию, чем извлекает . Это то, что ваш босс подразумевал под «малыми функциями» [], потому что он заставляет вас перемещаться в каждую маленькую функцию, чтобы увидеть, что делает код. â €

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

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

Очень важная метрика циклическая сложность (сложность МакКейба). Он измеряет количество независимых путей через кусок кода. Это число растет экспоненциально с каждым условным. Каждый условный или цикл удваивает количество путей. Имеются данные, чтобы предположить, что оценка более 10 баллов слишком сложна. Это означает, что очень длинная функция, которая, возможно, имеет 5 баллов, возможно, лучше, чем очень короткая и плотная функция со счетом 25. Мы можем уменьшить сложность, извлекая поток управления в отдельные функции.

Ваше условное является примером части сложности, которая может быть полностью извлечена:

 function bigFatFunction (...) {
  ...
  phoneNumber = getPhoneNumber (заголовки);
  ...
}

...

функция getPhoneNumber (заголовки) {
  return headers.resourceId? headers.resourceId: DEV_PHONE_NUMBER;
}

Это все еще очень полезно. Я не уверен, что это значительно снижает сложность, потому что это условное условие не очень условно . В производстве он будет всегда придерживаться того же пути.


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

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

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

(Примечание: этот ответ основывается на деталях на мыслях из Разумный код в блоге The Whiteboard от Jimmy Hoffa , который обеспечивает представление высокого уровня о том, что делает код простым.)

ответил amon 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 18:49:35 +0300 2016, 18:49:35
27

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

Не слушайте их!

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

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

ответил Doc Brown 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 00:37:44 +0300 2016, 00:37:44
23

В вашем случае: вам нужен номер телефона. Либо очевидно, как вы получите номер телефона, а затем напишите очевидный код. Или не очевидно, как вы получите номер телефона, тогда вы напишите для него метод.

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

Метод isApplicationInProduction совершенно бессмыслен. Вызов его из метода getPhonenumber не делает реализацию более очевидной и просто затрудняет определение того, что происходит.

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

PS. Мне совсем не нравится реализация. Он предполагает, что отсутствие номера телефона означает, что это версия dev. Поэтому, если номер телефона отсутствует в производстве, вы не только не обрабатываете его, но и заменяете случайный номер телефона. Представьте, что у вас 10 000 клиентов, а 17 нет номера телефона, и у вас проблемы с производством. Независимо от того, находитесь ли вы в производстве или разработке, следует проверять напрямую, а не на основе чего-то другого.

ответил gnasher729 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 21:05:05 +0300 2016, 21:05:05
16

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

В большинстве случаев количество строк не является полезным показателем.

300 (или даже 3000) строк совершенно тривиального чисто последовательного кода (Setup или что-то в этом роде) редко возникает (но может быть лучше сгенерировано автоматически или как таблица данных или что-то еще), 100 строк вложенных циклов с множество сложных условий выхода и математики, как вы могли бы найти в гауссовом устранении или инверсии матрицы, или это может быть слишком много, чтобы легко следовать.

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

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

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

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

ответил Dan Mills 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 21:52:46 +0300 2016, 21:52:46
15

Не помещайте все в один большой цикл, но не делайте этого слишком часто:

 function isApplicationInProduction (заголовки) {
   return _.has (заголовки, 'resourceId');
}

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

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

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

ответил Brad Thomas 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 00:19:06 +0300 2016, 00:19:06
14

Кажется, что вы действительно хотите:

phoneNumber = headers.resourceId || DEV_PHONE_NUMBER

Это должно быть понятным для всех, кто его читает: установите phoneNumber в resourceId, если он доступен, или по умолчанию - DEV_PHONE_NUMBER, если это не так.

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

ответил BlueRaja - Danny Pflughoeft 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 02:46:48 +0300 2016, 02:46:48
14

Позвольте мне быть тупым: мне кажется, что ваша среда (язык /рамки /дизайн класса и т. д.) действительно не подходит для «чистого» кода. Вы смешиваете все возможные типы вещей в нескольких строках кода, которые не должны быть близко друг к другу. Какое дело имеет одна функция, зная, что resourceId == undef означает, что вы не в производстве, что вы используете номер телефона по умолчанию в непроизводственных системах, что resourceId сохраняется в некоторых «заголовки» и так далее? Я предполагаю, что заголовки являются заголовками HTTP, поэтому вы даже оставляете решение о том, в какой среде вы находитесь у конечного пользователя?

Факторинг отдельных частей этого в функции не поможет вам с этой основной проблемой.

Некоторые ключевые слова для поиска:

  • расцепления
  • сплочение
  • инъекция зависимостей

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

Из вашего описания («300 строк кода в« основной »функции) даже слово« функция »(вместо метода) заставляет меня предположить, что нет смысла в том, чего вы пытаетесь достичь. В этой среде программирования старой школы (т. Е. Базовое обязательное программирование с небольшой структурой, без каких-либо значимых классов, без шаблона структуры классов, такого как MVC или somesuch), действительно нет особого смысла в выполнении чего-либо . Вы никогда не выйдете из поддона без фундаментальных изменений. По крайней мере, ваш босс, похоже, позволяет создавать функции, чтобы избежать дублирования кода, это хороший первый шаг!

Я знаю как тип кода, так и тип программиста, который вы описываете достаточно хорошо. Честно говоря, если бы это был сотрудник, мой совет был бы другим. Но поскольку это ваш босс, вам бесполезно бороться за это. Мало того, что ваш босс может отменить вас, но ваши дополнения к коду действительно приведут к худшему коду, если вы только частично будете «свою вещь», и ваш босс (и, возможно, другие люди) будет продолжать, как раньше. Это может быть лучше для конечного результата, если вы приспособитесь к их стилю программирования (конечно, только при работе над этой конкретной кодовой базой), и попытайтесь в этом контексте сделать все возможное.

ответил AnoE 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 03:40:36 +0300 2016, 03:40:36
13

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

ответил user1172763 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 19:08:30 +0300 2016, 19:08:30
6

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

Я не буду говорить, что вы должны абсолютно использовать троянец, некоторые люди, с которыми я работал, предпочитают немного длиннее if () {...} else {...}, это в основном, личный выбор. Я предпочитаю, чтобы «одна линия приближалась к одной вещи», но я в основном придерживаюсь того, что обычно использует кодовая база.

При использовании trernary, если логическая проверка делает линию слишком длинной или сложной, рассмотрите возможность создания хорошо названной переменной /s для хранения значения.

 //ПРИМЕЧАНИЕ «resourceId» не присутствует в dev build, используйте тестовые данные
let isProduction = 'resourceId' в заголовках;
let phoneNumber = isProduction? headers.resourceId: DEV_PHONE_NUMBER;

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

ответил nepeo 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 18:15:44 +0300 2016, 18:15:44
5

Пример кода, который вы указали, ваш босс IS CORRECT. В этом случае одна четкая линия.

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

Не игнорируйте недостатки: служебные данные функции, затухание (функция не делает то, что подразумевает комментарии и имя функции), сложная логика спагетти, потенциал для мертвых функций (в свое время были созданы для цель, которая больше не называется).

ответил Phil M 11 52016vEurope/Moscow11bEurope/MoscowFri, 11 Nov 2016 22:38:44 +0300 2016, 22:38:44
2

Я могу представить как минимум два аргумента в пользу длинных функций:

  • Это означает, что у вас много контекста вокруг каждой строки. Способ формализации этого: нарисуйте диаграмму потока управления вашего кода. В вершине (~ = строка) между входом функции и выходом функции вы знаете все входящих ребер. Чем дольше функция, тем больше таких вершин.

  • Многие небольшие функции означают, что существует более крупный и сложный граф вызовов. Выберите случайную строку в случайной функции и ответьте на вопрос «в каком контексте (ах) эта строка выполняется?» Это становится все сложнее, чем больше и сложнее граф вызовов, потому что вам нужно посмотреть больше вершин на этом графе.

Есть также аргументы против длинных функций - способность к тестированию на единицу. Используйте t̶h̶e̶ ̶f̶o̶r̶c̶e̶ свой опыт при выборе между одним и другим.

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


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


Комментируя ответ Дэвида Арно :

  
    

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

  
     

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

В названии видно, что значение возврата означает , но в нем ничего не говорится о эффектах для выполнения кода (= код >). Имена (только) передают информацию о намерении , код передает информацию о поведении (из которого иногда могут быть выведены части намерения).

Иногда вам нужен один, иногда другой, поэтому это наблюдение не создает одностороннее универсальное правило принятия решения.

  
    

Поместите все в основной большой цикл, даже если основной цикл больше 300 строк, быстрее читать

  
     

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

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

Предположим, что крайний случай из 500 строк прямого кода с высокой степенью бокового эффекта, и вы хотите знать, действует ли эффект A до или после эффекта B. В случае с большими функциями используйте Page Up /Down, чтобы найти две строки а затем сравните номера строк. В случае с множеством мелких функций вы должны помнить, где в дереве вызовов происходят эффекты, и если вы забыли, вам придется потратить нетривиальное количество времени, заново открыв структуру этого дерева.

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

(*) По крайней мере, я честен в этом; -)

Еще раз, я думаю, что оба подхода имеют свои сильные и слабые стороны.

  
    

Записывайте только небольшие функции, если вам нужно дублировать код

  
     

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

Интересуетесь ли вы тем, «как» или «что» является функцией цели, для которой вы читаете код (например, получение общей идеи или отслеживание ошибки). Цель, для которой вы читаете код, недоступна при написании программы, и вы, скорее всего, прочитаете код для разных целей; различные решения будут оптимизированы для разных целей.

Тем не менее, это часть взгляда босса, с которым я, вероятно, не согласен.

  
    

Не записывайте функцию с именем комментария, поместите сложную строку кода (3-4 строки) с комментарием выше. подобноэто вы можете напрямую изменить неисправный код.

  
     

Я действительно не могу понять причины этого, считая, что это действительно серьезно. [...] Комментарии имеют фундаментальный недостаток: они не компилируются /не интерпретируются и поэтому не могут быть протестированы. Код будет изменен, и комментарий останется один, и вы не узнаете, что правильно.

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

ответил Jonas Kölker 16 32016vEurope/Moscow11bEurope/MoscowWed, 16 Nov 2016 02:23:46 +0300 2016, 02:23:46
-1

Просто комментарий по двум пунктам пули

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

Многие редакторы (например, IntelliJ) позволят вам перейти к функции /классу, просто нажав Ctrl-Click для использования. Кроме того, вам часто не нужно знать детали реализации функции для чтения кода, тем самым ускоряя чтение кода.

Я рекомендую вам сказать своему боссу; ему понравится ваша адвокация и увидит это как лидерство. Просто будьте вежливы.

ответил noɥʇʎԀʎzɐɹƆ 20 72016vEurope/Moscow11bEurope/MoscowSun, 20 Nov 2016 04:50:06 +0300 2016, 04:50:06
-1

На мой взгляд, правильный код для требуемой функциональности:

 phoneNumber = headers.resourceId || DEV_PHONE_NUMBER;

Или если вы хотите разбить его на функцию, возможно, что-то вроде:

 phoneNumber = getPhoneNumber (заголовки);

функция getPhoneNumber (заголовки) {
  return headers.resourceId || DEV_PHONE_NUMBER
}

Но я думаю, что у вас есть более фундаментальная проблема с концепцией «в производстве». Проблема с вашей функцией isApplicationInProduction заключается в том, что кажется странным, что это единственное место в системе, в котором происходит «производство», и что вы всегда можете полагаться на присутствие или отсутствие заголовка resourceId рассказать тебе. Должен быть общий метод isApplicationInProduction или метод getEnvironment, который напрямую проверяет среду. Код должен выглядеть так:

 function isApplicationInProduction () {
  process.env.NODE_ENV === 'production';
}

Затем вы можете получить номер телефона с помощью:

 phoneNumber = isApplicationInProduction ()? headers.resourceId: DEV_PHONE_NUMBER;
ответил rjmunro 18 52016vEurope/Moscow11bEurope/MoscowFri, 18 Nov 2016 13:28:41 +0300 2016, 13:28:41

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132