Pull to refresh

Comments 46

> Когда я пишу код, мне нравится отдавать себе отчёт о том, что именно я делаю.

Когда я пишу код, мне вот приходится отдавать себе отчет о том, что именно я делаю :-)
Не так давно один «смышленый» заказчик попросил откомментировать меня код следующим образом:
/**
* public function doSmth()
*/
public function doSmth() {}

Долго приходилось отдавать себе отчет, в том что именно я делаю О_о
С таким «смышленым» заказчиком мог бы справиться скрипт.

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

Вобщем вам еще повезло :)
ИМХО, самая жесть — когда комментарий подробно описывает, что будет делать метод, но на самом деле метод делает что-то другое. Я пару раз так ловился: в комментарии «this method updates local variable», на деле код лезет в базу данных и что-то там обновляет. Брр.
Не преувеличивайте. Уверен, что для сложных функций заказчик требовал описание всех параметров — названия функции в большинстве случаев достаточно для того, чтобы понять, что она делает, с названием параметров всегда проблемы (например, что такое parent_id и проч.):

/**
* public function doSmth()
* param1 — …
* smth1 — …
*/
public function doSmth(int param1, double smth1) {}
Комментарии зачастую — немалое зло, так как имеют свойство устаревать и рассинхронизироваться с кодом, которому относятся. Так что, по возможности, я стараюсь обходиться длинными понятными названиями переменных/функций/классов.

Т.е.

public function doSmth( int UniqueIdOfParentClassAsControl, double CelciusTemperatureToDisplay ){}

Прошу прощения, имена переменных несколько надуманны. Такие имена переменных сами собой поддерживаются в актуальном состоянии.

И ещё — если кусок кода напрашивается на комментарий — я задумываюсь — а не вынести ли его в отдельную функцию с ясным названием вместо этого. По тем же причинам.

Собственно, после этого, за редкими исключениями, остаются только комментарии для всяких систем автогенерации справки, типа Doxygen.
Иногда комментарии необходимы, а названия должны быть короткими и одназначными чтобы уменьшить количество ошибок и ускорить чтение кода (это уменьшает желание читающего переписать код по своему)
Но если у метода расширяется функционал то проще написать комментарий чем заменять во всем проекте, хотя если правильно организовывать код то это случается крайне редко.
«Короткими» и «Однозначными» — зачастую несовместимы. Ну назовёте вы переменную id или handle — вроде, суть отражает, а понятней не стало.
Количество ошибок это увеличить не должно — опечататься не даст автокомплит и компилятор. Читается такой код как раз замечательно — практически связный текст на английском языке.

  
if( mOS->IsBatteryInCriticalState() )
{
  TRACE( "Low battery level - exit" );
  ShutDown();
}

или

virtual bool GetMemoryUsage( int &aTotalKB, int &aFreeKB, int &aUsedKB, int &aSwapKB ) = 0;

if( mSysInfoEngine->GetMemoryUsage( Status.system.totalRAMkB, Status.system.freeRAMkB, Status.system.usedRAMkB, Status.system.swapRAMkB ) )
  // Do smth

Какие комментарии вы бы сюда добавили?

Как раз переименовать во всём проекте проще, так как это, обычно, можно сделать средствами среды разработки, в полуавтоматическом режиме. А вот поправить все места возможных комментариев (в *.h, *.cpp и в местах использования) — совсем не тривиально.

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

Пол вашим примерам:

// IsBatteryInCriticalState()
// Возможно ложное срабатывание, требуется повторная проверка через некоторое время. Не учитывает наличие других источников питания.

GetMemoryUsage()
// Возвращает суммарный объем фрагментов. Для получения информации о фрагментах см. GetMemoryDetails()
В одной конторе с которой мне приходилось сотрудничать говорили — «Недостаточное количество комментариев, достаточная причина для увольнения».
Не поверите, код написанный тогда, сейчас спустя несколько лет, прекрасно читаем и понятен… ))) А что бы комментарии не устаревали, их стоит менять вместе с изменением кода.
UFO just landed and posted this here
Постоянно пишу в таком духе, поэтому получается мало и переодически всё переписываю чтоб было красиво. Такой код просто приятен сам по себе. Но блин как же медленно я пишу. Иногда возникают мысли всё бросить и писать как придётся, но уже видимо привычка…
У всего есть обратная сторона: можно писать код быстро, но потом тратить много времени (и/или нервов) на багфикс.

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

Сразу документировать бесполезно, поскольку обычно подбор лучшего алгоритма идет наощупь с частым переписыванием кода.
Имхо всегда стоит отдавать себе отчет в том, что надо писать правильный код и всегда придерживаться правил, независимо «для себя» он или же для кого-то там еще.
Все эти отступы от собственных правил ни к чему хорошему не приведут в итоге. В дальнейшем просто будет «а, да тут можно и схалявить, все равно заказчик не полезет смотреть исходники» (это к тому, что код никто не смотрит) — а это не есть хорошо.
В общем, Вы правы.
Однако, зачастую надо писать код очень быстро. В таких случаях приходиться принимать решения, где стоит потратить время на документирование (проверку параметров и пр), а где не стоит. Тогда полезна приведённая классификация.
Не всегда. Вы же не будете в программу Hello world! писать throw-try-catch и другую лабуду.
Я не пишу программ типа «Hello world!».
А в программах содержащих пару строк кода все равно следую правилам в виде хотя бы банальных отступов, которыми многие пренебрегают…
Хорошая среда разработки должна сама расставлять отступы, что бы программист об этом даже не задумывался.
«Есть ещё одно важное правило. Если для работы прототипа необходимо поменять старый код, изменение должно иметь комментарий. Хотя изменение может быть очевидно в момент написания прототипа, через несколько месяцев будет очень сложно понять, что же хотелось сделать. Особенно если прототип пришлось выкинуть.»
помоему тут нужно делать бренчь в системе конроля ревизий…
Согласен, бренчь — самое чистое решение. Если есть возможность делать прототип там, то обязательно надо ей пользоваться.
К сожалению, я был в ситуациях когда необходимо было разрабатывать прототип в основной ветке. Очень неприятные ситуации…
Названия терминов классификации (точка роста, точка интеграции) сами придумывали?
Я про себя называл это внешний API (для клиентов), корпоративный API (для коллег = точки интеграции?), внутренний API (для себя = точки роста?) и остальной код, хотя может ваши термины и точнее.
Названия придумывал сам. Думаю, что как назвать не очень важно: главное, смысл. Внешние, корпоративный и внутренний API тоже нормальные названия.
Я с самого начала привык писать качественный, читабельный, хорошо документированный код.

Теперь я учусь писать код в стиле «работает и черт с ним». Потому что иногда это оправдано, иногда быстрое решение важнее качественного. При необходимости в будущем можно сделать рефакторинг. Но, как правило, такая необходимость возникает очень редко.
Ваш подход оправдан, только для одноразового кода. Если код совершенствуется часто — лучше затратить чуть больше усилий на качественный код, чем потом постоянно ругать себя за необдуманность.

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

Из этого вывод — слабо зависимый от другого кода, неосновополагающий, простой (с относительно прозрачной архитектурой, но необязательно с простым алгоритмом) код должен разрабатываться быстро (меньше внимания деталям/качеству/документации) и дорабатываться по мере необходимости — его изменения должны повлечь минимум временных затрат, и затрат на обновление зависимого кода.
Эту мысль стоило бы добавить в пост. Код действительно можно разделить на «основопологающий» и «неосновополагающий».
Хотя, дьявол в деталях: как найти между ними грань.
хороший критерий — цена ошибки
чем больше времени уделяешь написанию качественного кода, тем меньше головной боли будет потом =)

но иногда это «потом» может и не наступить, поэтому можно написать кое-как

Страшнее когда твой «качественный код» считают за написанный кое-как
или когда нет ни времени писать дальше ни времени потом это исправить потомучто «это не приносит денег компании» таких работодателей надо слать. что я и сделал в свое время
«писать качественный код» вместо «дальше»
Лично мне трудно перестать давать переменным значимые названия и хорошо комментировать код. Даже в «Hello world», наверное, буду сначала минут 5 продумывать структуру программы, что как назвать и.т.д… Это занимает много времени, но и избавиться от мыслей «зато какая красивая структура» и «а вдруг придется дописать когда-то» так просто не могу…
Это же отлично!

Наверное, стиль кода довольно сильно зависит от компании, где работает разработчик.
Есть два случая:
1. Разработчик может сказать, сколько времени ему надо на разработку фичи. Тут всё просто: код действительно можно писать очень хорошо, документируя каждую деталь.
2. Разработчику ставят сроки. Тут-то и надо принимать сложные решения: как написать неплохой код и успеть в срок. Понятно, что удар берут на себя документация, проверка входных данных и юнит-тесты. Тут появляются комментарии //TODO: Refactor this later

Однако, поймите меня правильно. Цель этой статьи рассказать о местах в коде где документация совершенно необходима. Я ни в коей мере не пытаюсь сказать, что иногда можно писать плохой код.
Очень помогает давать осмысленные названия не сразу, а чуть позже. Для применения этого совета обязательно должно быть автоматический рефакторинг «переименование» в IDE. Вместо того, чтобы сразу давать название методу — называете его 'qqq' или любое другое любимое сочетание клавиш. А когда большая часть метода уже написана, становится гораздо легче подобрать ему название.
Втом то и дело, что я не могу взяться за написание даже самой простой програмки, если перед этим не спланировал всю структуру. Не говоря уже о программах, на написание которых я планирую потратить от нескольких дней — тогда я как минимум рисую на бумажке A4 всю структуру, взаимодействия и.т.д. Так что название всех переменных и.т.д. я знаю еще перед началом кодинга.
UFO just landed and posted this here
да, код читабелен, поскольку мал. Хотя использование названий типа function t() или $icl вряд ли этому способствует.
UFO just landed and posted this here
Ну, в общем то, да. Разделите объявление функции t() и её использование сотней строк кода, и попробуйте читать с той строки, где она вызывается. Легко ли будет догадаться, что она делает, не проскроллив несколько экранов? Разнесите функцию to_kbs() и её использование в разные файлы, и попробуйте угадать, что она принимает на вход — байты или мегабайты.
когда-то очень давно, когда училась программировать и пыталась писать программы, завела себе привычку — сначала пишу в комментариях алгоритм функционала, а затем под соответствующими комментами уже писала сам код :)
лучше писать не алгоритмы в комментариях, а сразу тесты под будущий код)
тогда про тесты никто почти ничего не знал :)
Мне кажется, у МакКоннела есть рекомендация: писать столько комментариев, чтобы можно было понять, что происходит, не читая код между ними.
Я бы еще добавил «Точку риска», где располагается некий сомнительный функционал. Такие места удобно заключать в #ifdef, чтобы в случае необходимости сгенерить код без этих вопросительных моментов и без ведения отдельного бренча.
Большое спасибо: это отличная идея.
Я не уверен, как именно это определить, но понятие нужное. Мне самому не раз приходилось писать что-то вроде //HACK ALERT: This code might break.
Sign up to leave a comment.

Articles