Как сделать описание программного кода

Обновлено: 07.07.2024

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

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

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

В качестве иллюстрации в этой статье я буду рассматривать программу, представляющую собой гипотетическую компьютерную игру под названием Kill Bad Aliens (Убей плохого инопланетянина). Участник этой игры должен управлять космическим кораблем. Этот корабль перемещается по горизонтали в нижней части экрана и стреляет снарядами по вертикали. Управление этим космическим кораблем будет осуществляться, скажем, с помощью клавиатуры.

Наша гипотетическая игра

Рис. 1. Наша гипотетическая игра

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

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

Итак, вы садитесь за рабочий стол и начинаете писать программный код игры Kill Bad Aliens на языке C++. Сначала вы определяете объекты, которые будут представлять космический корабль, снаряды игрока, инопланетян и их бомбы. Затем вы пишете код для графического представления на экране всех указанных объектов. После этого вы пишете код для перемещения объектов по экрану в зависимости от времени. И, наконец, вы пишете игровую логику, искусственный интеллект инопланетян, программный код для ввода с клавиатуры команд игрока и т.д.

Возникает неизбежный вопрос - как сделать все перечисленное таким образом, чтобы программный код готовой игры был понятным, не создавал сложностей при последующем сопровождении и вообще не представлял собой неразборчивую путаницу?

Комментируйте свой программный код. Обязательно. К примеру, вы написали процедуру и не сопроводили ее комментариями. Когда вы через несколько месяцев вернетесь к ней для доработки (а вам наверняка придется это сделать), отсутствие комментариев приведет к дополнительным потерям рабочего времени. Напоминаю, что время является самым ценным ресурсом. Потерянное время невозможно компенсировать.

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

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

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

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


Что тут можно сказать… Если какой-либо фрагмент программы настолько очевиден, он не нуждается в комментариях. С другой стороны, если ваша программа настолько запутана, что вы должны комментировать каждую ее строку, возможно, лучше сначала упростить ее каким-либо другим способом. Комментарии не только экономят время, они сами требуют времени. Комментарии требуют времени на прочтение, кроме того, они увеличивают фактические размеры программы на экране монитора, в результате чего перед вашими глазами может одновременно находиться меньший объем действующего программного кода.

И уж если мы подошли к этому, еще одна рекомендация - никогда не делайте такого:


Итак, как комментировать свою программу, если вы пишете программный код в отсутствие указаний начальника или корпоративных правил? Что касается меня, то первое, что я делаю при написании программного кода, который мне придется поддерживать самому - пишу введение. Когда я возвращаюсь к созданной ранее процедуре, я уже давно забыл, о чем думал в момент ее написания, поэтому мне хочется понять, что эта процедура делает. После того как я пойму, что программа делает, становится значительно проще понять реальный программный код. В общем случае необходимы следующие комментарии:

  1. Несколько предложений в начале процедуры/функции, объясняющих, что она делает.
  2. Описание значений, передаваемых в эту процедуру/функцию.
  3. В случае функции - описание смысла возвращаемых параметров.
  4. Внутри процедуры/функции - комментарии, разбивающие программный код на короткие подзадачи.
  5. Для особо сложных фрагментов кода - краткое пояснение того, что происходит.

Ниже приведен пример из нашей гипотетической игры Kill Bad Aliens. Рассмотрим объект, представляющий снаряды, которыми стреляет игрок. Вам придется часто вызывать функцию, которая будет перемещать этот объект вверх и определять, куда он попал. Я бы написал эту процедуру примерно так:


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

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


Хороший способ: В некотором глобальном файле напишите следующую строку:


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



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


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

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


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

Игра Kill Bad Aliens до изменения констант

Рис. 2. Игра Kill Bad Aliens до изменения констант

Игра Kill Bad Aliens после увеличения всех констант (играть, может быть, трудновато, но посмотреть интересно)

Рис. 3. Игра Kill Bad Aliens после увеличения всех констант (играть, может быть, трудновато, но посмотреть интересно)

Между прочим, вы обратили внимание, что для указанных выше значений я не писал никаких-либо комментариев. Это объясняется тем, что их смысл очевиден из имен переменных. Это естественным образом приводит нас к следующему важному совету.

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

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

Например, в реальных условиях я, скорее всего не давал бы константам такие длинные имена, которые я применил в предыдущем разделе. Я сделал это только для того, чтобы читатель смог полностью осознать их смысл без какого-либо контекста. В контексте самой программы вместо текста:


я, скорее всего, написал бы следующее:


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


Обратите внимание, что массив для всех инопланетян так и называется - aliens . И это очень хорошо. Данное имя передает именно то, что я хотел сказать, однако при этом оно достаточно короткое, чтобы я мог ввести его с клавиатуры тысячи раз и не сойти при этом с ума. По всей вероятности, вы будете использовать этот массив ОЧЕНЬ ЧАСТО. Если вы назовете этот массив all_aliens_currently_on_screen , ваш программный код станет на десять миль длиннее и настолько же непонятнее.

Несомненно, к именованию переменных можно относиться гораздо серьезнее. Например, существует т.н. венгерская нотация. Эта концепция имеет множество вариантов, однако ее основная идея состоит в том, что каждое имя переменной должно начинаться с префикса, указывающего на тип этой переменной. (Например, все переменные типа unsigned long variable должны начинаться с префикса ul и т.д.). На мой взгляд, это уже перебор, однако вам надо знать о существовании и такого варианта. Можно потратить достаточно много времени на то, чтобы сделать вещи понятнее, однако решение этой задачи также требует определенных усилий.

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

Рассмотрим следующий пример. Основная задача нашей замечательной космической игры состоит в том, чтобы убивать инопланетян и набирать баллы, поэтому нам необходима процедура для изменения набранных игроком баллов. Более того, при добавлении игроку баллов мы хотели бы вызывать процедуру, которая расцвечивала бы итоговый счет красивыми искорками. Первый вариант выглядит следующим образом:


Во-первых, один очевидный момент. Что произойдет, если переменная num_points будет иметь отрицательное значение? Можем ли мы допустить, чтобы счет игрока снижался? Возможно. Однако в описании игры я до этого нигде не упоминал о возможности потери игроком баллов. Кроме того, игры должны приносить удовольствие, а потеря баллов этому противоречит. Таким образом, мы приходим к выводу, что отрицательное число очков - это ошибка, которую необходимо поймать.

Этот пример был достаточно простым. Существует и менее очевидная проблема (с которой я постоянно сталкиваюсь в своих играх). Что произойдет, если переменная num_points будет равна нулю?

Это весьма правдоподобная ситуация. Не забудьте, что по окончании каждой волны мы даем игроку бонусные баллы в зависимости от скорости ее прохождения. Что произойдет, если игрок будет действовать слишком медленно и мы решим дать ему 0 баллов? Вполне вероятно, что, работая над своим кодом в 3 часа ночи, вы решите вызвать процедуру change_score и передать ей значение 0.

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


Ну вот. Так гораздо лучше.

Обратите внимание, что это была очень простая функция. В ней совершенно отсутствуют всякие новомодные указатели, которые так любят использовать молодые лихие программисты. Если вы передаете массивы или указатели, вам ОБЯЗАТЕЛЬНО нужно предусмотреть выявление ошибок или плохих данных.

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

Этот подход экономит массу времени и заслуживает регулярного применения. Время - наш самый ценный ресурс.

Эту фразу придумал не я. Однако она есть в Википедии, и поэтому, по всей видимости, не лишена смысла.

Если ваша конечная цель не состоит в том, чтобы мучить людей, то при написании программного кода следует стремиться к максимальной понятности. Простой код требует меньше времени на написание, на понимание при последующем обращении к нему и на отладку.

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

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

Однако возрадуйтесь! После моих долгих проповедей о том, что вы должны тратить больше времени на то и больше времени на это, наступил редкий, поистине бесценный момент, когда я говорю вам, что небольшая лень вполне допустима!

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

И, наконец, раз уж мы заговорили о болезненном, вот мой завершающий совет:

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

Каждый программист имеет свой допустимый уровень сложности создаваемого кода. Лично я пишу свои программы так, как водит машину типичная бабушка. На мой взгляд, если ваш код на C требует понимания тонких различий между выражениями i++ и ++i, то он слишком сложен.

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

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

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


Исхо́дный код (также исхо́дный текст) — текст компьютерной программы на каком-либо языке программирования. В обобщённом смысле — любые входные данные для транслятора.

Исходный код либо транслируется в исполняемый код при помощи компилятора, либо исполняется непосредственно по тексту при помощи интерпретатора.

Содержание

Назначение

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

Другое важное назначение исходного кода — в качестве описания программы. По тексту программы можно восстановить логику её поведения. Для облегчения понимания исходного кода используются комментарии. Существуют также инструментальные средства, позволяющие автоматически получать документацию по исходному коду — т. н. генераторы документации.

Кроме того, исходный код имеет много других применений. Он может использоваться как инструмент обучения; начинающим программистам бывает полезно исследовать существующий исходный код для изучения техники и методологии программирования. Он также используется как инструмент общения между опытными программистами, благодаря своей (идеально) лаконичной и недвусмысленной природе. Совместное использование кода разработчиками часто упоминается как фактор, способствующий улучшению опыта программистов.

Программисты часто переносят исходный код из одного проекта в другой, что носит название повторного использования кода (Software reusability).

Исходный код — важнейший компонент для процесса портирования программного обеспечения на другие платформы. Без исходного кода какой-либо части ПО, портирование либо слишком сложно, либо вообще невозможно.

Организация

Исходный код некоторой части ПО (модуля, компонента) может состоять из одного или нескольких файлов. Код программы не обязательно пишется только на одном языке программирования. Например, часто программы, написанные на языке Си, с целью оптимизации, содержат вставки кода на языке ассемблера. Также возможны ситуации, когда некоторые компоненты или части программы пишутся на различных языках, с последующей сборкой в единый исполняемый модуль при помощи технологии известной как компоновка библиотек (library linking).

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

Качество

Неисполняемый исходный код

Копилефтные лицензии для свободного ПО требуют распространения исходного кода. Эти лицензии часто используются также для работ, не являющихся программами — например, документации, изображений, файлов данных для компьютерных игр.

Набор практик хорошего кода, не зависящих от языка программирования, опубликовал сайт proglib.io. Примените их, и ваш код будет не только работать, но и читаться.


Почему важна читаемость кода

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

Чем проще читать код, тем проще его сопровождать. Понятный, читаемый код легче тестировать, в нем легче отлавливать ошибки – они не скрываются в его запутанной структуре. Плохо оформленный код неприятно изучать, читать, тестировать, сложно дополнять. Рано или поздно плохой код становится проще переписать.

Эстетическое восприятие кода влияет на удобство работы. Казалось бы, гораздо важнее производительность, возможность модификации, расширения… Но все эти показатели улучшаются, если код соответствует нашему чувству прекрасного. Глядя на качественно написанный код, можно быстро понять алгоритм и то, как работает программа для разных входных данных. Чистый код читается как хорошо написанная проза: слова превращатся в зрительные образы.

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

С чего начать: документация по стилю оформления кода

Все дороги программиста ведут к документации. В каждом языке существует свой стандарт оформления кода. Для Python используется документ PEP-8, для PHP – стандартные рекомендации PSR-1 и PSR-2, для Java – Java Coding Conventions, для JavaScript – Airbnb JavaScript Style Guide или Google JavaScript Style Guide. Документ для вашего языка вы найдете по поисковому запросу Code Style.

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

В популярных IDE заложена возможность автоматической настройки стиля кода под стандарты – общие или предложенные командой. Разберитесь, как настроить среду под необходимое оформление. Потраченное время сэкономит многие часы рутинной работы.

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


Конечно, мы не могли обойтись без упоминания замечательной книги Роберта Мартина о чистом коде и анализе программ. В ней приводятся примеры для языка Java, но большинство идей справедливы для любых языков.

Всё что изложено ниже, в значительной мере представляет сжатый конспект этой книги с дополнениями из нашего опыта в проектировании программ. Итак, приступим к практикам.

Главное правило чистого кода: выразительные имена

Содержательность. К выбору названий любых объектов нужно подходить со всей ответственностью. Выразительные имена позволяют писать код, не требующий комментариев.

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

Избегайте любых двусмысленностей и ложных ассоциаций. Если в объекте перечисляется список, но сам объект не является списком, нельзя в составе его названия употреблять слово list – это запутывает читающего.

Остерегайтесь малозаметных различий – имена объектов должны существенно отличаться друг от друга. По этой причине плохи длинные имена с повторяющимся элементами – чтобы сличить их друг с другом, тратятся лишние силы и время. Избегайте использования в именах переменных строчной буквы L и прописных I, O – они часто путаются с единицей и нулем.

Путаница также возникает, если несколько синонимичных слов и выражений используются для обозначениях разных сущностей, например, controller , manager и driver .

Правильно выбирайте часть речи. Классы и объекты желательно называть существительными и их комбинациями: Account , WikiPage , HTMLParser . Имена функций и методов лучше представлять глаголами или глагольными словосочетаниями: delete_page , writeField(name) . Для методов чтения/записи и предикатов используйте стандартные префиксы get , set , is .

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

Одно слово для каждой концепции. Для одной и той же идеи, реализующей одну механику, используйте одно слово. Например, для добавления элементов одинаковым образом – метод add . Однако, если механика и семантика изменились, потребуется и другое слово (например, insert , append ), описывающее новую концепцию.

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

Помещайте имена в соответствующий контекст. Например, имена street , house_number , city понятнее смотрятся внутри класса Address .

Рабочие среды продолжают развиваться. Уже нет никакой необходимости кодировать типы в именах, создавать префиксы для членов классов. Всю нужную информацию можно получить из цветового выделения или контекстно-зависимых подсказок сред разработки. Добавление префиксов убивает удобство поиска по автовыполнению – выпадает слишком много имен, начинающихся с одинаковых символов.


Функции

Блоки if, else, while должны иметь минимальный размер, чтобы информацию о них можно было держать в уме. Старайтесь избегать отрицательных условий – на их восприятие обычно уходит чуть больше времени, чем на положительные. То есть запись if (buffer.shouldCompact()) предпочтительнее записи if (!buffer.shouldNotCompact() .

Правило одной операции. Плохой код пытается сделать слишком много всего, намерения программиста расплываются для читателя. Поэтому стоит ввести важное правило:

Функция должна выполнять только одну операцию, выполнять ее хорошо, и ничего другого она делать не должна.

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

Исключения вместо кодов ошибок. Используйте исключения ( try-catch , try-except ) вместо возвращения кодов ошибок. Возвращение кодов приводит к слишком глубокой вложенности.

Соблюдайте уровни абстракции. Одна функция – один уровень абстракции. Смешение уровней абстракции создает путаницу, функция обрастает слишком большим количеством второстепенных подробностей. Старайтесь соблюдать ясную иерархию.

Код читается сверху вниз. По мере чтения уровни абстракции должны меняться равномерно. Каждая функция должна быть окружена функциями единого уровня абстракции.

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

Комментарии

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

В чём проблема? Программисты умеют сопровождать код, но не комментарии. В растущем коде комментарии быстро устаревают, частично или полностью переставая соответствовать ситуации. Только код правдиво сообщает своим содержанием, что он в действительности делает. Лучше потратить время на исправление запутанного кода, чем добавлять к плохому коду комментарии.

Однако есть несколько видов комментариев, которые выглядят достаточно оправданными.

TODO-комментарии. Бывает так: нужно было успеть к дедлайну, пришлось писать код быстро, поэтому в нем остались дыры. То есть всё работает, но реализация ущербная. Укажите все недоработки и создайте под них задачи. Каждый комментарий указывает на недоработку или потенциальную уязвимость.

Юридические комментарии. Корпоративные стандарты могут принуждать вставлять комментарии по юридическим соображениям. Ограничьтесь в таком комментарии описанием лицензии и ссылкой на внешний документ.

Предупреждения о последствиях. Иногда бывает полезно предупредить других программистов о нежелательных последствиях:

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


По-настоящему плохие комментарии

Бывают такие типы комментариев, которые лучше никогда не делать.

Мертвые функции – идентичные по смыслу предыдущему пункту функции и методы, которые не вызываются в программе. Пользуйтесь системой контроля версий и без зазрений совести удаляйте любой код, который не используется во время выполнения программы.

Избыточные комментарии. Задайте себе вопрос: стал ли код понятнее после прочтения комментария? Часто комментарии просто загромождают код и скрывают его смысл, излагая очевидные вещи. Иногда в комментарии включаются описания не относящихся к делу подробностей. Но профессионал бережет не только свое, но и чужое время, и не отвлекает читающего без повода.

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

Позиционные маркеры. Иногда любят отмечать определенные группы и позиции в исходных файлах:

Качественно организованный код способен внятно рассказать историю без балластных заголовков.

Уровень файлов программ

Минималистичность. Чем меньше кода, тем лучше. Имя файла должно быть простым, но содержательным. Маленькие файлы обычно более понятны, чем большие. Но размер файла, конечно, не должен быть самоцелью.

Код должен быть максимально линейным. Чем больше вложенность кода, тем сложнее его читать. Следите за тем, как двигаются ваши глаза. В хорошем коде вы двигаетесь строка за строкой, лишь изредка возвращаясь к предыдущим строчкам. Вложенность более трех уровней указывает на то, что с кодом нужно поработать: переписать условия проверок и циклов (использовать return и функциональное программирование), разбить код на меньшие методы.

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

Пробелы для группировки взаимосвязанных элементов. Пробелы улучшают читаемость кода, если они стоят вокруг операторов присваивания, после запятых при перечислении переменных. В формулах пробелы используются для подчеркивания приоритета: не ставятся между множителями, но отбивают знаки сложения и вычитания.

Отступы. Размер отступов должен соответствовать позиции кода в иерархии. Это общая практика, которая позволяет быстро пропускать области видимости, не относящиеся к текущей ситуации. Не поддавайтесь искушению нарушить правила расстановки отступов для коротких команд.


Некоторые замечания по поводу архитектуры и тестов

В системе должны выполняться все тесты. Тесты – главный способ, с помощью которого можно понять, что система контролируема. А только контролируемую систему можно проверить.

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

  1. Не пишете код продукта, пока не напишете отказной модульный тест.
  2. Не пишите модульный тест в объеме большем, чем необходимо для отказа.
  3. Не пишите код продукта в объеме большем, чем необходимо для прохождения текущего отказного теста.

F.I.R.S.T. Качественные тесты должны обладать пятью характеристиками, первые буквы которых образуют указанный акроним:

  • Fast. Тесты должны выполняться быстро.
  • Independent. Тесты не должны зависеть друг от друга и выполняться в любом порядке.
  • Repeatable. Тесты должны давать воспроизводимые в любой среде результаты.
  • Self-validating. Результат выполнения теста – логический признак: тест пройден или нет. Иначе результаты приобретают субъективный характер.
  • Timely. Тест должен создаваться своевременно. Тесты нужно писать непосредственно перед написанием кода.

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

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

Несколько языков в одном исходном файле. Современные среды программирования позволяют объединять в одном файле код, написанный на разных языках. Результат получается запутанным, неаккуратным и ненадежным. Чтобы четко разграничить ответственность, в файле должен преобладать один язык. Сведите к минимуму количество и объем кода на дополнительных языках.

Не нужно бездумно следовать догмам. Не переусердствуйте с сокращением кода функций и классов. Всегда руководствуйтесь здравым смыслом.

Заключение

Чистый код выглядит так, как если его автор над ним тщательно потрудился. Вы не можете найти очевидных возможностей для его улучшения. Попытавшись его улучшить, вы вновь вернетесь к тому же коду.

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

Стилистические требования к написанию программного кода

пишите поддерживаемый код

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

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

Общие положения

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

Разбивка по модулям

Каждый логический объект кода должен находиться в отдельном файле, далее называемом модулем. Модуль должен содержать не более одного логического объекта. Это может быть класс, функция или даже константа. Всё зависит от назначения объекта. Примерами модулей являются:

  • Контроллер Express.js
  • Модуль Node.js
  • Плагин yb-processor
  • Middleware yb-server
  • Контроллер yb-client

Оформление модуля

Каждый модуль должен начинаться с комментария, в котором должны быть указаны:

  1. Имя первоначального автора модуля
  2. Дата создания модуля
  3. Назначение и краткое описание модуля
  4. Место модуля в иерархии
  5. Лицензия, под которой распространяется модуль (если отличается от лицензии вышестоящего в иерархии объекта)

Примером правильно оформленного начала модуля является такой заголовок модуля CoffeeScript:

Общие правила оформления кода

Обязательно использование символов табуляции для отбивки кода, за пробелы кастрирую без суда и следствия.

  • Легче форматировать
  • Легче редактировать на удалённом сервере
  • Можно настроить ширину табуляции по своему вкусу

JavaScript

Общие правила

Текст комментария должен быть отделён одним пробелом от символа комментария.

Использование пробела

  • В однострочных массивах и объектах после открывающей и перед закрывающей скобками
  • Между именем функции и списком параметров (если функция анонимна, то между словом function и списком параметров)
  • Всегда после запятой, кроме случаев, когда следующий элемент списка записывается с новой строки
  • Вокруг бинарных операторов (арифметические, логические, оператор присваивания)
  • После двоеточия в описаниях объектов

Пробел не ставится

  • В списке параметров функции после открывающей и перед закрывающей скобками
  • Для выравнивания переменных в столбцах
  • При вызове функций

Перевод строки

Символ перевода строки ставится:

  • После открывающей фигурной или квадратной скобки в описаниях массивов, объектов, при ограничении области видимости или группировке операторов за исключением однострочных объектов и массивов
  • Между операторами и выражениями (т.о. каждая строка должна содержать не более одного оператора/выражения)
  • Между элементами длинных списков при записи массивов, параметров функций, объектов

Пустая строка ставится между:

  • Двумя определениями функций
  • Логически раздельными участками кода
  • По усмотрению автора

Использование точки с запятой в конце строк в модулях JS запрещено.

Использование фигурных скобок

Фигурные скобки играют в JS три роли: ограничение области видимости, группировка операторов и описание объектов. Во всех случаях используется одинаковое оформление.

Открывающая фигурная скобка должна быть отделена пробелом от предыдущего символа, закрывающая должна быть лишь отбита нужным количеством символов табуляции. Если открывающей фигурной скобке предшествует квадратная или круглая, то пробел между ними не ставится. Аналогично пробел не ставится после закрывающей скобки, если сразу за ней идёт круглая или квадратная.

Однострочные объекты

Использование однострочных объектов допустимо, когда такие объекты содержат не более одного поля. В остальных случаях нежелательно.

В случае, когда объект передаётся как параметр функции и содержит более одного поля, также допускается запись такого объекта прямо в вызове функции в одну строку, однако рекомендуется всё же записывать такой объект на нескольких строках.

Группировка операторов

При группировке операторов используются те же правила оформления фигурных скобок. При этом, даже если оператор в группе ровно один, он обязательно обрамляется фигурными скобками.

Правила написания кода

Имена переменных, функций, объектов

Всегда следует использовать camelCase, начиная имя с прописной буквы. Переменные не должны содержать в имени глаголы, функции же обязательно должны содержать глагол в названии, отражающий совершаемой ими действие.

Запрещено давать бессмысленные имена. Каждое имя должно отражать назначение переменной или функции.

CoffeeScript

Общие правила

Общие правила оформления совпадают с правилами для JavaScript, однако есть некоторые дополнения, связанные с особенностями синтаксиса.

Вызов функций

В случае, если производится вызов функции с единственным параметром, то он никогда не заключается в круглые скобки, даже если это однострочный объект. Сам однострочный объект при этом не обрамляется в фигурные скобки.

В случае, если параметров несколько, они также не обрамляются в круглые скобки. При этом объекты-параметры всегда обрамляются фигурными скобками.

В случае, если функция в качестве одного из параметров принимает callback, используется следующая запись:

Круглые скобки в вызове someFunc также не ставятся. В случае, если callback не является последним параметром, или если нужно добавить ещё один callback, используется следующая запись:

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

Вызов функций в выражениях

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

Несмотря на то, что компилятор верно скомпилирует такое выражение:

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

Условные операторы

Запрещается использование краткой формы условного оператора:

Запрещается использование if not :

Запрещается использование is undefined и is null . Следует использовать оператор существования: if someVariable? .

Запрещается использовать обратные условия:

Часто возникает ситуация, когда в обработчике результата асинхронной операции нужно проверить наличие ошибки и вернуть какой-либо специальный результат в случае её наличия.

return

В общем случае, когда неочевидно, каков будет результат функции, следует ставить оператор return . В остальных случаях это не обязательно. Если в конце функции возвращается некий объект, массив или вообще переменная, следует предварить её оператором return . Если функция просто возвращает константу, предварять её оператором return не следует.

Короткие функции

Если функция входит в состав выражения, или передаётся в виде параметра, и её тело достаточно коротко, то её можно записать в одну строку:

Хотя такая запись и не приветствуется.

AngularJS

Общие правила

Код следует разделять либо по назначению, либо по функции. В небольших проектах допускается следующая структура кода:

Где controllers содержит все контроллеры, directives все директивы, а resources все сервисы. Однако для больших проектов такой способ малопригоден и выгоднее разделять модули по группе выполняемых функций.

При таком разделении очень легко найти нужные модули, а группы не мешают друг другу.

Dependency Injection

Также выше указана рекомендуемая форма записи во всех подобных ситуациях.

Использование манипуляций с DOM

Любые манипуляции с DOM за пределами директив строго запрещены. Забыть про jQuery и иже с ними.

Использование $scope

Не следует рассматривать $scope как модели. Это связка между настоящими моделями (Backbone.js, Restangular) и видом. Не больше, но и не меньше. Модели не обязательно выделять в отдельные сервисы, чаще всего достаточно просто использовать Restangular напрямую.

Рекомендуемые модули

Angular UI Router, Restangular.

Общие правила

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

Отбивка

Как и во всех остальных случаях осуществляется только символами табуляции. Отбивка осуществляется всегда, когда возникает новая ступень иерархии DOM. Следует помнить, что текст внутри тега создаёт новую ступень иерархии (см. пример выше).

Перевод строк

Рекомендуется переводить строку перед переходом на новую ступень иерархии, однако в некоторых случаях это не обязательно. Обязательно переводить строку, если производится возврат на предыдущую ступень иерархии.

Не рекомендуется записывать более двух ступеней иерархии в одну строку, даже если они невелики по объёму.

CSS, LESS, SASS

В организации кода рекомендуется придерживаться методологии SMACSS или по крайней мере разделять модули по принадлежности к группе элементов сайта. Например выделить в отдельный файл стили для заголовка страницы, стили для записи в блоге и т.д.

При записи правил CSS/LESS/SASS следует придерживаться того же стиля записи фигурных скобок, что и в JavaScript:

Соавтор(ы): Archana Ramamoorthy, MS. Арчана Рамамурти — технический директор Workday (Северная Америка). Высококлассный специалист по продуктам, поборница безопасности, сторонница большего распространения интеграции на равных для всех условиях в индустрии технологий. Получила степень бакалавра в Университете SRM и магистра в Университете Дьюка. Работает в области продакт-менеджмента более восьми лет.

Изображение с названием Code Step 1

  • Выбирая язык, сконцентрируйтесь на том, в каких целях вы хотите создавать программные коды, и уже потом выбирайте начальный язык. К примеру, если вы хотите заниматься разработкой веб-сайтов, то вам следует начать с изучения HTML5, а затем дополнить его языками CSS, JavaScript и PHP. Если вы хотите создавать компьютерные программы, то начните изучать C ++ или любой другой основной язык программирования.
  • Если вы станете профессиональным программистом, то вы можете обнаружить, что никогда не используете язык, который вы изначально выучили, для своей работы. Вместо этого вы будете все время продолжать учить новые языки через документацию и эксперименты.

Изображение с названием Code Step 2

Технический директор Workday

Арчана Рамамурти — технический директор Workday (Северная Америка). Высококлассный специалист по продуктам, поборница безопасности, сторонница большего распространения интеграции на равных для всех условиях в индустрии технологий. Получила степень бакалавра в Университете SRM и магистра в Университете Дьюка. Работает в области продакт-менеджмента более восьми лет.

Читайте также: