Чи може коментований код бути цінною документацією?


83

Я написав наступний код:

if (boutique == null) {
    boutique = new Boutique();

    boutique.setSite(site);
    boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
    boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
    boutique.setNom(fluxBoutique.getNom());
    boutique.setSelected(false);
    boutique.setIdWebSC(fluxBoutique.getId());
    boutique.setDateModification(new Date());

    boutiqueDao.persist(boutique);
} else {
    boutique.setSite(site);
    boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
    boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
    boutique.setNom(fluxBoutique.getNom());
    //boutique.setSelected(false);
    boutique.setIdWebSC(fluxBoutique.getId());
    boutique.setDateModification(new Date());

    boutiqueDao.merge(boutique);
}

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

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

Відповіді:


109

Більшість відповідей зосереджені на тому, як змінити цей конкретний випадок, але дозвольте запропонувати загальну відповідь на те, чому коментований код зазвичай поганий:

По-перше, коментований код не складається. Це очевидно, але це означає, що:

  1. Код може навіть не працювати.

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

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

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

Розглянемо альтернативи:

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

5
Я думаю, що вам не вистачає однієї важливої ​​причини: Документація: Якщо мета - задокументувати альтернативні варіанти дизайну, замість оригінального коду слід надати пояснення альтернативи, а особливо причину її відкидання.
Sarien

14
Варіанти дизайну краще пояснюються людською мовою, ніж мовою програмування.
Марк Е. Хааз

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

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

263

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

Якщо ви створюєте boutiqueDao.mergeOrPersistметод, ви можете переписати це як:

if (boutique == null) {
    boutique = new Boutique();
    boutique.setSelected(false);
}

boutique.setSite(site);
boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
boutique.setNom(fluxBoutique.getNom());
boutique.setIdWebSC(fluxBoutique.getId());
boutique.setDateModification(new Date());

boutiqueDao.mergeOrPersist(boutique);

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

Багато ORM якимось чином підтримують це. Наприклад, вони можуть створити новий рядок, якщо idнуль, і оновити існуючий рядок, якщо idвін не дорівнює нулю. Точна форма залежить від конкретної ORM, і оскільки я не знайомий з технологією, яку ви використовуєте, я не можу вам у цьому допомогти.


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

bool isNewBoutique = boutique == null;
if (isNewBoutique) {
    boutique = new Boutique();
    boutique.setSelected(false);
}

boutique.setSite(site);
boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE + fluxBoutique.getLogo());
boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE + fluxBoutique.getUrl());
boutique.setNom(fluxBoutique.getNom());
boutique.setIdWebSC(fluxBoutique.getId());
boutique.setDateModification(new Date());

if (isNewBoutique)
    boutiqueDao.persist(boutique);
else
    boutiqueDao.merge(boutique);

166

Це абсолютно жахлива ідея. Зрозуміло, що це за наміри. Чи забудовник помилково прокоментував рядок? Щоб щось перевірити? Що відбувається?!

Окрім того, що я бачу 6 рядків, які в обох випадках абсолютно рівні. Швидше, ви повинні запобігти дублюванню цього коду. Тоді стане зрозуміліше, що в одному випадку ви додатково викликаєте setSelected.


9
Домовились. Я б припустив побачити, що коментований рядок - це стара поведінка, яку було видалено. Якщо потрібен коментар, він повинен бути натуральною мовою, а не кодом.
Жуль

4
Я повністю згоден! Нещодавно я витрачав години, намагаючись зрозуміти та очистити деякі спадкові програми, які я майже не читаю через цю практику. Він також включає код, який був відключений від усіх інших кодів, але не видалений! Я вважаю, що це основна мета систем управління версіями. У ньому є коментарі, а також зміни, які пов'язані з ними. Зрештою, я мав принаймні 2 тижні роботи значною мірою доданий до своєї тарілки через цю практику.
bsara


120

Ні, це жахлива ідея. Виходячи з цього коду, на думку мені приходять такі думки:

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

Побачивши тисячі рядків коментованого коду, я зараз роблю єдине розумне, коли бачу: негайно видаляю його.

Немає розумних причин перевіряти коментований код у сховище.

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


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

23
це оптимізація для читабельності людини
jk.

11
@Traroth ви можете оптимізувати швидкість, використання пам’яті, споживання енергії чи будь-яку іншу метрику, тому я не бачу, що ви не можете оптимізувати для читабельності (хоча як показник це трохи шерше)
jk.

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

4
Програмне забезпечення як відповідальність також розглядається на сайті c2.com/cgi/wiki?SoftwareAsLiability. Звідти: "Виробництво більше коду не завжди є
ninjalj

51

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

function fill(boutique) {    
  boutique.setSite(site);
  boutique.setUrlLogo(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getLogo());
  boutique.setUrlBoutique(CmsProperties.URL_FLUX_BOUTIQUE+fluxBoutique.getUrl());
  boutique.setNom(fluxBoutique.getNom());
  boutique.setIdWebSC(fluxBoutique.getId());
  boutique.setDateModification(new Date());
}    

function create() {
  boutique = new Boutique();      
  fill(boutique);
  boutique.setSelected(false);
  return boutiqueDao.persist(boutique);
}

function update(boutique) {
  fill(boutiquie);
  return boutiquieDao.merge(boutique); 
}

function createOrUpdate(boutique) {
  if (boutique == null) {
    return create();
  }
  return update(boutique);  
}

6
Я думаю, що це найчистіша пропозиція тут.
Олексій Дуфреной

+1, і я також додам, що чим більше ви уникаєте обходу nullпредметів, тим краще (я вважаю, що це рішення є хорошим прикладом).
Надір Сампаоолі

Я передав би boutiqueDaoяк вхід до createта update.
Happy Green Kid Naps

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

Ліріон: Тривіально, я додам цей код також для наочності.
Олександр Торстлінг

27

Хоча це явно не є гарним випадком для коментованого коду, є ситуація, на яку я думаю, що це вимагає:

// The following code is obvious but does not work because of <x>
// <offending code>
<uglier answer that actually does work>

Це попередження того, хто бачить це пізніше, що очевидного поліпшення немає.

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


5
Що не так // the following part done like it is because of X? Поясніть , чому ви зробили що - то, як ви зробили, що не то, чому ви зробили НЕ на нього в якому - то конкретному шляху. У вашому конкретному прикладі це виключає необхідність цілком великого блоку коментованого коду цілком. (Я не брав участь в голосі, але, безумовно, бачу, чому це буде знято.)
CVn

13
Майкл, тому що це дає зрозуміти інші кодери (і самі дні / тижні / місяць потому) , що да, ви ж спробувати , що очищувач / розумніший підхід, але немає, він не працює з - за X, тому вони не повинні турбуйтеся спробувати його ще раз. Я думаю, що це цілком законний підхід і підтримав цю сумно поховану відповідь.
Гаррет Олбрайт

1
@GarrettAlbright: Дякую, я радий, що хтось це отримує.
Лорен Печтел

3
@LorenPechtel: Мало того, я писав про більш-менш точно те саме. Бувають ситуації, коли дуже і дуже корисно швидко дізнатися, які «очевидні» рішення вже пройшли без випробувань і чому вони не працюють.
JensG

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

14

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

// Не потрібно знімати вибір цього бутіка, оскільки [ЩО БЕЗ]

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

%% Векторизований код нижче:

% for ii in 1:N
%    for jj in 1:N
%      etc.

%, але версія матриці працює на 15 разів швидше на типовому вході (MK, 03.10.2013)

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


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

1
Ну, це проблема з усіма коментарями, правда? Деякі векторизовані коди є досить непрозорими, що коментарі варті, і наявність "розкрученої" версії може бути зручною для налагодження.
Метт Крауз

Правда. Але я б намагався тримати коментар якомога коротшим, а не використовувати повний вихідний код. У будь-якому разі, якщо у вас є приклад, добре запитати (як тут, або на codereview.se), було б найкраще запитати, як найкраще зробити його читабельним.
sleske

1
У вашому останньому випадку я б зберігав обидва варіанти коду як компільований код.
CodesInChaos

12

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

## Enable support for mouse input:
# enable_mouse = true

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


7

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

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


2
Це дзвонить цілком вірно. Дуже багато людей (включаючи мене) вважають, що їх код настільки приголомшливий, що йому не потрібна документація. Однак, всі інші люди в світі вважають, що це гоблік, якщо це не ретельно задокументовано та не прокоментовано.
Райан Амос

" код - це самодокументування лише тій особі, яка написала код ". Будь ласка, виберіть фрагмент складного коментуваного коду, який ви написали рік тому, і спробуйте його зрозуміти за обмежену кількість часу. Ви не можете? Ооопс.
JensG

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

4

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

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

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


2

Це може бути в дуже рідкісних випадках, але не так, як ви це робили. Інші відповіді досить добре висвітлили причини цього.

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

Name:           foomatic
Version:        3.14
 ...
Source0:        %{name}-%{version}.tar.gz

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

Name:           barmatic
Version:        2.71
 ...
# This package has no sources.
# Source0:        %{name}-%{version}.tar.gz

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

if ( condition ) {
  foo();
  // Under most other circumstances, we would do a bar() here, but
  // we can't because the quux isn't activated yet.  We might call
  // bletch() later to rectify the situation.
  baz();
}

5
Можливо, цей коментар не коментується кодом.
jk.

1
@jk: Ви, мабуть, правильні.
Blrfl

1

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

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

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


1
Вибачте, але я не бачу значення коду коментаря. Код, який коментується, не використовується, отже, він не має місця у виробничому коді.
Володимир Кочанчич

1
Будь ласка, визначте "використано".
JensG

Я думаю, що він мав на увазі "страчений"
Олексій Дуфреной

-2

Це не виглядає добре приятелем.

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

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

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

Інакше тут можна спробувати щось гнучкіше, щось подібне

boutique.setSite (сайт) можна замінити на

setsiteof.boutique (сайт). Існують різні аспекти та перспективи OOP, завдяки яким можна збільшити читабельність.

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


15
"Що стосується мене, треба написати код для компілятора" О, будь ласка, не варто. Ось так ви закінчуєте жахливі місця, схожі на те, що їх можна було б взяти прямо з конкурсу «Замучений C» та подібних. Комп'ютери є бінарними, тоді як люди використовують нечітку логіку (до речі, для власників домашніх тварин це подвійно). Час на комп’ютер сьогодні майже вільний (в основному це лише електроенергія), тоді як час програміста порівняно дуже дорогий. Напишіть код для людей, і компілятор зрозуміє це. Напишіть код для компілятора без огляду на людей, і ви не заведете багато друзів у команді.
CVn

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