Критерии хорошего кода

Хороший код — понятный и непрожорливый до ресурсов. Давайте поговорим об этом.

Время на понимание

Главный критерий хорошего кода — это время T, которое требуется не-автору, чтобы разобраться в коде. Причем разобраться не на уровне «вроде понятно», а достаточно хорошо, чтобы внести изменения и ничего не сломать.

Чем меньше T, тем лучше код.

Допустим, Нина и Витя реализовали одну и ту же фичу, а вы хотите ее доработать. Если разберетесь в коде Нины за 10 минут, а в коде Вити за 30 минут — код Нины лучше. Неважно, насколько у Вити чистая архитектура, функциональный подход, современный фреймворк и всякое такое.

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

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

Напрямую T не очень-то померяешь, поэтому в основном используют практики, которые положительно влияют на T:

  • соответствие код-стайлу,
  • проверка на «запашки» в коде (линтинг),
  • уменьшение цикломатической сложности,
  • зависимости между модулями без циклов,
  • код-ревью.

Потребление ресурсов

Второй критерий хорошего кода — количество ресурсов R, которое он потребляет (времени, процессора, памяти, диска). Чем меньше R, тем лучше код.

Допустим, Нина и Витя реализовали фичу с одинаковым T. Если код Нины работает за O(n), а код Вити за O(n²) (при одинаковом потреблении прочих ресурсов) — код Нины лучше (для достаточно большого n).

Насчет ситуации «пожертвовать понятностью ради скорости». Для каждой задачи есть порог потребления ресурсов R₀, в который должно уложиться решение. Если R < R₀, не надо ухудшать T ради дальнейшего сокращения R.

Если некритичный сервис обрабатывает запрос за 50мс — не надо переписывать его с питона на C, чтобы сократить время до 5мс. И так достаточно быстро.

Если у кода высокое T при низком R — в большинстве случаев можно сократить T (отрефакторить код для лучшего понимания), сохранив R < R₀ (достаточно низкое потребление ресурсов).

Иногда, если ресурсы ограничены, или исходные данные большие — не получается достичь R < R₀ (например, уложить выполнение задачи в 5мс) без ухудшения T (например, без инлайнинга функций и собственной реализации структур данных из стандартной библиотеки). Тогда действительно приходится жертвовать понятностью ради эффективности. Но убедитесь в следующем:

  1. Это последний вариант, когда все прочие уже испробованы.
  2. Участки кода, где пожертвовали T ради R, хорошо изолированы.
  3. Таких участков мало.
  4. Они подробно документированы.

Итого

Мнемоника хорошего кода:

T↓ R<R0

Оптимизируйте T, следите за R. Коллеги скажут вам спасибо.

Подписывайтесь на канал, чтобы не пропустить новые заметки 🚀