Страницы

Поиск по вопросам

воскресенье, 30 сентября 2018 г.

Как писать красивый и читаемый код?

Максимальное сокращение кода. Бывает желания максимально сократить код, но появляются сомнения, не перебор ли это. Ведь можно было бы отдельно объявить переменную и ей уже присвоить выражение, которое без переменной не сразу понятно что делает. Именование переменных. Проблемы с выбором имени для переменной. Если описывать полностью, что она делает, то будет около 16 символов, а если сокращать, то может конфликтовать с пониманием других переменных. Контекст тоже не всегда спасает. Разделение действий. Слишком много всего в одной части кода, что может усложнить понимание. С одной стороны можно было бы вынести в отдельные функции, а с другой стороны нет смысла, так как используются только в той части кода. Уместность комментариев. Свой код всегда понятен, а предположить как его понимают другие, будет не всегда объективно. Так что, не всегда очевидно, нужен комментарий или он будет избыточен. Форматирование. С большой или маленькой буквы начинать переменную, а также в пределах переменной нужно ли большими буквами начинать слова или же разделять их с помощью "_". Делать ли пустую строку между if и другими блоками, а также между переменными и этими блоками или же расставлять по действиям. Делать ли отступы внутри выражений, к примеру if( sometring ) или if(sometring). 6...
Эти пункты только для понимания проблемы, потому что многие забыл, а многие и не замечал, думаю. А также на эти пункты с одной стороны очень легко ответить, а с другой хотелось бы правил или детального разбора. Так вот, есть ли правила гласные/негласные, в которых бы описывалось это и многое другое в этом направлении? Или есть книги посвященные этой теме?


Ответ

Вопрос стиля — на самом деле очень серьёзный вопрос.
Не забывайте, что код пишется вами не для компилятора. Сделать, чтобы было понятно компилятору просто, но ваша цель сложнее: сделать так, чтобы было понятно человеку
Код программы — то же самое литературное произведение. Вы должны донести мысль читателю, причём этим читателем можете оказаться как вы сами через полгода, так и ваш коллега, которому придётся править код пока вы в отпуске.
Хороший код живёт долго, а значит, он будет прочитан, подправлен, понят и объяснён много раз. Понимание чужого кода гораздо сложнее, чем написание нового с нуля, поэтому инвестировать в понятность кода важно (если, конечно, вы желаете своему коду долгой счастливой жизни).
Сокращение кода не нужно. Код должен быть понятным, не больше и не меньше.
Если вам кажется, что где-то нужно расписать для наглядности — так и сделайте, даже пусть придётся вводить дополнительные переменные только чтобы дать имя промежуточному результату. Если, наоборот, вам кажется, что кода слишком много для той простой штуки, которую он делает — вынесите эту штуку в отдельную функцию и придумайте ей правильное название, чтобы пояснить смысл действия. Поддерживайте однородность и общий темп: если кусок кода запускает космическую ракету в полёт, то кусок кода рядом с ним, который читает данные из конфигурационного файла, смотрится нелепо.
Именование переменных и функций. Не жалейте букв! Байты на винчестере подешевели. Вы не должны писать комментарии, чтобы пояснить смысл переменной, иначе читатель должен видеть одно (имя переменной), а в уме держать другое (её смысл). С другой стороны, не надоедайте читателю излишними подробностями. То, что у вас не просто acceptableByteCount, а countOfBytesWhichDidNotPassAtLeastTwoFilters, — скучно. Соблюдайте разумный баланс. Если вам нужна переменная цикла, назовите её i или j. Придерживайтесь общепринятых соглашений, если нужно, придумывайте свои (но разумные!), легко понятные другим.
Именуйте переменные правильно. Название должно отображать смысл. Если вы используете одну и ту же переменную в двух разных смыслах, вы делаете неправильно, разделите её на две переменные с однозначным смыслом. Например, не стоит совмещать длину переданной строки и счётчик оставшихся символов для обработки, хотя начальное значение счётчика и совпадает с длиной строки.
Старайтесь, чтобы текст читался естественно. Например, имя действия должно бы быть глаголом (не vector.Normalization(), а vector.Normalize() или vector.GetNormal()). Имя булевого условия должно быть похоже на условие и скорее всего начинаться с is, has и тому подобного. (Например: hasChanges(), isPrime() и т. п.) Ради бога, используйте английские имена, а не русские транслитом! Поверьте, isZarplataComputed() смотрится ужасно. Исключение — языки с кириллическим синтаксисом (?) или общепринятый стиль команды.
Разделение действий. Да, имеет смысл отделять код в функцию только для того, чтобы правильно назвать этот фрагмент кода. Функции существуют не для повторного использования! Функции нужны для логического разбиения кода на части. Если вы видите, что ваша функция ответственна за разные вещи, и вы не можете придумать ей короткого точного названия, значит, ваша функция делает чересчур много, и её надо разделить. Часто из супердлинной функции в 500 строк получается десяток классов. И это хорошо.
И да, читателю гораздо лучше понять функцию, которая делает одну простую задачу. Если функция делает слишком много, у неё кроме более сложного кода более сложные пред- и постусловия (а значит, её ещё сложнее понять).
Для хорошего разбиения на части проектируйте сверху вниз. Пример: приготовить еду — это что? Решаем, что это значит приготовить французский завтрак. Окей, а что такое приготовить французский завтрак? Это купить круассаны и сварить кофе. А что такое сварить кофе? Это смолоть зёрна в кофемолке, засыпать в турку, добавить воды, поместить на огонь, и т. д. Это естественным образом оформляется в процедуры PrepareMeals, PrepareFrenchBreakfast, BuyCroissants, MakeCoffee. Ничего выдумывать не пришлось.
Уместность комментариев. Старайтесь писать код так, чтобы комментарии не были нужны. Очень часто комментарии избыточны; очень часто они устаревают и перестают отображать действительность. Люди часто меняют логику кода, но забывают пробежаться и по комментариям.
Не забывайте, что выполняется код, а не комментарии. Поэтому ошибочный, вводящий в заблуждение комментарий (например: /* здесь не может получиться NULL */) гораздо хуже его отсутствия. Если у вас есть кусок кода, снабжённый комментарием, объясняющим, что он делает, превратите этот код в функцию, а комментарий — в её имя. Полностью избежать комментариев, вероятно, не удастся, но постарайтесь, чтобы комментарии описывали, почему вы делаете так, как делаете, а что именно вы делаете, должно быть понятно из кода.
Форматирование. Плохое форматирование очень сильно влияет на читаемость кода. Выработайте стиль и придерживайтесь его. Какой именно стиль вы выберете, в общем-то и не важно, главное, чтобы он был логичен и последователен. (Например, если вы ставите пробел после while, наверное стоит ставить пробел и после if.) Старайтесь, тем не менее, не отступать от общепринятых соглашений (например, имена методов в Java принято выбирать в lowerCamelCase), иначе вам трудно будет читать чужой код.
Если вы работаете в команде, не нарушайте общий стиль, даже если вам персонально он не нравится. Если в команде нету общепринятого стиля, предложите его! Расстановка скобок, отступы, пробелы, максимальная длина строк и всё такое важны, чтобы читатель не отвлекался. Непоследовательное форматирование сбивает с толку и отвлекает гораздо больше, чем это кажется — точно так же, как неправильная пунктуация мешает правильно понимать текст литературного произведения.

И последнее. Не заботьтесь о повышении эффективности кода путём понижения его читаемости. Выделение отдельного метода — не проблема, современные компиляторы научились inline-ить всё, что нужно. И объединять разные переменные в один регистр они скорее всего умеют гораздо лучше вас. Если же в каком-то месте ради низкоуровневой оптимизации действительно нужно ухудшить читаемость, снабдите этот фрагмент достаточными комментариями по поводу того, что же происходит в коде, и самое главное — почему такой трюк понадобился.

Комментариев нет:

Отправить комментарий