Яка хороша практика кодування, коли робити функцію / метод для невеликих повторюваних сегментів коду?


12

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

Відповіді:


29

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

Наприклад, у "Чистому коді" Роберт К. Мартін наводить такий приклад: Який із них ви б краще бачили? Це:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
    (employee.age > 65))

Або це?

if (employee.isEligibleForFullBenefits())

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

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


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

11
Мені сподобався цей приклад. Раптом вам більше не потрібен цей коментар. Це правило : якщо ваш коментар можна перетворити на назву змінної або функції, зробіть це!
Каролі Горват

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

+1 Цей код може бути навіть швидшим, принаймні, якщо він повинен бути JIT-ed - ви платите лише за те, що використовуєте.
Робота

1
також відомий як Ім’я розкриття імен .
rwong

13

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


1
Подивіться, на яку довжину йдуть програмісти, щоб уникнути написання коментарів?
Альгер

1
@Alger як слід
MatrixFrog

6

Якщо він використовується в більш ніж одному місці, і

  • це, ймовірно, зміниться, або
  • це складно правильно

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


3
Питання полягає в тому, чому б ви не написали функцію для часто повторюваного фрагмента коду, навіть якщо це не складно отримати правильно або, ймовірно, зміниться? (Моє правило: якщо його повторне і довше, ніж виклик функції, зробіть це функцією)
Вінстон Еверт

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

@ Вінстон: це залежить від мови, якою ви користуєтеся. Не кожна конструкція може бути природно захоплена як функція, функція може зайняти більше місця, ніж вихідний код (думаємо, C і повертається за вказівником), виклики функцій можуть мати накладні витрати.
Фред Фоо

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

Якщо фрагмент коду обчислює декілька значень, скажімо float x, int yі double density, то налаштування цих обчислень як функції C може бути складнішим, ніж просто повторення коду, оскільки вам доведеться розробити спосіб виведення всіх трьох значень. Якщо самі повторні обчислення є тривіальними, іноді краще просто залишити їх в рядку.
Фред Фоо

4

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

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


Остерігайтеся набору тексту качок, якщо наразі реалізація схожа, але функціональність фактично відрізняється, то об'єднання двох робить це дратує, як пекло, щоб розділитись назад. Особливо мовами з поганою підтримкою IDE (ага, я працюю в C ++ ...)
Матьє М. М.

З іншого боку, утримуючи їх окремо, ви маєте дві функції, які роблять те саме, що перевірити, половина шансів на виконання вашого коду, два місця, в яких може виповзнути той самий помилка, і ви повинні пам'ятати, щоб виправити ту, в якій помилка ще не виявлена Я хотів би ще працювати в C ++, незважаючи на підтримку IDE ;-)
Nicola Musatti

1

Пошук " рефакторингу " приведе вас до багатьох ресурсів для "кращих практик" для цього дуже поширеного процесу. Дещо відома стаття " Раз і тільки один раз" - це чудова історична довідка, що пояснює, що деякі вважають "найкращими методами" для проблем, викликаних вашим запитанням. Крім того, ще більш загальна концепція відома як " Не повторюй себе" (DRY) . По-справжньому поглиблений набір відповідей на ваше запитання читайте чудову класику Мартіна Фаулера « Рефакторинг: вдосконалення дизайну існуючого коду» , яка охоплює деякі найвідоміші поради щодо рефакторингу , які ви інтуїтивно намагаєтеся виконати. !


0

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


1
якщо це зміниться, ще більше підстав для рефакторації. Тоді вам доведеться змінити тільки один раз
Shug

0

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

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

Дивіться статтю у Вікіпедії про концепцію згуртованості коду .


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

0

Ви повинні розрізняти функції в сенсі структурованого програмування та методи класу.

У вашому прикладі те, що ви показали - це метод a як такий, не повинен кодуватися в рядку.

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

Ця відмінність важлива особливо у великих проектах.

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

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