Я прочитал первые главы « Чистого кода » Роберта С. Мартина, и мне кажется, что это довольно хорошо, но у меня есть сомнения, в одной части упоминается, что хорошо (познавательно), что функции должны иметь как можно меньше параметров насколько это возможно, он даже предполагает, что 3 или более параметров - это слишком много для функции (что я считаю очень преувеличенным и идеалистическим), поэтому я начал задаваться вопросом ...
Практика использования глобальных переменных и передачи множества аргументов в функции была бы плохой практикой программирования, но использование глобальных переменных может значительно уменьшить количество параметров в функциях ...
Поэтому я хотел услышать, что вы думаете об этом, стоит ли использовать глобальные переменные для уменьшения количества параметров функций или нет? В каких случаях это будет?
Я думаю, что это зависит от нескольких факторов:
- Размер исходного кода.
- Количество параметров в среднем функций.
- Количество функций.
- Частота, с которой используются одни и те же переменные.
По моему мнению, если размер исходного кода относительно мал (например, менее 600 строк кода), есть много функций, те же переменные передаются в качестве параметров, а функции имеют много параметров, тогда использование глобальных переменных будет полезно, но я хотелось бы узнать...
- Вы разделяете мое мнение?
- Что вы думаете о других случаях, когда исходный код больше и т. Д.?
PS . Я видел этот пост , названия очень похожи, но он не спрашивает, что я хочу знать.
postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)
является вонючей версиейpostLetter(Address address)
. Продолжайте читать книгу, она, надеюсь, скажет что-то подобное.Ответы:
Я не разделяю ваше мнение. По моему мнению, использование глобальных переменных является худшей практикой, чем большее количество параметров, независимо от описанных вами качеств. Я считаю, что большее количество параметров может усложнить понимание метода, но глобальные переменные могут вызвать множество проблем в коде, включая плохую тестируемость, ошибки параллелизма и жесткую связь. Независимо от того, сколько параметров имеет функция, она по своей природе не будет иметь тех же проблем, что и глобальные переменные.
Это может быть дизайнерский запах. Если у вас есть одинаковые параметры, передаваемые большинству функций в вашей системе, может возникнуть сквозная проблема, которая должна быть решена путем введения нового компонента. Я не думаю, что передача одной и той же переменной во многие функции является разумным аргументом для введения глобальных переменных.
В одном из вариантов вашего вопроса вы указали, что введение глобальных переменных может улучшить читабельность кода. Я не согласен. Использование глобальных переменных скрыто в коде реализации, тогда как параметры функции объявлены в сигнатуре. Функции в идеале должны быть чистыми. Они должны работать только по своим параметрам и не должны иметь побочных эффектов. Если у вас есть чистая функция, вы можете рассуждать о ней, рассматривая только одну функцию. Если ваша функция не является чистой, вы должны учитывать состояние других компонентов, и об этом становится гораздо сложнее рассуждать.
источник
Вы должны избегать глобальных переменных, таких как чума .
Я бы не стал жестко ограничивать количество аргументов (например, 3 или 4), но вы , по возможности, хотите свести их к минимуму.
Используйте
struct
s (или объекты в C ++), чтобы сгруппировать переменные в одну сущность и передать их (по ссылке) в функции. Обычно функция получает структуру или объект (с несколькими различными вещами в нем), переданные ей вместе с парой других параметров, которые говорят функции сделать что-то сstruct
.Для хорошо пахнущего, чистого, модульного кода, старайтесь придерживаться принципа единой ответственности . Делайте это с вашими структурами (или объектами), функциями и исходными файлами. Если вы сделаете это, естественное число параметров, переданных функции, будет очевидным.
источник
Мы говорим о когнитивной нагрузке, а не о синтаксисе. Итак, вопрос в том ... Что является параметром в этом контексте?
Параметр - это значение, которое влияет на поведение функции. Чем больше параметров, тем больше возможных комбинаций значений вы получаете, тем сложнее рассуждать о функции.
В этом смысле глобальные переменные, которые использует функция, являются параметрами. Это параметры, которые не фигурируют в его подписи, которые имеют проблемы порядка построения, контроля доступа и остаточных значений.
Если упомянутый параметр не является тем, что называется сквозной задачей , то есть каким-то программным состоянием, которое все использует, но ничего не меняет (например, объект регистрации), вы не должны заменять параметры функции глобальными переменными. Они все еще будут параметрами, но противнее.
источник
ИМХО твой вопрос основан на недоразумении. В «Чистом коде» Боб Мартин не предлагает заменять повторяющиеся параметры функции глобальными, что было бы действительно ужасным советом. Он предлагает заменить их закрытыми переменными-членами класса функции. И он также предлагает небольшие, связные классы (обычно меньше, чем 600 строк кода, которые вы упомянули), поэтому эти переменные-члены определенно не являются глобальными.
Таким образом, если у вас есть мнение в контексте с менее чем 600 строками «использование глобальных переменных стоило бы того» , то вы полностью разделяете мнение дяди Боба. Конечно, это спорно , если «3 параметра в максимуме» идеальное количество, и если это правило иногда приводит к слишком много переменных - членов , даже в небольших классах. ИМХО, это компромисс, нет строгого правила, где проводить черту.
источник
Наличие многих параметров считается нежелательным, но преобразование их в поля или глобальные переменные намного хуже, потому что это не решает реальную проблему, но создает новые проблемы.
Наличие многих параметров само по себе не является проблемой, но это признак того, что у вас может быть проблема. Рассмотрим этот метод:
Наличие 7 параметров является определенным предупреждающим знаком. Основная проблема заключается в том, что эти параметры не являются независимыми, а относятся к группам.
left
иtop
принадлежат друг другу какPosition
-структура,length
иheight
какSize
структураred
,blue
иgreen
какColor
структура. А можетColor
и прозрачность принадлежитBrush
структуре? Возможно,Position
иSize
принадлежат друг другу вRectangle
структуре, и в этом случае мы можем даже рассмотреть возможность превращения его вPaint
методRectangle
объекта вместо этого? Таким образом, мы можем в итоге:Миссия выполнена! Но важно то, что мы фактически улучшили общий дизайн, и следствием этого является сокращение количества параметров . Если мы просто уменьшим количество параметров без решения основных проблем, мы можем сделать что-то вроде этого:
Здесь мы добились такого же сокращения количества параметров, но на самом деле мы ухудшили дизайн .
Итог: для любого совета по программированию и практических правил действительно важно понять основную причину.
источник
Не
Вы читали остальную часть книги?
Глобал - это просто скрытый параметр. Они вызывают разные боли. Но это все еще боль. Хватит думать о способах обойти это правило. Подумай, как ей следовать.
Что такое параметр?
Это вещи. В красиво помеченной коробке. Почему имеет значение, сколько у вас коробок, когда вы можете положить в них что угодно?
Это стоимость доставки и обработки.
Скажи мне, что ты можешь это прочитать. Давай, попробуй.
Вот почему.
Этот трюк называется ввести параметр объекта .
И да, это просто хитрость, если все, что вы делаете, это подсчет параметров. То, что вы должны считать, это ИДЕИ! Абстракция! О чем ты заставляешь меня думать сразу? Будь проще.
Теперь это тот же счет:
OW! Это ужасно! Что здесь пошло не так?
Недостаточно ограничить количество идей. У них должны быть четкие идеи. Что за хрень?
Теперь это все еще слабо. Какой более мощный способ думать об этом?
Зачем заставлять функцию делать больше, чем нужно? Принцип единой ответственности не только для классов. Серьезно, стоит изменить всю архитектуру, просто чтобы одна функция не превратилась в перегруженный кошмар с 10 иногда связанными параметрами, некоторые из которых нельзя использовать с другими.
Я видел код, где наиболее распространенное количество строк в функции было 1. Серьезно. Я не говорю, что вы должны писать таким образом, но, боже, не говорите мне, что глобальный - это ЕДИНСТВЕННЫЙ способ соблюдения этого правила. Прекратите пытаться избавиться от рефакторинга этой функции должным образом. Вы знаете, что можете. Это может быть разбито на несколько функций. Это может фактически превратиться в несколько объектов. Черт возьми, вы можете даже разбить часть этого на совершенно другое приложение.
Книга не говорит вам посчитать ваши параметры. Он говорит вам обратить внимание на боль, которую вы причиняете. Все, что устраняет боль, решает проблему. Просто знайте, когда вы просто меняете одну боль на другую.
источник
Я бы никогда не использовал глобальные переменные для уменьшения параметров. Причина в том, что глобальные переменные могут быть изменены любой функцией / командой, поэтому ввод данных функции ненадежен и подвержен значениям, выходящим за рамки возможностей, которые может обрабатывать функция. Что если переменная была изменена во время выполнения функции, и половина функции имела значения, отличные от другой половины?
Передача параметров, с другой стороны, ограничивает область видимости переменной только своей собственной функцией, так что только функция может изменять параметр после его вызова.
Если вам нужно передать глобальные переменные вместо параметра, предпочтительнее переделать код.
Просто мои два цента.
источник
Я с дядей Бобом согласен с тем, что следует избегать более 3 параметров (я очень редко использую более 3 параметров в функции). Наличие большого количества параметров для одной функции создает большую проблему обслуживания и, вероятно, является запахом того, что ваша функция выполняет слишком много / имеет слишком много обязанностей.
Если вы используете более 3 в методе на языке OO, вы должны рассмотреть, не связаны ли параметры каким-либо образом друг с другом, и, следовательно, вы должны вместо этого передавать объект?
Кроме того, если вы создадите больше (меньших) функций, вы также заметите, что функции чаще имеют 3 параметра или меньше. Функция извлечения / метод - ваш друг :-).
Не используйте глобальные переменные как способ обойти, имея больше параметров! Это замена одной плохой практики на еще худшую!
источник
Допустимой альтернативой многим параметрам функции является введение объекта параметра . Это полезно, если у вас есть составной метод, который передает (почти) все свои параметры множеству других методов.
В простых случаях это простой DTO, имеющий в качестве свойств только старые параметры.
источник
Использование глобальных переменных всегда кажется простым способом кодирования (особенно в небольшой программе), но это затруднит расширение вашего кода.
Да, вы можете уменьшить количество параметров в функции, используя массив для привязки параметров в одном объекте.
Вышеупомянутая функция будет отредактирована и изменена на [использование ассоциативного массива] -
Я согласен с ответом Роберта Бристоу-Джонсона : вы даже можете использовать структуру для связывания данных в одном объекте.
источник
Взяв пример из PHP 4, посмотрите на сигнатуру функции для
mktime()
:int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )
Вы не находите это запутанным? Функция называется «время выполнения», но она принимает параметры дня, месяца и года, а также три параметра времени. Насколько легко запомнить, в каком порядке они идут? Что если ты увидишь
mktime(1, 2, 3, 4, 5, 2246);
? Можете ли вы понять это, не обращаясь ни к чему другому? Это2246
интерпретируется как 24-часовое время "22:46"? Что означают другие параметры? Было бы лучше как объект.Переходя к PHP 5, теперь существует объект DateTime. Среди его методов два названных
setDate()
иsetTime()
. Их подписи следующие:public DateTime setDate ( int $year , int $month , int $day )
public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )
Вы все еще должны помнить, что порядок параметров изменяется от наибольшего к наименьшему, но это большое улучшение. Обратите внимание, что не существует единственного метода, который позволяет вам устанавливать все шесть параметров одновременно. Вы должны сделать два отдельных звонка, чтобы сделать это.
Дядя Боб говорит о том, чтобы избежать плоской структуры. Связанные параметры должны быть сгруппированы в объект, и если у вас есть более трех параметров, вполне вероятно, что у вас есть псевдообъект, который дает вам возможность создать соответствующий объект для большего разделения. Хотя в PHP нет отдельного класса
Date
иTime
класса, вы можете подумать, что онDateTime
действительно содержитDate
объект иTime
объект.Вы могли бы иметь следующую структуру:
Обязательно ли устанавливать два или три параметра каждый раз? Если вы хотите изменить только час или день, теперь это легко сделать. Да, объект должен быть проверен, чтобы убедиться, что каждый параметр работает с другими, но в любом случае это было раньше.
Самое главное, легче ли понять и, следовательно, поддерживать? Блок кода внизу больше, чем одна
mktime()
функция, но я бы сказал, что это гораздо легче понять; даже у непрограммиста не возникло бы больших проблем с тем, что он делает. Цель - не всегда более короткий код или более умный код, но более поддерживаемый код.О, и не используйте глобалы!
источник
Здесь много хороших ответов, но большинство из них не решают проблему. Почему эти эмпирические правила? Речь идет о сфере действия, о зависимостях и о правильном моделировании.
Глобальные аргументы хуже, потому что это выглядит так, будто вы сделали это проще, а на самом деле вы только скрыли сложность. Вы больше не видите этого в прототипе, но вы все равно должны осознавать это (что трудно, так как вы больше не можете его видеть), и вы не можете помочь себе понять логику функции, потому что быть другой скрытой логикой, мешающей вам за спиной. Ваша сфера применения повсеместна, и вы ввели зависимость от чего бы то ни было, потому что теперь все может связываться с вашей переменной. Фигово.
Главное, что нужно сохранить для функции, это то, что вы можете понять, что она делает, посмотрев на прототип и вызов. Поэтому имя должно быть четким и однозначным. Но также, чем больше аргументов, тем сложнее будет понять, что он делает. Это расширяет сферу вашей головы, происходит слишком много вещей, поэтому вы хотите ограничить количество. Неважно, с какими аргументами вы имеете дело, некоторые хуже других. Дополнительный необязательный логический тип, который учитывает регистронезависимую обработку, не усложняет понимание функции, поэтому вам не захочется делать с этим большие проблемы. В качестве примечания, перечисления приводят лучшие аргументы, чем логические, потому что значение перечисления очевидно в вызове.
Типичная проблема не в том, что вы пишете новую функцию с огромным количеством аргументов, вы начнете с нескольких, когда еще не поймете, насколько сложна действительно решаемая вами проблема. По мере развития вашей программы списки аргументов постепенно становятся длиннее. После того, как модель пришла вам в голову, вы хотите сохранить ее, потому что это безопасная ссылка, которую вы знаете. Но, оглядываясь назад, модель, возможно, не так уж велика. Вы пропустили шаг или слишком в логике, и вы не смогли распознать сущность или два. «Хорошо ... Я мог бы начать заново и потратить день или два на рефакторинг своего кода или… я мог бы добавить этот аргумент, чтобы я мог все-таки сделать это правильно и покончить с этим. Пока. Для этого сценария» Чтобы убрать эту ошибку с моей тарелки, чтобы я мог переместить заметку "Готово".
Чем чаще вы переходите ко второму решению, тем более дорогостоящим будет дальнейшее обслуживание и тем сложнее и непривлекательнее будет рефакторинг.
Не существует единого решения для уменьшения числа аргументов в существующей функции. Простое объединение их в составы на самом деле не делает вещи проще, это просто еще один способ вытереть сложность под ковром. Чтобы сделать это правильно, нужно снова посмотреть на весь стек вызовов и распознать, что отсутствует или было сделано неправильно.
источник
Несколько раз я обнаружил, что группирование множества параметров, которые были отправлены вместе, улучшило ситуацию.
Это заставляет вас дать доброе имя этому сочетанию понятий, которые используются вместе. Если вы используете эти параметры вместе, это может означать, что они имеют отношение (или что вы вообще не должны использовать их вместе).
Однажды с объектом я обычно нахожу, что некоторая функциональность может быть перенесена на этот явно тупой объект. Обычно его легко тестировать, а отличная когезия и низкий уровень сцепления делают его еще лучше.
В следующий раз, когда мне нужно будет добавить новый параметр, у меня есть хорошее место, чтобы включить его без изменения сигнатуры многих методов.
Так что это может не сработать в 100% случаев, но спросите себя, должен ли этот список параметров быть сгруппирован в объекте. И пожалуйста. Не используйте нетипизированные классы, такие как Tuple, чтобы избежать создания объекта. Вы используете объектно-ориентированное программирование, не против создавать больше объектов, если они вам нужны.
источник
При всем моем уважении, я почти уверен, что вы полностью упустили смысл иметь небольшое количество параметров в функции.
Идея состоит в том, что мозг может хранить только столько «активной информации» за один раз, и если у вас есть n параметров в функции, у вас есть еще n фрагментов «активной информации», которые должны быть в вашем мозгу, чтобы легко и точно понять, что делает фрагмент кода (Стив Макконнелл, в Code Complete (гораздо лучшая книга, IMO), говорит что-то похожее о 7 переменных в теле метода: редко мы достигаем этого, но больше, и вы теряете умение держать все прямо в голове).
Смысл небольшого числа переменных в том, чтобы поддерживать небольшие когнитивные требования для работы с этим кодом, чтобы вы могли работать над ним (или читать его) более эффективно. Побочной причиной этого является то, что хорошо структурированный код будет иметь все меньше и меньше параметров (например, плохо структурированный код имеет тенденцию группировать кучу вещей в беспорядок).
Передавая объекты вместо значений, возможно, вы получаете уровень абстракции для своего мозга, потому что теперь ему нужно понять, что да, у меня есть SearchContext для работы здесь, вместо того, чтобы думать о 15 свойствах, которые могут находиться в этом контексте поиска.
Пытаясь использовать глобальные переменные, вы полностью пошли по неверному пути. Теперь вы не только не решили проблемы с наличием слишком большого количества параметров для функции, вы взяли эту проблему и бросили ее в гораздо более лучшую проблему, которую вам теперь приходится переносить в уме!
Теперь вместо того, чтобы работать только на функциональном уровне, вам необходимо учитывать глобальную сферу вашего проекта (черт возьми, как ужасно! Я содрогаюсь ...). У вас даже нет всей вашей информации перед функцией (дерьмо, что это за имя глобальной переменной?) (Я надеюсь, что это не было изменено чем-то другим, так как я вызвал эту функцию).
Глобальные переменные - одна из самых худших вещей, которую можно увидеть в проекте (большой или маленький). Они обозначают инвалидность для правильного управления областью, что является очень фундаментальным навыком для программирования. Oни. Находятся. Зло.
Вынеся параметры из вашей функции и поместив их в глобальные переменные, вы застрелились в полу (или в ноге, или в лице). И не дай Бог, вы когда-нибудь решите, что, эй, я могу использовать это глобально для чего-то другого ... мой разум дрожит от этой мысли.
Весь идеал состоит в том, чтобы держать вещи простыми в управлении, и глобальные переменные НЕ собираются делать это. Я бы сказал, что это одна из худших вещей, которые вы можете сделать, чтобы пойти в противоположном направлении.
источник
Я нашел очень эффективный подход (в JavaScript), чтобы минимизировать трение между интерфейсами: использовать единый интерфейс для всех модулей , в частности: функции с одним параметром.
Когда вам нужно несколько параметров: используйте один объект / хэш или массив.
Терпите меня, я обещаю, что я не троллю ...
Прежде чем сказать «что хорошего в функции с одним параметром?» Или «Есть ли разница между функциями 1 Array и multi arg?»
Ну да. Это, возможно, визуально неуловимо, но различие многократно - я исследую множество преимуществ здесь
Очевидно, некоторые люди думают, что 3 - это правильное количество аргументов. Некоторые думают, что это 2. Ну, это все еще напрашивается вопрос, "какой параметр идет в arg [0]?" Вместо выбора опции, которая ограничивает интерфейс более жестким объявлением.
Полагаю, я выступаю за более радикальную позицию: не полагайтесь на позиционные аргументы. Я просто чувствую, что это хрупко и приводит к спорам о позиции чертовых аргументов. Пропустите его и идите прямо к неизбежной борьбе за имена функций и переменных. 😉
Если серьезно, то после установления имен, надеюсь, вы получите код, подобный следующему, который несколько самодокументируется, не зависит от позиции и позволяет обрабатывать будущие изменения параметров внутри функции:
источник