Чистый код: функции с несколькими параметрами [закрыто]

49

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

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

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

Я думаю, что это зависит от нескольких факторов:

  • Размер исходного кода.
  • Количество параметров в среднем функций.
  • Количество функций.
  • Частота, с которой используются одни и те же переменные.

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

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

PS . Я видел этот пост , названия очень похожи, но он не спрашивает, что я хочу знать.

OiciTrap
источник
144
Я не думаю, что альтернативой будут глобальные переменные, а объединение аргументов в объекты. Это, вероятно, скорее предложение, которое postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)является вонючей версией postLetter(Address address). Продолжайте читать книгу, она, надеюсь, скажет что-то подобное.
Натан Купер
3
@DocBrown Я взял вопрос, чтобы обозначить что-то более похожее на то, что дядя Боб говорит, что не используйте более 3 параметров, поэтому я обхожу эту проблему, используя глобальные переменные, верно? :-) Я думаю, что скорее всего автор не знает, что есть лучшие способы обойти эту проблему - как упомянуто в ответах ниже.
bytedev
9
Не более n параметров - это практическое правило (для любого значения n), не выгравированное на ромбе. Не путайте добрый совет с мандатом. Множество параметров - это, как правило, запах кода, который вы слишком много делаете в одной функции / методе. Люди привыкли избегать разделения на несколько функций, чтобы избежать дополнительных затрат на дополнительные вызовы. Немногие приложения стали настолько интенсивными, и профилировщик может сказать вам, когда и где вам нужно избегать дополнительных вызовов.
Джаред Смит
14
Это показывает, что не так с этим правилом без суждений: оно открывает дверь для безошибочных «решений». Если функция имеет много аргументов, она может указывать на неоптимальный дизайн, обычно не только функции, но и контекста, в котором она используется. Решение (если оно необходимо) заключается в поиске рефакторинга кода. Я не могу дать вам простое общее правило без суждений о том, как это сделать, но это не означает, что «не более N аргументов» - это хорошее правило.
sdenham
4
Если у вас слишком много параметров для функции, вероятность того, что некоторые из них связаны, должна быть сгруппирована в объект, который затем становится единым параметром, инкапсулирующим несколько фрагментов данных. Здесь есть третий вариант.

Ответы:

113

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

... те же переменные передаются в качестве параметров

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

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

Самуил
источник
Хорошо, хорошо слышать другие мнения, но насчет запаха дизайна , я программирую на C проблемах, которые решаются методами искусственного интеллекта, и я склонен использовать много функций, которые почти всегда используют одни и те же матрицы, массивы или переменные (которые Я передаю в качестве параметров функции), я говорю это, потому что не чувствую, что могу поместить эти переменные в общую концепцию / вещь, такую ​​как структура или объединение, чтобы я не знал, как сделать лучший дизайн, вот почему я думаю, что использование глобальных переменных в этом случае может стоить, но, скорее всего, я ошибаюсь.
OiciTrap
1
Это не похоже на проблему дизайна. Я все еще думаю, что передача параметров в функции - лучший дизайн. В системе ИИ, которую вы описываете, мне было бы полезно написать модульные тесты для тестирования частей системы, и самый простой способ сделать это с помощью параметров.
Самуил
96
Чем больше параметров, тем сложнее понять подпрограмму, глобальные переменные затрудняют понимание всей программы, т. Е. Всех подпрограмм .
Йорг Миттаг
2
Я поддерживаю базу кода, где некоторые функции принимают более десятка параметров. Это огромная трата времени - каждый раз, когда мне нужно вызвать функцию, мне нужно открыть этот файл в другом окне, чтобы я знал, в каком порядке должны быть указаны параметры. Если бы я использовал IDE, которая давала мне что-то вроде intellisense, или если бы я использовал язык с именованными параметрами, это было бы не так уж плохо, но кто может вспомнить, в каком порядке находится дюжина параметров для всех этих функций?
Джерри Иеремия
6
Ответ правильный в том, что в нем говорится, тем не менее, кажется, что ОП воспринимает недопонимание относительно рекомендаций в «Чистом коде» как должное. Я уверен, что в этой книге нет рекомендаций по замене параметров функций глобальными.
Док Браун
68

Вы должны избегать глобальных переменных, таких как чума .

Я бы не стал жестко ограничивать количество аргументов (например, 3 или 4), но вы , по возможности, хотите свести их к минимуму.

Используйте structs (или объекты в C ++), чтобы сгруппировать переменные в одну сущность и передать их (по ссылке) в функции. Обычно функция получает структуру или объект (с несколькими различными вещами в нем), переданные ей вместе с парой других параметров, которые говорят функции сделать что-то с struct.

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

Роберт Бристоу-Джонсон
источник
5
В чем принципиальная разница между передачей десятков параметров, скрытых в структуре, и передачей их явно?
Руслан
21
@ Руслан Сплоченность.
abuzittin gillifirca
9
И вы, скорее всего, будете реорганизовывать функцию в более мелкие функции, поскольку вы можете просто передать один параметр подфункциям вместо десятков параметров. И меньше риск перепутать параметры, если вы используете позиционные аргументы.
Ганс Олссон
8
Это нормально, но вы должны обеспечить согласованность в структурах - убедитесь, что параметры, сгруппированные в структуру, являются «связанными». При некоторых обстоятельствах вы можете использовать более одной структуры.
Эндрю Доддс
8
@abuzittingillifirca Вы не получаете сплоченность автоматически. Если единственное оправдание для помещения параметров в структуру - это передать их определенной функции, то сплоченность, вероятно, иллюзорна.
sdenham
55

Мы говорим о когнитивной нагрузке, а не о синтаксисе. Итак, вопрос в том ... Что является параметром в этом контексте?

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

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

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

Quentin
источник
11
Вам +1, будь то туалет или комод, они пахнут одинаково. Хорошая работа, указывая на волка в овечьей шкуре.
Джаред Смит
1
+1 за то, что многие пармы и глобальные переменные плохие. Но я хочу кое-что уточнить. В большинстве языков примитивные параметры передаются по значению по умолчанию (Java), а в других вы можете передавать их по значению явно (PL / SQL). С другой стороны, глобальные примитивы всегда доступны по ссылке (так сказать). Таким образом, параметры, по крайней мере, примитивных типов, всегда безопаснее, чем глобальные переменные. Хотя, конечно, наличие более двух или трех параметров - это запах, а наличие двенадцати параметров - это огромный запах, который следует подвергнуть рефакторингу.
Тулаинс Кордова
4
Безусловно, глобальная переменная является скрытым параметром.
Билл К
+1 К вашему сведению, я видел симуляции MATLAB, которые полагаются на глобальные переменные для передачи данных. Результат оказался совершенно нечитаемым, потому что было очень трудно определить, какие переменные являются параметрами для какой функции.
Корт Аммон
34

ИМХО твой вопрос основан на недоразумении. В «Чистом коде» Боб Мартин не предлагает заменять повторяющиеся параметры функции глобальными, что было бы действительно ужасным советом. Он предлагает заменить их закрытыми переменными-членами класса функции. И он также предлагает небольшие, связные классы (обычно меньше, чем 600 строк кода, которые вы упомянули), поэтому эти переменные-члены определенно не являются глобальными.

Таким образом, если у вас есть мнение в контексте с менее чем 600 строками «использование глобальных переменных стоило бы того» , то вы полностью разделяете мнение дяди Боба. Конечно, это спорно , если «3 параметра в максимуме» идеальное количество, и если это правило иногда приводит к слишком много переменных - членов , даже в небольших классах. ИМХО, это компромисс, нет строгого правила, где проводить черту.

Док Браун
источник
10
Я никогда не понимал, почему кто-то предпочел бы сделать свой класс с состоянием, вставляя параметры в конструктор, а не просто жить с фактическим аргументом. Это всегда казалось мне огромным увеличением сложности. (Примером из реальной жизни, который я видел, является объект подключения к базе данных, который делает невозможным отслеживание состояния базы данных через программу в сочетании с внедрением зависимостей.) Но, возможно, Clean Code может сказать больше об этом конкретном тема. Globals, конечно, еще худший вариант в том, что касается состояния.
jpmc26
2
@ jpmc26: «огромное увеличение сложности» можно получить только в том случае, если классы становятся слишком большими и получают слишком много переменных-членов, поэтому результат уже не является связным.
Док Браун
4
Я думаю, что ответ игнорирует сложность в управлении состоянием (которое может быть даже изменчивым), которое распределено по многим классам. Когда функция зависит не только от аргументов, но и от того, как объект был построен (или даже изменен в течение срока его службы), понимание его текущего состояния при выполнении определенного вызова становится более сложным. Теперь вам нужно отследить конструкцию другого объекта, просто чтобы выяснить, что будет делать вызов. Добавление переменных экземпляра активно увеличивает объем состояния программы, если вы не создадите объект и не выбросите его немедленно?
jpmc26
3
@ jpmc26 Один шаблон, который я регулярно использую при рефакторинге, заключается в том, что конструктор действует как установка контекста, а аргументы метода являются специфическими для действия. Объект не является точно состоящим, поскольку его состояние никогда не изменяется, но перемещение этих общих действий в методы этого контейнера значительно улучшает удобочитаемость, когда он используется (контекст задается только один раз, аналогично менеджерам контекста python), и уменьшает дублирование, если множественные вызовы сделаны к методам объекта.
Изката
3
+1 Для того, чтобы четко сказать, что переменные-члены не являются глобальными переменными. Многие люди думают, что они есть.
Тулаинс Кордова
34

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

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

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

Наличие 7 параметров является определенным предупреждающим знаком. Основная проблема заключается в том, что эти параметры не являются независимыми, а относятся к группам. leftи topпринадлежат друг другу как Position-структура, lengthи heightкак Sizeструктура red, blueи greenкак Colorструктура. А может Colorи прозрачность принадлежит Brushструктуре? Возможно, Positionи Sizeпринадлежат друг другу в Rectangleструктуре, и в этом случае мы можем даже рассмотреть возможность превращения его в Paintметод Rectangleобъекта вместо этого? Таким образом, мы можем в итоге:

Rectangle.Paint(brush);

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

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

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

Итог: для любого совета по программированию и практических правил действительно важно понять основную причину.

JacquesB
источник
4
+1 хороший, конструктивный, понятный, не теоретический ответ.
AnoE
1
Не говоря уже о том, что, черт возьми, твой «квадрат» делает с атрибутом длины и высоты. :)
Wildcard
1
+1 за признание того, что очевидный третий путь, подразумеваемый некоторыми ответами (т. Е. Многими присвоениями некоторой структуре / объекту до вызова функции), не лучше.
benxyzzy
@Wildcard: Спасибо, изменили его на «прямоугольник», чтобы не путать проблему!
JacquesB
7

Стоит ли использовать глобальные переменные для уменьшения количества параметров функций или нет?

Не

Я прочитал первые главы этой книги

Вы читали остальную часть книги?

Глобал - это просто скрытый параметр. Они вызывают разные боли. Но это все еще боль. Хватит думать о способах обойти это правило. Подумай, как ей следовать.

Что такое параметр?

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

Это стоимость доставки и обработки.

Move(1, 2, 3, 4)

Скажи мне, что ты можешь это прочитать. Давай, попробуй.

Move(PointA, PointB)

Вот почему.

Этот трюк называется ввести параметр объекта .

И да, это просто хитрость, если все, что вы делаете, это подсчет параметров. То, что вы должны считать, это ИДЕИ! Абстракция! О чем ты заставляешь меня думать сразу? Будь проще.

Теперь это тот же счет:

Move(xyx, y)

OW! Это ужасно! Что здесь пошло не так?

Недостаточно ограничить количество идей. У них должны быть четкие идеи. Что за хрень?

Теперь это все еще слабо. Какой более мощный способ думать об этом?

Функции должны быть небольшими. Не меньше, чем это.

Дядя боб

Move(PointB)

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

Я видел код, где наиболее распространенное количество строк в функции было 1. Серьезно. Я не говорю, что вы должны писать таким образом, но, боже, не говорите мне, что глобальный - это ЕДИНСТВЕННЫЙ способ соблюдения этого правила. Прекратите пытаться избавиться от рефакторинга этой функции должным образом. Вы знаете, что можете. Это может быть разбито на несколько функций. Это может фактически превратиться в несколько объектов. Черт возьми, вы можете даже разбить часть этого на совершенно другое приложение.

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

candied_orange
источник
3
"Вы прочитали остальную часть книги?" На ваш вопрос отвечают первые 8 слов моего поста ...
OiciTrap
Я полностью согласен - дело в том, чтобы разложить проблему на мелкие кусочки. Объекты действительно могут помочь организовать эти части и сгруппировать их, они также позволяют передавать в качестве параметра одну концептуальную единицу, а не связку не связанных частей. Я начинаю беспокоиться, когда вижу метод с более чем 3 параметрами. 5 - это указание на то, что мой дизайн испортился, и мне нужен еще один раунд рефакторинга. Лучший способ, который я нашел для решения проблем проектирования, таких как подсчет параметров, - это просто преобразовать вещи в меньшие, более простые единицы (классы / методы).
Билл К
2
Тон этого ответа может быть улучшен. Это выглядит очень резким и резким. Например: «Скажите, что вы можете прочитать это. Продолжайте, попробуйте». выглядит очень агрессивно и может быть переписано как «Из двух вызовов функций выше / ниже, какой из них легче прочитать?» Вы должны попытаться объяснить это без агрессии. ОП просто пытается учиться.
Кайл А
Не забывайте, что ОП также пытается не заснуть.
candied_orange
4

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

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

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

Просто мои два цента.

Dimos
источник
«Я бы никогда не использовал глобальные переменные для уменьшения параметров», полностью согласен. Это создает ненужную связь.
bytedev
2

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

Если вы используете более 3 в методе на языке OO, вы должны рассмотреть, не связаны ли параметры каким-либо образом друг с другом, и, следовательно, вы должны вместо этого передавать объект?

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

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

bytedev
источник
1

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

В простых случаях это простой DTO, имеющий в качестве свойств только старые параметры.

Тимоти Тракл
источник
1

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

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

function <functionname>(var1,var2,var3,var4.....var(n)){}

Вышеупомянутая функция будет отредактирована и изменена на [использование ассоциативного массива] -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Я согласен с ответом Роберта Бристоу-Джонсона : вы даже можете использовать структуру для связывания данных в одном объекте.

Нарендер Пармар
источник
1

Взяв пример из 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объект.

Вы могли бы иметь следующую структуру:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

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

Самое главное, легче ли понять и, следовательно, поддерживать? Блок кода внизу больше, чем одна mktime()функция, но я бы сказал, что это гораздо легче понять; даже у непрограммиста не возникло бы больших проблем с тем, что он делает. Цель - не всегда более короткий код или более умный код, но более поддерживаемый код.

О, и не используйте глобалы!

CJ Деннис
источник
1

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

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

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

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

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

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

Мартин Маат
источник
0

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

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

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

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

Так что это может не сработать в 100% случаев, но спросите себя, должен ли этот список параметров быть сгруппирован в объекте. И пожалуйста. Не используйте нетипизированные классы, такие как Tuple, чтобы избежать создания объекта. Вы используете объектно-ориентированное программирование, не против создавать больше объектов, если они вам нужны.

Borjab
источник
0

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

Идея состоит в том, что мозг может хранить только столько «активной информации» за один раз, и если у вас есть n параметров в функции, у вас есть еще n фрагментов «активной информации», которые должны быть в вашем мозгу, чтобы легко и точно понять, что делает фрагмент кода (Стив Макконнелл, в Code Complete (гораздо лучшая книга, IMO), говорит что-то похожее о 7 переменных в теле метода: редко мы достигаем этого, но больше, и вы теряете умение держать все прямо в голове).

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

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

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

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

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

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

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

jleach
источник
-1

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

Когда вам нужно несколько параметров: используйте один объект / хэш или массив.

Терпите меня, я обещаю, что я не троллю ...

Прежде чем сказать «что хорошего в функции с одним параметром?» Или «Есть ли разница между функциями 1 Array и multi arg?»

Ну да. Это, возможно, визуально неуловимо, но различие многократно - я исследую множество преимуществ здесь

Очевидно, некоторые люди думают, что 3 - это правильное количество аргументов. Некоторые думают, что это 2. Ну, это все еще напрашивается вопрос, "какой параметр идет в arg [0]?" Вместо выбора опции, которая ограничивает интерфейс более жестким объявлением.

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

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

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})

Дэн Леви
источник
6
Поддельные именованные аргументы на самом деле не передают только один аргумент.
JDługosz
Почему это «притворство», если я достиг цели, которую поставил перед собой? Я ставлю более высокий приоритет на именованные аргументы. Поскольку позиционные аргументы не очевидны при вызове кода, и с числом именованных функций dev должен запомнить, что не полезно помнить, какие параметры есть, а какие - необязательные. ... В конце концов вы захотите добавить обязательный параметр после опций, удачи в документировании и обновлении этого карточного дома.
Дэн Леви
2
Именованные параметры также являются подкреплением в обучении - люди придают больше значения наборам слов.
Дэн Леви