Бессмертные best practices в программировании на любом языке
Твоя обязанность как программиста – экономить время, ресурсы и деньги руководства. Мы решили поделиться с миром важными принципами чистого кода. Поехали!
Основные принципы
Писать чистый код – как писать книгу: сначала черновик, а потом редактирование до состояния завершенности и легкой читаемости. Это гарантирует, что следующему программисту, столкнувшемуся с твоей работой, не придется тратить время на расшифровку вложенного тобой смысла.
- Осмысленные имена. Если имя объекта не соответствует его функционалу и назначению, то его следует переименовать во что-то подходящее. Если это невозможно – значит, что-то не так с функционалом, и код должен быть отрефакторен.
- Повторное использование
и гибкость.
Различные модули приложения должны легко повторно использоваться в контексте
одного проекта или легко переноситься в другой проект.
- Единая ответственность. Любая сущность должна отвечать за один и только один функционал. Само собой, что все должно быть красиво и лаконично описано.
- Простота. Код должен быть таким, чтобы через некоторое время, открыв его, ты смог понять суть. Постоянно просматривай свой код, как в первый раз.
- Code review. Весь код каждого члена команды проходит через строгий анализ (в идеале, командный) и QA-тестирование до тех пор, пока не разрешатся все спорные моменты или пока они не будут покрыты TODO-комментариями.
- Дальновидность и ошибки. Пиши свой код со взглядом в будущее, чтобы избежать дорогостоящих ошибок и багов, вызванных позже в процессе разработки.
- Обслуживаемость. Это чуть ли не важнейший атрибут хорошего кода. Твоя писанина рано или поздно будет переписана/дописана, так что нет необходимости усложнять этот процесс.
- "Магические числа" должны быть помещены в константы.
- Функции и аргументы. Функция не должна принимать большое количество аргументов. Если аргументов слишком много, это может указывать на необходимость еще одной функции.
- Код должен быть покрыт тестами. Если ты начал рефакторинг или реализацию новых фич, а тестами покрыт не весь код, есть большая вероятность появления ошибки, которая даст о себе знать впоследствии.
- Защита от потенциальных уязвимостей. Особое внимание следует уделять уязвимостям кода, особенно когда он написан без учета его безопасности.
Это были ключевые вещи, которые ты должен знать и применять на каждом шагу. Теперь перейдем к теории, уточняющей некоторые нюансы для лучшего понимания.
Функции
- Избегай передачи
boolean
в функцию. Это намек на то, что код выполняет несколько действий, а это нехорошо. - Функции должны или делать что-то или отвечать на что-то, а не одновременно обе задачи. Это гарантирует, что со временем не вылезут скрытые побочные эффекты. Например, функция
isPresent()
должна возвращать только bool и ничего более не выполнять. - Для обработки исключений и для возврата кодов ошибок используй только блоки
try-catch
. Хорошо бы вообще вынести все в отдельный метод. Не смешивай данный код с остальным – это усложняет его читабельность. - Остерегайся выходных аргументов. Функция должна (если должна) изменить состояние своего объекта-родителя.
- Код всегда должен быть разделен пустой строкой, чтобы объединить логические блоки вместе.
- Реализация функции всегда должна следовать за ее вызовом.
- Не возвращай значение
null
.
Объекты и структуры данных
- Переменные должны быть
private
, чтобы можно было изменять их тип или реализацию, когда это потребуется. Используйте геттеры и сеттеры. - Сокрытие реализации. Тебе следует не раскрывать детали данных, а скорее выражать данные в виде абстрактных терминов.
Исключения
- Возвращай исключения вместо кодов ошибок.
- Каждое созданное исключение должно обеспечивать достаточный контекст для определения источника и местоположения ошибки – конкретизируй, и тебе самому будет проще.
Комментарии
- Действительно хороший комментарий – это комментарий, в наличии которого нет необходимости.
- Не используй комментарий, если можно придумать хорошее и понятное имя для функции или переменной.
- Любой комментарий, заставляющий искать смысл происходящего в другом куске кода или модуле, не должен существовать.
- Не комментируй плохой код – перепиши его!
Организация кода
- Каждый блок кода должен нести смысловую нагрузку. Эти блоки должны быть отделены друг от друга пустыми строками.
- Локальные переменные должны быть объявлены как можно ближе к их использованию.
- Переменные экземпляра должны быть объявлены в верхней части класса, так как в хорошо спроектированном классе они будут использоваться несколькими методами.
- Если одна функция вызывает другую, вызывающая должна быть выше вызываемой (если это возможно). Это придает программе естественный поток.
- Попробуй следовать "принципу наименьшего удивления" – любая функция или класс должен реализовывать поведение, которое было бы ожидаемым для другого программиста.
Тесты
Существует
пять принципов тестирования – F.I.R.S.T
(или Б.Н.П.С.С.
). Расшифровывается это
так:
- Fast (Быстрота): тесты должны выполняться быстро, иначе их никто не будет запускать.
- Independent (Независимость): тесты не должны зависеть друг от друга. Один тест не должен создавать условия для следующего. Ты должен иметь возможность запускать каждый тест независимо и в любом порядке.
- Repeatable (Повторяемость): тесты должны быть повторяемыми в любой среде – в продакшене, в среде QA и на ноуте в метро без сети.
- Self-Validating (Самопроверка): тесты должны иметь вывод типа
boolean
. Либо они проходят, либо терпят неудачу. Для того чтобы узнать результаты, не нужно лезть в файлик журнала. - Timely (Своевременность): тесты должны быть написаны своевременно.
Проектирование
- KISS: Keep It Simple Stupid. Избегай ненужной сложности. Вопрос, который нужно задать в процессе кодинга: "Можно ли это написать проще?"
- DRY: Don't Repeat Yourself. Результатом работы этого принципа является отсутствие необходимости внесения изменений в другие, логически не связанные элементы, при изменении единственного элемента системы.
- YAGNI: You Aren't Gonna Need It. Суть принципа – отказ от создания избыточного функционала, в котором на данный момент нет необходимости.
- Композиция лучше наследования. Сложный для понимания принцип, но все же. Классы должны достигать полиморфного поведения и повторного использования кода путем их композиции (путем содержания экземпляров других классов, реализующих желаемую функциональность), а не наследования от базового или родительского класса.
- Удобочитаемость. Вопрос уже поднимался выше, но следует повториться. При работе над проектом (особенно в команде), всегда отдавай предпочтение читабельности над лаконичностью. Нет смысла иметь сжатый код, если его не понимают.
Литература
Ну и вместо точки предлагаем тебе подборочку книг для развития твоих навыков написания качественного кода. По возможности прочитай несколько из них и применяй все советы на практике.
- Рефакторинг. Улучшение проекта существующего кода – Мартин Фаулер
- Чистая архитектура – Роберт Мартин
- Паттерны проектирования – Эрик Фримен, Элизабет Фримен
- Совершенный код. Мастер-класс – Стив Макконнелл
- Чистый код: создание, анализ и рефакторинг – Роберт Мартин
- Программист-прагматик. Путь от подмастерья к мастеру – Э. Хант, Д. Томас