Чи я жертвую коротші назви змінних для більш тривалого колонного коду?


17

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

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }

До того, як я мав ці супер довгі імена змінних, у мене було таке, як я, j, k, але мій професор наполягає, що ми не використовуємо такі змінні в "професійному світі" і що навіть скорочені змінні, такі як lenWord, є недостатніми, тому що люди можуть припускати воно розшифровується як "Світова література Леннарда". Він каже, щоб вибрати значущі імена змінних, але, роблячи це, я відчуваю, що я порушив Золоте правило кодування, щоб тримати його під 80 стовпцями. Як мені це обійти?


26
Продовжувати йти; додати більше корисних імен. Ви можете придумати спосіб , щоб описати , cipherColumn + (rowSize*nextWord) + nextWordщо стає ясно , що це розрахунок для , наприклад? Б'юсь об заклад, що це ім’я коротше, ніж обчислення, тому ви отримуєте перевагу читабельності та зменшену довжину рядка. Також не вирівнюйте завдання, або вам доведеться перемістити їх усі, якщо ви перейменовуєте найдовшу змінну.
jonrsharpe

2
Хм .. так ви кажете, що я повинен створити нову змінну і зберегти в ній результат cipherColumn + (rowSize * nextWord) + nextWord, щоб я міг використовувати її далі? Це те, що роблять профі? Я щиро прошу
RaulT

8
Так, це моя пропозиція. Я професіонал, і це я би робив, так що ... хоча б деякі з них.
jonrsharpe

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

3
@stijn так, але це останній раз, коли нам це було потрібно. так само, як я не складаю свій код c для 8-бітового процесора 8086 на випадок, якщо мені потрібно зберігати його на перфокартах, я також не думаю, що золота зірка зі стовпцями 80 стовпців не має жодного значення в 21 столітті. ми повинні розтягувати цю технологію, а не сидіти у 80-х і думати, що це робить нас розумними хакерами. розумною є простота, читабельність та наполегливість технології до максимуму. у нас є повнорозмірні монітори, пора їх використовувати.
rsm

Відповіді:


24

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

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
}

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

Це не те, що ви ніколи не повинні використовувати i, jі k. Це точні імена при індексації 3 вкладених forциклів. Але тут імена справді є моєю підказкою щодо того, що ви очікували, що це станеться. Тим більше, що цей код насправді нічого не робить.

Найкраще правило, яке слід дотримуватися змінної довжини імені, - це область. Чим довше життя змінної, тим більше змінних людей має її ім'я. Назва CandiedOrange є унікальною для обміну стеками . Якби ми були в чаті, ви можете просто назвати мене "Цукерки". Але зараз ви знаєте, що це ім'я можна переплутати з Candide , Candy Chiu або Candyfloss . Отже, чим довший обсяг, тим довше має бути назва. Чим коротший обсяг, тим коротше може бути назва.

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

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

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
    return cipherColumn;
}

Там тепер це щось робить.

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

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

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

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn = 0;
    int cipherColumn = 0;
    int offset = 1;
    int nextWord = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

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

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

int calcCipherColumn(
        char keyWord[25], 
        char cipherText[17424],
        int rowSize, 
        char message[388]
) {
    int keyColumn = 0;
    int keyOffset = 1;

    int nextWord = 1;
    int cipherColumn = 0;
    int cipherOffset = (rowSize * nextWord) + nextWord;

    char key = keyWord[keyColumn];
    char keyNext = keyWord[keyColumn + keyOffset];

    while (key != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyNext != cipherText[cipherColumn + cipherOffset]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Там тепер логіка в циклі орієнтована на те, що змінюється в циклі. Насправді все, окрім як cipherColumnможна було позначатиfinal . І ей! Подивіться на це. Зараз у нас є місце для цього.

Все, що я зробив, було додати ще 3 змінні, перейменувати одну і трохи їх переставити. І результат просто трапився, щоб лінії були досить короткими, щоб вміститись без нерозумної лінії!= .

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

Я також взяв на себе сміття показати вам варіант 6 стилю Джеффа Грігга з викладенням вхідних параметрів з дотриманням обмежень по довжині рядків.


Нічого, це описово! Так, я знаю, що код насправді нічого не робить, я, мабуть, повинен був розмістити більше, ніж невеликий фрагмент, але, мабуть, я намагався отримати загальне уявлення про те, що роблять профі щодо довжини стовпців коду та імен змінних, але Ваша відповідь показала деякі дуже солодкі зміни, які я обов'язково буду впроваджувати у свої коди з цього моменту! Ще одне питання, яке у мене є: де ви вважаєте за потрібне робити перерви? Перед операторами? Чи є прийнятий "стандарт"?
RaulT

1
@RaulT витратьте деякий час, читаючи будь-яку кодову базу, в якій працюєте. Це дасть вам уявлення про те, що ви можете використовувати, що не здивує інших кодерів. Дотримуйтесь стандартного документа, якщо він у вас є. Але найкраще - запитати колег-програмістів і запитувати їх, наскільки читабельні ваші речі. Ох і перевірити codereview.stackexchange.com
candied_orange

Я б додав коментар нижче cipherOffset і пояснив обчислення, оскільки ця формула не очевидна. Ви забудете чому через три тижні.
Нельсон

15

Інші вже зробили кілька корисних пропозицій, дозвольте підсумувати:

  • 80 символів на рядок, можливо, були золотим правилом у 80-х. В даний час більшість людей погоджуються, що від 100 до 130 символів добре.
  • Використовуйте рядкові рядки всередині виразів.
  • Розбийте довгі вирази, вводячи проміжні результати.

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

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

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


1
Я згоден з вами у відповідь. На роботі ми використовуємо 80 char / line для c / c ++ з застарілих причин і тому, що ми використовуємо оглядову дошку. Для символів C # 100 / рядок іноді я порушував правило і переходжу трохи більше 100, щоб зберегти читабельність.
peval27

Нічого собі, яка чудова відповідь !! Усі ці відповіді були чудовими, дякую за допомогу, яку я ціную!
RaulT

Я сильно погоджуюся з натисканням на думку про те, що 80 символьних ліній застаріли. Він все ще застосовується до певних проектів та місць (переважно для послідовності), але для багатьох це просто непотрібно. Багато розробників використовують щось на зразок Visual Studio або IntelliJ на повному моніторі та мають другий монітор для інших матеріалів (документації тощо). Таким чином, вони мають багато екранного нерухомості для свого коду. Якщо ви використовуєте лише 80 символів на рядок, у вас, ймовірно, є тонна невикористаного простору. І межа 80 символів шкодить вам! Особливо, якщо врахувати, що стандартна ліб може примушувати довгі імена дупи.
Кет

1
Думаю, що в деяких мовах насправді не уникнути того, що 80 символів - це велике обмеження. То чому це зайве? Також напрошується згадати, що майже всі редактори великих імен та IDE в наші дні мають чудову розумну м'яку обробку слів, що дозволяє вам не обмежувати довжину рядків НА ВСІХ. Ви можете дозволити довжині рядків будь-якими, що бачить читач. Вони можуть змінити розмір вікна, щоб отримати більш оптимальний результат. Я особисто вважав, що такий підхід іноді ідеальний. І я ще розчарований тим, як працює ця м'яка обгортка.
Кет

Кожного разу, коли ви використовуєте прості імена змінних, ви ОБОВ'ЯЗКОВО на 100% бути впевненими в області застосування. Я витратив три години, щоб дізнатися про закриття JavaScript.
Нельсон

3

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

Про окреслення:

ExtractMessage(char keyWord[25], char cipherText[17424],
               int rowSize, char message[388]) 

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

ExtractMessage(
  char keyWord[25],
  char cipherText[17424],
  int rowSize,
  char message[388]
  )
{

І тоді ви навіть можете вирівняти ідентифікатори типів (додати пробіл після int). Однак будьте обережні / обмежуючі, викладаючи такі ініталізації чи списки аргументів, як це:

int keyColumn    = 0;
int cipherColumn = 0;
int offset       = 1;
int nextWord     = 1;

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

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

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


1
Особисто перший блок коду у вашій відповіді для мене набагато читає, ніж другий.
Майлз Рут

1
ніколи не робіть третього, це кошмар технічного обслуговування, щоб тримати його таким.
17:00

3

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

Ваш вчитель має право на 100%: більше немає "золотого правила" про 80 ​​символів (якщо ви не пишете код Linux, тобто). Це правило було встановлено через розмір терміналів на той час, але в наш час ви легко набиваєте більше 150 символів у вікні вашого завершальника. І навіть якщо ви перевищите цю межу, ваш редактор, сподіваємось, буде м'яко перегорнути рядок, так що вам не доведеться прокручувати. І єдиною причиною не виходити за рамки 80 символів була необхідність прокрутки .

Однак, насправді потрібно не дозволяти вашим лініям рости нескінченно довго. Чим довша лінія, тим важче людині стає розбирати. Але короткі назви змінних не є засобом для вирішення довгих рядків .

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


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

Для цього є три причини:

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

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

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

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

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


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

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


3

Багато років стилістичні умовності (а не правила!) Виникли через роки через обмеження в програмуванні. Повернувшись до днів перфокарт, у вас було жорстке обмеження кількості символів, які можуть з’являтися у фізичному рядку джерела (саме тому Fortran зарезервував стовпець 6 для символів продовження рядків). Не так багато десятиліть тому я працював над бурштиновим-чорним терміналом VT220 розміром 80x24; в той час, як редактори, якими я користувався, не обмежували рядки до 80 символів, життя було набагато простіше, якщо ви зробили все можливе, щоб уникнути горизонтальної прокрутки.

У старих версіях Fortran (до 77 років, IINM) ви навіть не могли мати ідентифікатори , довжина яких перевищувала від 6 до 8 символів. Навіть до 80-х років С гарантував би лише те, що перші 8 символів у зовнішніх іменах були значущими (саме тому деякі бібліотечні функції мають дивовижні описові назви на кшталт strpbrk).

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

Справа в тому, в правильних умовах, iі jта kє цілком розумними, значущими іменами . Якщо я повторюю через масив або вектор у циклі, і мені просто потрібно щось для ідентифікації поточного елемента, iпрацює чудово. Я б не використовував таке ім’я currentElement- воно в цьому контексті не є більш значимим , і воно просто додає візуальної безладу.

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


-1

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

Перевірте, чи можете ви починати + (rowSize * nextWord) + nextWord]) {у новому рядку. .


1
Так, це однозначно можливо. C розпізнає рядки та рядки коду, поки ви не додасте щось, як крапка з комою. Проблема в тому, що наші функції не можуть перевищувати 50 рядків, і хоча мій приклад коду не має 50 рядків, це лише частина моєї загальної функції. Мені дуже важко писати у вікні 50 на 80 алгоритми зі змістовними змінними, які можуть виконувати функції, які мені також потрібні. Я можу продовжувати зберігати ці довгі шматки коду в нових функціях, але я відчуваю, що я закінчу стільки викликів функцій, що люди втратять читання коду.
RaulT

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

Будь-яка функція, що наближається до 50 рядків, ймовірно, занадто довга і занадто складна (за можливим винятком ініціалізації даних зі складністю 1), але зазвичай, коли такі обмеження обговорюються, вони представляють собою рядки коду, а не текстові рядки, тому розбиваючи єдиний рядок коду, тобто крапка з комою часто не вважатиметься додатковою лінією, зверніться до Prof!
Стів Барнс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.