Технические стандарты
Checkstyle¶
Обязательно в каждом проекте использовать в пайплайне сборки плагин checkstyle. Сборка должна завершаться с ошибкой, если шаг checkstyle не пройден. В уже существующих проектах допускается выставить текущее количество ошибок в качестве лимита, чтобы новый код не вносил новых ошибок. И далее заниматься планомерным доведением лимита до 0.
Nullability¶
Обязательно использование Optional вместо null
.
Mapping¶
В качестве фреймворка для маппинга класса желательно использовать MapStruct. Так как он работает по принципу кодогенерации, то большая часть проблем с маппингом обнаружится на этапе компиляции, а не в рантайме.
Дата/Время¶
При передаче в текстовом виде даты и времени между системами используйте формат ISO 8601. Пользуйтесь константами из DateTimeFormatter
. Например:
Не используйте класс java.util.Date. Класс Date не является иммутабельным, thread-safe и не рекомендуется к использованию с Java 8+. Вместо него необходимо использовать новое Date Time API: классы Instant, LocalDateTime, ZonedDateTime…
Желательно использовать свой класс обертку над методом LocalDateTime.now() для получения текущего времени. Это полезно для тестирования. Замокав этот класс обертку на возврат фиксированного времени вы можете сделать тесты детерминированными.
DAO¶
В репозиториях и DAO классах использовать следующую стратегию именования методов:
- Если метод может вернть null, то называем его findXxx и обяательно оборачиваем результат в Optional.
- Если метод обязательно должен вернуть значение, то он должен начинаться с getXxx и выбрасывать исключение, в случае если запись не найдена.
- Если метод возвращает коллекцию, то он должен называться findXxx и возвращать не null, а пустой список в случае если записи не найдены.
Тесты¶
Mock¶
Стараться по минимуму использовать Mockito в юнит тестах. Часто моки появляются там, где бизнес логика начинает смешиваться с IO (обращения к БД, внешним сервисам).
Нужно стремится выносить всю важную бизнес логику в отдельные классы, без зависимостей на IO. Такие классы будет тестировать намного проще. Оставшийся же код лучше протестировать интеграционными и функциональными тестами без моков.
Никогда не используйте проверку того, сколько раз или с какими параметрами был вызов мока (Mockito.verify).
Тесты должны тестировать контракт, а не внутреннюю реализацию, иначе тесты становятся крайне хрупкими и бесполезными.
Наследование¶
Старайтесь использовать композицию вместо наследования. Наследование приводит к множеству проблем: сильная связанность между потомком и родителем, нарушение инкапсуляции, проблема хрупкого базового класса. По этим же причинам всеми силами старайтесь избегать использования абстрактных классов. Имплементация интерфейса без поведения не несет в себе этих проблем и является предпочтительным способом добиться полиморфизма.
Spring¶
Инжект спринговых зависимостей должен осуществляться через конструктор. Конструктор писать вручную не обязательно, вместо этого можно использовать аннотацию lombok @RequredArgsConstructor
. Все зависимости должны быть private final
. Пример: