Коментований короткий фантазійний код порівняно з коментованим довшим простим для розуміння кодом - що є кращим?


18

Іноді алгоритм можна записати двома способами:

  • Короткий, вигадливий шлях; або
  • Більш довгий, зрозумілий спосіб.

Наприклад, тут більше, простіше спосіб копіювання рядка sourceв destв C:

*dest = *source;
while (*source != '\0') {
    source++;
    dest++;
    *dest = *source;
} (true);

І ось короткий, вигадливий шлях.

// Copy string source to dest
while (*dest++ = *source++);

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

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

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

EDIT2: Ось новий іспит, який я отримав від SO :

Прокоментувала вигадливу версію:

//direct formula for xoring all numbers from 1 to N
int Sum = (N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) ) );

Не коментована довга версія:

int Sum = 0;
for (int i = 1; i < N; ++i)
{
   Sum ^= i; //or Sum = Sum ^ i;
}

2
@gablin: "добре" - це слово, але це прикметник з дещо іншим значенням, ніж "добре", і більше не використовується (принаймні в США) Прислівна форма "хороший" - "добре" як у "добре коментованому коді".
Джон М Гант

@John: Ага так, звичайно. Я відповідно оновив питання. Спасибі.
габлін

2
Яким способом короткий шлях "фантазії"? Це фрагмент текстової книги з кодом С, який кожен, хто стверджує, що знає С, повинен читати без жодних питань. Терзистість не означає «фантазії».
JBRWilkinson

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

@gablin: Ваша редакція компрометує поточні відповіді.
Маньєро

Відповіді:


28

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

Замість того, щоб коментувати фантазійний код, його метод має бути всім необхідним, щоб все було зрозуміло.

char *copy_string(char *s, const char *t) {    
    while (*s++ = *t++); 
    return s;
}

3
Чудова точка. Розроблення автономного коду набагато краще, ніж коментарі. Компілятор знає, як її вкласти в разі потреби.
dbkk

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

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

Невже ваша функція повинна бути названа "strcpy"?
JBRWilkinson

У цьому фрагменті коду помилка. Що повертається? Що потрібно було повернути? Просто зробіть це недійсним методом і виконайте його;)
Крістіан Манн

10

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

У мене є приклад із реального життя. У нашому продукті був такий фрагмент коду:

if (++someCounter < MAX_VALUE) {
    // Do something that has to be done only MAX_VALUE times
}

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

if (someCounter < MAX_VALUE) {
    ++someCounter;
    // Do whatever it is we came here for
}

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

Отже - я все для простоти та чіткості.

Редагувати: О, а щодо коментарів - це не має значення. Багато людей все одно не будуть читати коментарі ( http://www.javaspecialists.co.za/archive/Issue039.html ), а ті, хто не зрозуміє ваш код без коментарів, не зрозуміють його досить добре, щоб вони може підтримувати його. Мета - допомогти людям побачити, що певний код "правильний", коментарі не можуть допомогти у цьому.


1
"зруйнували виробничу систему нашого клієнта" - це дуже погано: -S

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

@quant_dev: навпаки, "Налагодження в першу чергу важче, ніж написання коду. Тому, якщо ви пишете код якомога розумніше, ви, за визначенням, недостатньо розумні, щоб налагодити його." - Брайан В. Керніган
Майкл Боргвардт

@MichaelBorgwardt Я б не застосовував наосліп Керніган до будь-якої можливої ​​ситуації. Приклад ОЗ - це функція, написана "якомога розумніше" (або близько до неї), і все ж вона повинна бути досить простою налагодження, якщо потрібна будь-яка налагодження. З іншого боку, складні бітлійндлайнери можуть бути дуже розумними, але, напевно, буде ще важче налагодити. (Також: Керніган припускає, що навички кодування = налагоджувальні навички. Це не повинно бути так. Я успішно налагодив код, я б не зміг написати.)
Quant_dev

6

Як правило, я віддаю перевагу більш тривалої версії. Дві головні причини:

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

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

void copy_string(char *s, char *t)
{
    *s = *t;
    while (*t != '\0') {
        t++;
        s++;
        *s = *t;
    }
}

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


1
Хіба це не те, що вбудовано?
Ансан

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

4

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

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

У коментарях ніколи не повинно бути зазначено нічого очевидного з коду, що просто змушує читача читати одне і те ж саме двічі. Мені перший фрагмент вимагає уточнення. Чому розробник не використав do...whileцикл для видалення дублікату *s = *t;завдання? Мені потрібно проаналізувати більше коду, щоб зрозуміти, що він реалізує струнну копію. Коментар був би кориснішим щодо цього більш тривалого коду, ніж для коротшого коду.

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


Розробник (мене) не використовував do ... whileпросто тому, що я не думав про це, коли писав питання. Дякуємо, що вказали на це. ^^ Другий фрагмент може бути для вас очевидним, але це, звичайно, не для мене.
габлін

4

Проблема полягає в тому, що немає чіткого визначення, short fancy codeоскільки це дуже залежить від рівня програміста. У той час як деякі люди не мають жодних проблем з розумінням while(*s++ = *t++);виразу, у інших це буде.

Особисто мені здається, що це while(*s++ = *t++);читається ідеально і довше важче читати. Інші, можливо, не погоджуються.

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


Мене сумно, що темою багатьох таких відповідей є "розробники можуть не розпізнати стандартний спосіб написання strcpy () на C"
AShelly

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

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

2

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

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

while (*dest++ = *source++)
    ;

або навіть:

while (*dest++ = *source++)
    ; /* no body */

Деякі люди вважають за краще використовувати брекети замість:

while (*dest++ = *source++)
    {}

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

if (x>y);
     x = z;

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


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

2
Keep it simple, stupid!

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

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

У цих ситуаціях я часто посилаюся на Дзен Пітона . Зокрема:

Explicit is better than implicit.
Simple is better than complex.

1

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

alt текст


1

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

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

~ Брайан Керніган


довший, але змістовніший, елегантний навіть, ніж більш компактний абревіатура KISS ~ сподіваюся, іронія там не втрачена; p
фіолетовий313

0

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


0

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

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

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


0

Читання та ремонтопридатність є ключовими, а ваш другий приклад (тобто довший) - набагато більше обох. Але навіщо обмежувати себе двома варіантами? Навіть довший код занадто складний (IMHO), щоб не записувати далі. Я поставив би його у власному методі з відповідним Javadoc (або будь-яким іншим) та відповідною назвою методу.

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