Должен ли я жертвовать более короткими именами переменных для более длинного «колонного» кода?

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;
        }
    }

До того, как у меня были эти сверхдлинные имена переменных, у меня были такие вещи, как i, j, k, но мой профессор настаивал на том, чтобы мы не использовали такие переменные в «профессиональном мире», и что даже сокращенные переменные, такие как lenWord, недостаточны, потому что люди могут предположить, это расшифровывается как «Всемирная литература Леннарда». Он говорит выбирать значимые имена переменных, но при этом я чувствую, что нарушил Золотое правило кодирования, чтобы оно оставалось ниже 80 столбцов. Как мне обойти это?

RAULT
источник
26
Продолжай двигаться; добавить больше полезных имен. Вы можете придумать способ , чтобы описать , cipherColumn + (rowSize*nextWord) + nextWordчто становится ясно , что это расчет для , например? Бьюсь об заклад, это имя короче, чем расчет, так что вы получите преимущество читабельности и уменьшенную длину строки. Также не выравнивайте назначения, или вы должны переместить их все, если вы переименуете самую длинную переменную.
Jonrsharpe
2
Хм .. так вы говорите, что я должен создать новую переменную и сохранить в ней результат cipherColumn + (rowSize * nextWord) + nextWord, чтобы я мог использовать ее дальше? Это то, что делают профессионалы? Я искренне спрашиваю
RaulT
8
Да, это мое предложение. Я профессионал, и это то, что я бы сделал, так что ... по крайней мере, некоторые из них.
Джоншарп
11
золотое правило заключается в написании кода, который можно прочитать и понять. мы пишем код для других людей (!), а не для машин. для машин есть машинный код. для некоторых код, который выглядит так, как вы описали (однобуквенные имена и т. д.), является недостатком уважения к другим программистам (и будущим вам - потому что вы забудете через несколько недель или месяцев). нет никаких причин придерживаться 80 столбцов, это не MS DOS в 80-х.
RSM
3
@stijn да, но мы в последний раз нуждались в этом. точно так же, как я не компилирую свой код c для 8-битного процессора 8086 на тот случай, если мне нужно будет сохранить его на перфокартах, я также не думаю, что 80 столбцов с золотым стандартом имеют какое-либо значение в 21 веке. мы должны расширить эту технологию, а не сидеть в 80-х и думать, что она делает нас умными хакерами. умная простота, удобочитаемость и продвижение технологии на максимум. у нас есть full-hd мониторы, пора их использовать.
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;
}

Да, я знаю, что это немного менее читабельно, но в противном случае вы сведете с ума людей, которые используют инструменты VDIF для обнаружения изменений.

Теперь давайте исправим эти глупые разрывы строк, которые у нас есть, потому что мы пытаемся не выходить за пределы длины строки.

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 для размещения входных параметров с учетом ограничений на длину строки.

candied_orange
источник
Вау, это описательно! Да, я знаю, что код на самом деле ничего не делает, возможно, мне следовало бы опубликовать не просто небольшой фрагмент этого, но я думаю, что я пытался получить общее представление о том, что делают профессионалы в отношении длины столбца кода и имен переменных, но ваш ответ показал некоторые очень приятные изменения, которые я теперь буду вносить в свои коды! У меня есть еще один вопрос: где вы находите подходящим для разрыва строки? Перед операторами? Есть ли принятый «стандарт»?
RaulT
1
@RaulT потратить некоторое время на чтение любой кодовой базы, в которой вы работаете. Это даст вам представление о том, что вы можете использовать, что не удивит других программистов. Следуйте стандартному документу, если он у вас есть. Но лучше всего спросить коллег-программистов и спросить их, насколько читабельны ваши материалы. Ох, и проверьте codereview.stackexchange.com
candied_orange
Я добавил бы комментарий ниже cipherOffset и объяснил бы вычисления, потому что эта формула не очевидна. Вы забудете почему через три недели.
Нельсон
15

Другие уже сделали несколько полезных предложений, позвольте мне подвести итог:

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

Я хотел бы добавить еще одну рекомендацию: не будьте догматичными в отношении длинных имен! Чем больше область действия переменной, тем больше информации нужно поместить в ее имя. И вообще, это хорошая идея, чтобы область переменных была небольшой.

Например, если у вас есть переменная для столбца таблицы шифрования ключевых слов, и очевидно, что в области действия вашей переменной используется только одна таблица, можно назвать ее columnили даже назвать col. Если область действия больше и в нее вовлечено несколько таблиц, имеет смысл вызывать ее keyWordEncryptionTableColumn.

Другой пример: если у вас есть цикл с телом, охватывающим две или три строки, и вы должны использовать индекс для доступа к элементам массива, нет ничего плохого в вызове индекса i. В этом контексте это гораздо более читабельно (по крайней мере, для большинства людей), чем, скажем arrayIndexOfMyVerySpecialDataSet.

Фрэнк Пуффер
источник
1
Я согласен с тобой ответить. На работе мы используем 80 символов в строке для c / c ++ по устаревшей причине и потому, что мы используем reviewboard. Для символов C # 100 / строка иногда я нарушал правило и немного превышал 100, чтобы сохранить читабельность.
peval27
Вау, какой отличный ответ !! Все эти ответы были великолепны, спасибо за помощь, я ценю это!
RaulT
Я полностью согласен с утверждением, что 80 строк символов устарели. Это все еще применяется для определенных проектов и мест (главным образом для согласованности), но для многих это просто ненужно. Многие разработчики используют что-то вроде Visual Studio или IntelliJ на полном мониторе и имеют второй монитор для других вещей (документация и т. Д.). Таким образом, они имеют много экранного пространства для своего кода. Если вы используете только 80 символов в строке, возможно, у вас тонна неиспользуемого пространства. И ограничение в 80 символов причиняет вам боль! Особенно, если учесть, что стандартная библиотека может вызывать длинные имена задниц.
Kat
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
никогда не делайте третьего, это кошмар обслуживания, чтобы держать его таким.
jwenting
3

Отказ от ответственности: я немного преувеличиваю, чтобы прояснить мою точку зрения. Так что возьми любой превосходной степени с зерном соли.

Ваш учитель на 100% прав: больше нет «золотого правила» для 80 символов (если вы не пишете код Linux). Это правило было установлено из-за размера терминалов в то время, но в настоящее время вы легко вписываете более 150 символов в окно вашего конечного пользователя. И даже если вы превысите этот лимит, надеюсь, ваш редактор будет мягко переносить строку, чтобы вам не пришлось прокручивать. И единственной причиной, чтобы не выходить за рамки 80 символов, была необходимость прокрутки .

Тем не менее, действительно, нет необходимости позволять вашим линиям расти бесконечно. Чем длиннее линия, тем труднее человеку разобраться. Но короткие имена переменных не являются средством решения проблемы длинных строк .

Средство состоит в том, чтобы логически разделить ваши выражения, введя еще более правильно названные переменные . Не пытайтесь быть умным с пробелами. Просто определите любое подвыражение, которое можно точно назвать, и создайте для него переменную. Это упрощает как код, вычисляющий переменную, так и код, использующий эту переменную .


Не часть вашего вопроса, но я бы все равно прокомментировал: очень плохая идея выровнять ваших =операторов по вертикали .

Для этого есть три причины:

  1. Редактирование блока, содержащего вертикально выровненные операторы, является PITA. Всякий раз, когда изменяется длина самой большой переменной (переименование, добавление, удаление), вам нужно ретушировать все строки в блоке, чтобы вернуть ваш «красивый» макет обратно.

    Конечно, эта проблема может быть немного уменьшена с помощью компетентного редактора, так что это второстепенная причина. Настоящая причина - вторая:

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

  3. Выравнивание имеет нулевое семантическое значение . Это бессмысленно. Там нет ничего, что вы можете лучше понять с выравниванием. Каждая строка в вашем блоке должна быть прочитана сама по себе, чтобы понять, что она делает, связь с линиями выше и ниже носит чисто синтаксический характер.

Поскольку выравнивание не несет какого-либо семантического значения, но приводит к значительным затратам, вы должны отучиться от привычки, прежде чем она будет стоить вам больше времени.


Если вам так нравится ограничение в 80 символов, попробуйте немного программировать на фортране. Правда, более новые стандарты увеличили предел строки Фортрана до 132 символов, но он остается в силе, так как всегда наносит вред компиляции любой программы, которая превышает этот предел. Если вы хорошо разбираетесь в программировании, вы скоро придете к ненависти к фортрану, включая ограничение длины строки. После этого вы будете исцелены на всю оставшуюся жизнь.

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

cmaster - восстановить монику
источник
3

Многие стилистические соглашения (не правила!) Возникли за эти годы из-за ограничений в средах программирования. Еще в дни перфокарт у вас было жесткое ограничение на количество символов, которые могут появиться в строке физического источника (именно поэтому Fortran зарезервировал столбец 6 для символов продолжения строки). Не так много лет назад я работал над терминалом VT220 янтарного цвета 80x24; в то время как редакторы, которые я использовал, не ограничивали строки до 80 символов, жизнь была бы намного проще, если бы вы старались избегать горизонтальной прокрутки.

При более старых версиях Fortran (до '77, IINM), вы даже не могли иметь identifers , которые были длиной более 6 до 8 символов. Даже в 80-х годах C гарантировал, что первые 8 символов во внешних именах были значимыми (именно поэтому некоторые библиотечные функции имеют удивительно описательные имена, такие как strpbrk).

Конечно, через два десятилетия в 21-м веке у нас больше нет этих ограничений. Нет причин не использовать более описательные идентификаторы.

Дело в том, в правильных условиях, iи jи kявляются вполне разумными, значимыми именами . Если я перебираю массив или вектор в цикле и мне просто нужно что-то, чтобы идентифицировать текущий элемент, он iработает отлично. Я бы не стал использовать подобное имя currentElement- оно не имеет смысла в этом контексте , а просто добавляет визуальный беспорядок.

Сказав это, ваш учитель не ошибается, заставляя вас думать с точки зрения более длинных и более описательных имен для всего - жизнь будет легче для вас, если вы сначала овладеете этой привычкой, а затем узнаете, где экономить по мере необходимости. Как кто - то , кто был в свое время вынужден уложиться в 8 символов или менее, это, безусловно , лучше ошибиться в сторону больше информации , чем меньше. По мере накопления опыта вы узнаете, где можно сэкономить на длине идентификатора, и где вам нужно быть немного более наглядным.

Джон Боде
источник
-1

Я не уверен, работает ли это для c или нет, но есть ли способ разделить формулы по нескольким строкам? Я знаю, что нечто подобное существует для Python.

Посмотрите, можете ли вы начать + (rowSize * nextWord) + nextWord]) {с новой строки. (Например, нажмите enter в вашей IDE и посмотрите, не отступает ли он, чтобы C знал, что предыдущее выражение завершается в текущей строке)

Krio
источник
1
Да, это определенно возможно. C распознает строки и строки кода, пока вы не добавите что-то вроде точки с запятой. Проблема в том, что наши функции не могут превышать 50 строк, и хотя мой пример кода не имеет 50 строк, это лишь часть моей общей функции. Я чувствую себя сильно ограниченным, чтобы написать в блоке 50 на 80 алгоритмы со значимыми переменными, которые могут выполнять функции, которые мне тоже нужны. Я мог бы хранить эти длинные куски кода в новых функциях, но я чувствую, что у меня будет так много вызовов функций, что люди потеряются, читая код.
Рауль
5
«Я чувствую, что у меня будет так много вызовов функций, что люди потеряются, читая код». Наоборот! Извлечение кода в отдельные методы позволяет вам давать им описательные имена, повышающие удобочитаемость (особенно метода, из которого вы извлекаете). Если у вас слишком много методов, ваш класс может делать много (принцип единой ответственности). Повторное извлечение методов в отдельный класс позволяет вам дать этой вещи описательное имя.
Роман Райнер,
Любая функция, которая приближается к 50 строкам, вероятно, слишком длинная и слишком сложная (за исключением возможной инициализации данных со сложностью 1), но обычно, когда обсуждаются подобные ограничения, это строки кода, а не текстовые строки, разделяющие одну строку. строка кода, т.е. точка с запятой часто не считается дополнительной строкой, уточните у Prof!
Стив Барнс