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


49

Я читав перші глави чистого коду Роберта К. Мартіна, і мені здається, це досить добре, але я сумніваюся, в одній частині зазначається, що добре (пізнавально), що функції повинні мати якомога менше параметрів Наскільки це можливо, це навіть припускає, що 3 і більше параметрів занадто багато для функції (що я вважаю дуже перебільшеним і ідеалістичним), тому я почав цікавитися ...

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

Тому я хотів почути, що ви думаєте про це, чи варто використовувати глобальні змінні для зменшення кількості параметрів функцій чи ні? У яких випадках це було б?

Я думаю, що це залежить від кількох факторів:

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

На мою думку, якщо розмір вихідного коду порівняно невеликий (наприклад, менше 600 рядків коду), є багато функцій, передаються ті ж змінні, що і параметри, а функції мають багато параметрів, тоді використовувати глобальні змінні було б варто, але я хотів би знати ...

  • Ви поділяєте мою думку?
  • Що ви думаєте про інші випадки, коли вихідний код більший тощо?

PS . Я бачив цю публікацію , заголовки дуже схожі, але він не запитує, що я хочу знати.


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
Це не схоже на проблему дизайну. Я все ще думаю, що передача параметрів функцій є найкращим дизайном. У такій системі AI, як ви описуєте, мені буде корисно писати одиничні тести для тестування фрагментів системи, і найпростіший спосіб зробити це за допомогою параметрів.
Самуїл

96
Більше параметрів ускладнює розуміння підпрограми, глобальні змінні ускладнюють всю програму, тобто всі підпрограми важче зрозуміти.
Йорг W Міттаг

2
Я підтримую кодову базу, де деякі функції приймають більше десятка параметрів. Це величезна витрата часу - кожен раз, коли мені потрібно викликати функцію, мені потрібно відкрити цей файл в іншому вікні, щоб я знав, в якому порядку потрібно вказати параметри. Якщо я використовував IDE, який дав мені щось на кшталт intellisense, або якщо я використовував мову, яка назвала параметри, це було б не так вже й погано, але хто може пригадати, в якому порядку є десяток параметрів для всіх цих функцій?
Джеррі Єремія

6
Відповідь правильна у тому, що вона говорить, але, здається, це сприймає ОП з непорозумінням щодо рекомендацій у "Чистому кодексі" як належне. Я впевнений, що в цій книзі немає жодної рекомендації замінювати параметри функції глобальними.
Док Браун

68

Вам слід уникати таких глобальних змінних, як чума .

Я б не поставити жорсткий межа числа аргументів (наприклад , 3 або 4), але ви дійсно хочете , щоб тримати їх до мінімуму, якщо це можливо.

Використовуйте structs (або об'єкти в C ++), щоб об'єднати змінні в одне ціле і передати (посиланням) на функції. Зазвичай функція отримує передану їй структуру або об'єкт (з кількома різними речами) разом з парою інших параметрів, які сповіщають функцію щось робити з struct.

Для гарного, чистого, модульного коду спробуйте дотримуватися єдиного принципу відповідальності . Зробіть це зі своїми структурами (або об'єктами), функціями та вихідними файлами. Якщо це зробити, то природне число параметрів, переданих функції, буде очевидним.


5
Яка принципова відмінність між передачею десятків параметрів, прихованих у структурі, та передачею їх явно?
Руслан

21
@ Русланська згуртованість.
abuzittin gillifirca

9
І ви, швидше за все, перефактуруєте функцію на більш дрібні функції, оскільки ви можете просто передати один параметр до підфункцій замість десятків параметрів. І менший ризик змішування параметрів, якщо ви використовуєте позиційні аргументи.
Ганс Олссон

8
Це добре, але ви повинні забезпечити узгодженість у структурах - переконайтесь, що параметри, згруповані в структуру, "пов'язані". Ви можете використовувати декілька структур за певних обставин.
Ендрю Доддс

8
@abuzittingillifirca Згуртування ви не отримуєте автоматично. Якщо єдиним виправданням для введення параметрів у структуру є передача їх певній функції, то згуртованість, ймовірно, ілюзорна.
sdenham

55

Ми говоримо про когнітивне навантаження, а не про синтаксис. Отже, питання ... Що таке параметр у цьому контексті?

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

У цьому сенсі глобальні змінні, які використовує функція, - це параметри. Це параметри, які не відображаються в його підписі, які мають замовлення на будівництво, контроль доступу та залишки.

Якщо зазначений параметр не називається наскрізною проблемою , це якийсь загальнопрограмний стан, який використовується все, але нічого не змінює (наприклад, об'єкт журналу), не слід замінювати параметри функції глобальними змінними. Вони все ще були б параметрами, але неприємнішими.


11
Тобі +1, будь то туалет чи комод, вони підбирають те саме. Хороша робота із вказівкою вовка в овечому одязі.
Джаред Сміт

1
+1 за твердження, що як багато парм, так і глобальні періоди погані. Але я хочу щось уточнити. У більшості мов примітивні параметри передаються за значенням за замовчуванням (Java), а в інших ви можете передавати їх за значенням явно (PL / SQL). З іншого боку, до глобальних примітивів завжди доступ посилаються (так би мовити). Тож параметри, принаймні примітивних типів, завжди безпечніші, ніж глобальні змінні. Хоча, звичайно, більше двох-трьох параметрів - це запах, а наявність дванадцяти параметрів - це величезний запах, який повинен бути відновлений.
Tulains Córdova

4
Абсолютно, глобальна змінна IS є прихованим параметром.
Білл К

+1 До вашої точки зору, я бачив моделювання MATLAB, які покладаються на глобальні змінні для передачі даних. Результат був абсолютно нечитабельним, оскільки важко було сказати, які змінні були параметрами для якої функції.
Корт Аммон

34

ІМХО ваше запитання ґрунтується на непорозумінні. У "Чистому коді" Боб Мартін не пропонує замінити повторні параметри функції глобальними, це було б дійсно жахливою порадою. Він пропонує замінити їх приватними змінними класу класу функції. А також він пропонує невеликі, згуртовані класи (як правило, менше 600 згаданих вами рядків коду), тож ці змінні учасники точно не є глобальними.

Отже, коли у вас є думка в контексті з менш ніж 600 рядками "використання глобальних змінних варто було б" , то ви прекрасно поділяєте думку дядька Боба. Звичайно, дискусійним є те, якщо "максимум 3 параметри" є ідеальним числом, і якщо це правило іноді призводить до занадто великої кількості змінних членів навіть у малих класах. ІМХО це компроміс, немає жорсткого правила, де провести межу.


10
Я ніколи не розумів, чому хтось вважає за краще зробити свій клас стаціонарним, заповнивши параметри в конструктор, а не просто живучи з фактичним аргументом. Це завжди вражало мене як величезне збільшення складності. (Приклад із реального життя, який я бачив, це об'єкт підключення до бази даних, який зробив неможливим намагання відстежувати стан бази даних через програму, поєднуючись із введенням залежностей.) Але, можливо, Код Чистого має більше сказати про це конкретно предмет. Зрозуміло, глобалісти є ще гіршим варіантом щодо того, щоб зробити речі державними.
jpmc26

2
@ jpmc26: один отримує «величезне збільшення складності», якщо класи стають занадто великими і отримують занадто багато змінних членів, тому результат вже не є згуртованим.
Док Браун

4
Я думаю, що ця реакція ігнорує труднощі в управлінні станом (які можуть бути навіть незмінними), що розповсюджуються на багато класів. Коли функція залежить не тільки від аргументів, але і від того, як об’єкт був побудований (або навіть модифікований протягом його життя), розуміння його поточного стану під час здійснення певного виклику стає складніше. Тепер вам слід відстежити спорудження іншого об'єкта, просто зрозуміти, що буде робити дзвінок. Додавання змінних екземплярів активно збільшує обсяг стану програми, якщо ви не сконструюєте об'єкт і негайно викинете його?
jpmc26

3
@ jpmc26 Один шаблон, який я регулярно використовую під час рефакторингу, полягає в тому, що конструктор діє як встановлення контексту, тоді аргументи методу є специфічними для дії. Об'єкт не зовсім старий, тому що стан, який він містить, ніколи не змінюється, але переміщення цих загальних дій у методи цього контейнера значно покращує читабельність, коли це використовується (контекст встановлюється лише один раз, схожий на менеджерів контексту python), і зменшує дублювання, якщо до методів об'єкта робиться кілька викликів.
Ізката

3
+1 Якщо чітко сказати, що змінні члена не є глобальними змінними. Багато людей думають, що вони є.
Tulains Córdova

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();

Тут ми домоглися такого ж зменшення кількості параметрів, але насправді проект погіршився .

Підсумок: Для будь-яких порад щодо програмування та принципів роботи важливо зрозуміти основні міркування.


4
+1 приємна, конструктивна, зрозуміла, нетеоретична відповідь.
AnoE

1
Не кажучи вже про те, що, на біса, ваш "квадрат", що має атрибут довжини та висоти. :)
Wildcard

1
+1 за визнання того, що очевидний третій спосіб, який має на увазі деякі відповіді (тобто багато присвоєння якійсь структурі / об'єкту до виклику функції), не є кращим.
benxyzzy

@Wildcard: Дякую, змінив його на "прямокутник", щоб не плутати проблему!
ЖакБ

7

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

Ні

Я прочитав перші глави цієї книги

Ви прочитали решту книги?

Глобальний - це лише прихований параметр. Вони викликають різний біль. Але це все-таки біль. Перестаньте думати про способи обійти це правило. Подумайте, як це слідкувати.

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

Це речі. У красиво маркованій коробці. Чому має значення, скільки ящиків у вас, коли ви можете помістити в неї будь-які речі?

Це вартість доставки та обробки.

Move(1, 2, 3, 4)

Скажіть, ви можете це прочитати. Продовжуйте, спробуйте.

Move(PointA, PointB)

Ось чому.

Цей трюк називається об'єктом введення параметра .

І так, це лише хитрість, якщо все, що ви робите, - це підрахунок параметрів. Що вам слід порахувати - це ІДЕЇ! Абстракції! Скільки ти змушуєш мене задуматися одразу? Не ускладнювати.

Тепер це той самий підрахунок:

Move(xyx, y)

О! Це жахливо! Що тут пішло не так?

Недостатньо обмежити кількість ідей. Вони повинні мати чіткі ідеї. Що за чорт - це ксикс?

Зараз це ще слабко. Що є більш потужним способом думати про це?

Функції повинні бути невеликими. Не менший за це.

Дядько Боб

Move(PointB)

Чому змушувати функцію робити більше, ніж це дійсно потрібно робити? Принцип єдиної відповідальності стосується не лише занять. Серйозно, варто змінити всю архітектуру просто, щоб одна функція не перетворилася на перевантажений кошмар з 10 іноді пов'язаними параметрами, деякі з яких не можна використовувати з іншими.

Я бачив код, де найпоширеніша кількість рядків у функції була 1. Серйозно. Я не кажу, що ти повинен писати так, але так, ні, не кажи мені, що глобальний - це ТІЛЬКИ спосіб, яким ти можеш дотримуватись цього правила. Перестаньте намагатися вийти з рефакторингу цієї функції належним чином. Ви знаєте, що можете. Це може розбитись на кілька функцій. Насправді це може перетворитися на кілька об’єктів. Пекло, ви навіть можете розбити частину цього в абсолютно іншому додатку.

Книга не каже вам рахувати ваші параметри. Це говорить вам звернути увагу на біль, який ви завдаєте. Все, що фіксує біль, усуває проблему. Просто майте на увазі, коли ви просто торгуєте одним болем за інший.


3
"Ви прочитали решту книги?" На ваше запитання відповідають у перших 8 словах мого допису ...
OiciTrap

Я повністю згоден - справа в тому, щоб розкласти проблему на невеликі шматочки. Об'єкти дійсно можуть допомогти впорядкувати ці фрагменти та згрупувати їх, вони також дозволяють передавати одну концептуальну одиницю як параметр, а не купу непоєднаних фрагментів. Я отримую анци, коли бачу метод з більш ніж 3 параметрами. 5 - вказівка ​​на те, що моя конструкція пішла на лайно, і мені потрібен ще один раунд рефакторингу. Найкращий спосіб, який я знайшов для вирішення проблем дизайну, таких як підрахунок параметрів, - це просто переробляти речі на менші, простіші одиниці (класи / методи).
Білл К

2
Тон цієї відповіді можна було б покращити. Він читається як дуже різкий і суворий. Наприклад: "Скажіть, ви можете це прочитати. Продовжуйте, спробуйте". видається дуже агресивним і може бути переписаний як "З двох викликів функцій вище / нижче, який з них легше читати?" Вам слід спробувати домогтися точки без агресії. ОП просто намагається навчитися.
Kyle A

Не забувайте, що ОП також намагається не спати.
candied_orange

4

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

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

Якщо вам потрібно передавати глобальні змінні замість параметра, то краще переробити код.

Всього два мої центи.


"Я б ніколи не використовував глобальні змінні для зменшення параметрів" повністю згоден. Це створює непотрібне зчеплення.
bytedev

2

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

Якщо ви використовуєте більше 3 в методі на мові ОО, то вам слід врахувати, чи парами певним чином не пов'язані один з одним, і тому ви дійсно замість цього повинні переходити в об'єкт?

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

Не використовуйте глобальні змінні як спосіб обійти більше парам! Це заміна однієї поганої практики на ще гіршу!


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 ]]]]]]] )

Ви не вважаєте це заплутаним? Функція називається "make time", але вона займає параметри дня, місяця та року, а також три часові параметри. Наскільки легко запам'ятати, в якому порядку вони заходять? Що робити, якщо бачите 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()функція, але я б стверджував, що це набагато простіше зрозуміти; навіть у непрограміста не було б багато проблем з розробкою того, що він робить. Мета - це не завжди коротший код або розумніший код, але більш доцільний код.

О, і не користуйтеся глобальними!


1

Тут багато хороших відповідей, але більшість не звертаються до цього питання. Чому ці великі правила? Це про сферу застосування, про залежності і про правильне моделювання.

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

Головне, що потрібно підтримувати для функції, це те, що ви можете зрозуміти, що вона робить, подивившись на прототип і зателефонувавши. Тож назва повинна бути чіткою та однозначною. Але також, чим більше аргументів, тим важче буде зрозуміти, що він робить. Це розширює сферу в вашій голові, надто багато чого відбувається, саме тому ви хочете обмежити кількість. Має значення, з якими аргументами ви маєте справу, хоча деякі з них гірші за інші. Додатковий додатковий булевий режим, що дозволяє обробляти нечутливу обробку випадків, не ускладнює цю функцію важче для розуміння, тому ви не хочете робити з цим великої справи. Як бічне зауваження, енуми висловлюють кращі аргументи, ніж булеві, оскільки значення дзвінка очевидно в дзвінку.

Типова проблема не в тому, що ви пишете нову функцію з величезною кількістю аргументів, ви почнете лише з кількох, коли ще не зрозумієте, наскільки складною є проблема, яку ви вирішуєте насправді. У міру розвитку вашої програми списки аргументів поступово стають довшими. Після того, як модель з’явилася у вас на думці, ви хочете зберегти її, оскільки це безпечна довідка, яку ви знаєте. Але в перспективі модель може бути не такою великою. Ви пропустили крок чи занадто логіку, і вам не вдалося розпізнати сутність чи два. "Гаразд ... я міг би почати спочатку і провести день чи два, перефактуруючи свій код, або ... я міг би додати цей аргумент, щоб я змусив його зробити все правильно і з цим зробити все. Поки що. Для цього сценарію . Щоб усунути цю помилку з моєї тарілки, щоб я міг перенести наліпку ".

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

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


0

Кілька разів я виявляв, що групування безлічі параметрів, які були надіслані разом, покращувало речі.

  • Це змушує вас дати хороше ім’я цій групі понять, які використовуються разом. Якщо ви разом використовуєте ці параметри, можливо, вони мають відношення (або взагалі не слід використовувати разом).

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

  • Наступного разу, коли мені потрібно буде додати новий параметр, я маю приємне місце, щоб його включити, не змінюючи підпис багатьох методів.

Тож воно може не працювати в 100% разів, але запитайте себе, чи слід цей список параметрів групувати в об’єкт. І будь ласка. Не використовуйте нетипізовані класи типу Tuple, щоб уникнути створення об'єкта. Ви використовуєте об'єктно-орієнтоване програмування, не проти створити більше об'єктів, якщо вони вам потрібні.


0

З усією повагою я впевнений, що ви повністю пропустили пункт про наявність невеликої кількості параметрів у функції.

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

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

Передаючи об'єкти замість значень, можливо, ви отримуєте рівень абстракції для вашого мозку, тому що тепер він повинен усвідомити так, я маю SearchContext для роботи тут, а не думати про 15 властивостей, які можуть бути в цьому контексті пошуку.

Спробувавши використовувати глобальні змінні, ви повністю пішли в абсолютно неправильному напрямку. Тепер ви не тільки не вирішили проблем із занадто великою кількістю параметрів для функції, ви взяли цю проблему і кинули її в набагато кращу проблему, яку вам зараз доведеться вирішувати у своїй думці!

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

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

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

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


-1

Я знайшов високоефективний підхід (в JavaScript) для мінімізації тертя між інтерфейсами: Використовуйте єдиний інтерфейс для всіх модулів , зокрема: функцій однієї парами.

Коли вам потрібно кілька параметрів: Використовуйте один об'єкт / хеш або масив.

Візьми з собою, я обіцяю, що я не тролінгу ...

Перш ніж сказати, "що хорошого є функцією однієї парами?" Або "Чи є різниця між функцією 1 Array і Multi arg?"

Ну так. Це, мабуть, візуально тонко, але різниця багаторазова - я досліджую багато переваг тут

Мабуть, деякі ppl вважають, що 3 - це правильний аргумент. Деякі думають, що це 2. Ну, і досі виникає питання "який параметр входить в аргумент [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

Чому це "підробка", якщо я досягну мети, яку я поставив перед собою? Я ставлю більш високий пріоритет на названі аргументи. Оскільки позиційні аргументи не очевидні для виклику коду, а з # іменованими функціями розробник повинен запам'ятати, не корисно запам’ятовувати, які параметри є де і які необов’язкові. ... Зрештою ви захочете додати необхідний параметр після необов'язкових записів, удачі документуючи та модернізуючи цей будинок карт.
Ден Леві

2
Названі парами також є підкріплювальним прийомом навчання - люди надають більше значення колекціям слів.
Ден Леві
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.