Який правильний баланс між послідовністю коду та покращенням коду?


53

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

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

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

Отже, наскільки шаблони є частиною стилю коду, і де нам слід провести межу між послідовністю та вдосконаленням?


14
То як би якість коду коли-небудь покращувалася, якби кожен обмежувався "поганим" способом?
Ізката


Коли ви пишете LINQ, ви не маєте на увазі LINQ для SQL? Якщо так, то я міг би погодитися з вашим другом. Якщо ви говорите про LINQ, то я з ним не згоден. Всі мають бути знайомі з LINQ в наші дні. Це не їх вибір. Їм платять, щоб бути знайомими.
Пьотр Перак

@Peri Я мав на увазі просто базовий LINQ - я думаю, мій приклад повинен був стосуватися роботи з IEnumerables, а не DAO.
Роберт Джонсон

2
ICYMI - Комікс Ділберта на цю саму тему: dilbert.com/strips/2013-09-21
Джим Бетханкурт

Відповіді:


53

Щоб дати більш загальну відповідь:

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

  • Наскільки корисний «правильний» спосіб?

    • Іноді нова та вдосконалена найкраща практика різко підвищить продуктивність, усуне помилки, набагато простіше програмувати тощо. У такому випадку я б сильно схилявся до використання нового методу. З іншого боку , "правильний шлях" може бути трохи більше, ніж синтаксичний цукор, або узгоджений ідіоматичний метод робити щось, що насправді не є вищим. У цьому випадку послідовність коду, мабуть, важливіша.
  • Наскільки велика проблема створила б непослідовність?

    • Наскільки взаємопов’язаний новий код із застарілим кодом? Ваш новий код є частиною бібліотеки? Чи створює він об'єкт, який передається багатьом частинам програми? У таких випадках дуже важлива послідовність. Використання нового API або нового способу ведення справ взагалі може створити тонко різні результати, які порушують припущення в інших місцях вашої програми. З іншого боку , якщо ви пишете досить ізольований фрагмент коду, невідповідність є меншою ймовірністю.
    • Наскільки велика і наскільки зріла база вашого коду? Скільки розробників потрібно зрозуміти це і працювати над ним? Узгоджені, узгоджені стандарти набагато важливіші для великих проектів.
    • Чи потрібно запускати код у старих середовищах, які можуть не підтримувати новітні функції?

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

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


7
Дуже хороша і врівноважена відповідь (+1). На мій досвід, команда може бути більш продуктивною, якщо всі погоджуються щодо відносно невеликого набору добре зрозумілих ідіом, ніж якщо кожен член команди може вільно використовувати нові та різні ідіоми, які іншим членам команди може бути важко зрозуміти. Невеликий момент щодо твердження "переписати існуючий код таким чином, щоб він використовував новітні практики та був послідовним": "останнє" автоматично не означає "краще". Завжди потрібно вирішувати від конкретного випадку.
Джорджіо

1
@Giorgio, дякую за відгуки; Я налаштував мову підсумкової точки.

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

+1. Погоджена, ретельна та зважена відповідь - добре врахування різноманітних сценаріїв. Знову гарний коментар Джорджіо.
Роберт Джонсон

1
Щодо прийняття нових ідіом, технологій: я б вважав початок нового проекту хорошим моментом для впровадження нових матеріалів. Потім, протягом усього періоду проекту, стиль коду повинен дотримуватися максимально послідовного. Нещодавно мені довелося розкопати якийсь 5-річний код, і я був дуже радий, що все-таки зможу знайти свій шлях через цей код, тому що вся команда дотримувалася загальної архітектури та набору ідіом, про які ми домовились (не без боротьби! ) на початку проекту.
Джорджіо

26

Моя точка зору залишається незмінною; постійне вдосконалення є обов'язковим.

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

Я вважаю за краще невідповідності, коли якийсь код все ще робиться foreachнад ArrayLists, а інші частини використовують LINQ IEnumerable<T>, замість того, щоб дотримуватися найдавнішого способу робити до кінця часу.

Відповідальність ваших колег залишається актуальною та вивчайте нові способи здійснення справ.


3
"Ваші колеги - це відповідальність за те, щоб залишатися актуальними та вивчати нові способи здійснення дій".
Джорджіо

8

Послідовність API дуже важлива як для публічних, так і для внутрішніх API.

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

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

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

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


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

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


6

Відповідь на це проста.

Консистенція має першорядне значення.

але він поставляється із застереженням ...

Ви з колегами, ймовірно, нав'язливі через неправильну послідовність

Реалізації є одноразовими. Вони можуть бути повністю відремонтовані з різним ступенем легкості залежно від якості та всебічності тестового набору. Турбуючись про такі речі, як "Чи повинно це бути властивість?", "Чи не повинен тонкий код використовувати LINQ замість конструкції нижчого рівня?" має сумнівну цінність. Її важко пов'язати будь-які вимірювання зі значенням узгодженості на рівні реалізації. Набагато кращим питанням на цьому рівні є "Чи працює цей код так, як рекламується?". Послідовність виконання TL; DR - це те, де "маленькі розуми" отримують свій хобгоблін.

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

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

API не є одноразовими.

Це всі рівні коду API, веб-сервіси, SDK тощо. Вони повинні, ОБОВ'ЯЗКОВО бути послідовними. Збільшення продуктивності від цієї різноманітності консистенції величезне з кількох причин:

Інтеграційні тести:

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

Продуктивність

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

Чому в цьому сценарії важлива послідовність? Оскільки в API є прямо протилежна проблема реалізації. Кількість людей, які їх використовують, як правило, набагато більша, ніж кількість людей, що сприяють їх реалізації. Невеликі прибутки від невеликої консистенції примножуються, а витрати на підтримання цієї консистенції амортизуються.

Висновок

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

Реймонд Хеттінгер зробив кілька чудових моментів у своїй розмові про Pycon 2015 щодо використання керівництва зі стилю PEP8 для команд програмістів-пітонів. Він показав, що нав'язливість щодо стилістичної послідовності у фрагменті коду змусила рецензентів коду пропустити серйозні недоліки логіки та дизайну. Його гіпотезу можна узагальнити як легко знайти стилістичну невідповідність; визначити реальну якість фрагмента коду важко

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


4

Не знайомий з LINQ? Якщо так, чи не став би мій код більш корисним для моїх колег-розробників, якби я не використовував його?

Мова C # все ще розвивається. Якби люди не дізналися зміни від C # 1, вони б пропустили:

  • Джерела
  • Партії
  • Анонімні методи
  • Ітератори
  • Зменшувані типи
  • Авто-властивості
  • Анонімні типи
  • Методи розширення
  • Лінг
  • Лямбди
  • Асинхронні методи

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

Linq полегшує життя. Використовуйте його там, де можете. Ви можете мотивувати членів вашої команди.

Отже, наскільки шаблони є частиною стилю коду, і де нам слід провести межу між послідовністю та вдосконаленням?

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


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

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

3

Ви повинні відповідати старому коду, але не обов'язково. Тобто, ваша команда повинна домовитися про правильний спосіб робити щось, і використовувати цей спосіб, коли буде написаний новий код або будуть внесені суттєві зміни.

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

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


1

Я думаю, що важливо дотримуватися стилю коду в проекті, наприклад. називання конвенцій, відступів тощо.

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

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


Для чого був мінус?
ozz

0

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

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

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

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


-1

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


Для чого була сутичка?
Мураха

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

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