Java: fill the gaps
12.6K subscribers
7 photos
216 links
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк

🔥Тот самый курс по многопочке🔥
https://fillthegaps.ru/mt

Комплименты, вопросы, предложения: @utki_letyat
Download Telegram
Чистая архитектура: главы 1-2

Начала читать книгу Clean architecture Роберта Мартина.

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

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

У меня нет больших ожиданий. Книга 2017 года, да и Мартин вряд ли плотно работал в энтерпрайзе, когда её писал. Но мне интересно почитать первоисточник и идейную составляющую.

И по первым впечатлениям - книга очень противоречивая.

Поднимается много тем - от парадигм программирования до структуры папок в проекте. Есть что обсудить👌

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

Поэтому решила делиться с вами процессом чтения. Это не будет подробный конспект, скорее спидран/реакция/саммари. Буду отмечать, что мне показалось интересным. Думаю, получится полезно.

Главы 1 и 2 - это введение. Большой смысловой нагрузки пока нет.

⭐️ Глава 1 ⭐️

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

⭐️ Глава 2 ⭐️

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

Собственно, и всё.

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

В целом, Мартин кажется противоречивым персонажем, поэтому интересно, что будет дальше. Идеалистические концепты? Конкретные инструкции? 400 страниц воды? Посмотрим, обсудим
🔥114👍4722🎄4👎3
Чистая архитектура. Главы 3-5

Продолжаем спидран по Clean Architecture Роберта Мартина.

⭐️ Глава 3. Парадигмы программирования ⭐️

определяют способы написания и организации кода. Их 3:

▫️ Структурная - ход программы описывается явно через условия и циклы. Используется для описания алгоритмов
▫️ Обьектно-ориентированная - программа описывается как взаимодействие объектов. Используется полиморфизм, ход работы не всегда очевиден
▫️ Функциональная - базируется на неизменяемости

⭐️ Глава 4. Структурное программирование ⭐️

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

⭐️ Глава 5. Обьектно-ориентированное (ОО) программирование ⭐️

Роберт рассуждает, что полезного и нового предлагает ООП

▫️ Инкапсуляция - не уникальна для ООП, плюс в современных языках не решает свою задачу.

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

В С (предшественник С++) определение функции и реализация разнесены по разным файлам, там инкапсуляция нормальная. В современных ОО языках инкапсуляция слабая. Нет разделения на определение и реализацию. Чтобы посмотреть, что умеет класс, надо зайти в класс, и тут открывается вся его внутрянка. Детали реализации как на ладони.

(мысль интересная, но с текущими IDE это не актуально. Выпадающие списки методов делают большой вклад в сокрытие сложности)

▫️ Наследование - всего лишь переопределение переменных/функций в ограниченном контексте. Добавочной ценности для архитектуры нет.

▫️ Полиморфизм легко и безопасно реализован в ОО языках, и в этом его главная ценность. Благодаря полиморфизму расцвел концепт инверсии зависимостей.

Дальше автор объясняет dependency inversion. Тут меня знатно побомбило.

DI - базовый кирпичик и первый шаг к чистой архитектуре. Это самая важная часть раздела. И она объяснена очень плохо:
▪️ Роберт вводит 2 типа стрелочек: source code dependency и flow of control. Не объясняя, что это такое
▪️ Рисует схему, где стрелочки идут вместе
▪️ Добавляет в схему ещё один квадрат (интерфейс) и поворачивает одну стрелку в другую сторону

На этом всё. Ни одного примера с кодом, только квадратики и стрелки. Этого недостаточно, чтобы каждый читатель понял, что нужно делать и в чём инверсия. Просто добавить интерфейс к каждому классу? Service и ServiceImpl это и есть тот самый power move?

Особенно дико такое объяснение выглядит на контрасте с менее важными темами. Рядом есть детальный разбор
✔️ разницы инкапсуляции в С и С++
✔️ как в С (язык без классов) можно имитировать наследование
✔️ как работают атомики в Clojure

Всё это разжевано гораздо подробнее, чем DI🤦

В 11 главе Роберт сделает второй заход в dependency inversion, но (спойлер) всё останется на уровне "просто добавь интерфейс". Это рекомендации по форме, но не по содержанию.

Интерфейсом может быть не только дополнительный квадратик, но и набор публичных методов класса. Чем больше этот набор скрывает детали реализации и упрощает работу с классом, тем лучше. И чтобы уменьшить связность, не обязательно множить сущности.
👍6425🔥17👎5
Тестовый контекст поднимается 2 минуты. У нас 4 класса с интеграционными тестами, их конфигурация ниже. Настройки прогона тестов стандартные. Сколько времени займет выполнение этих тестов?
@SpringBootTest
public class UserIT{...}

@ActiveProfiles("test")
@SpringBootTest
public class BidProcessingIT{...}

@SpringBootTest(properties = {
"user.rebalance.enabled=true"
})
public class RebalanceAccountIT{...}

@ActiveProfiles("test")
@SpringBootTest
public class AccountProcessingIT{...}
5
Как переиспользовать контекст в интеграционных тестах

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

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

Если в коде теста какой-то бин помечен @MockitoBean, @MockitoSpyBean или @TestBean, Spring создает для него прокси. Получается уникальный контекст, который нужно поднимать отдельно и нельзя в дальнейшем переиспользовать.

К новому контексту приводит переопределение свойств, указание профиля, конфигурация MockMvc и тд

Ответ на вопрос перед постом - прогон тестов будет занимать чуть больше 6 минут, потому что формируется 3 контекста. Для тестов BidProcessingIT и AccountProcessingIT используется один контекст.

🤔 Как оптимизировать выполнение тестов?

Популярный прием, который помогает зафиксировать контекст - базовый класс с тестовой конфигурацией. В базовом классе настраивается тестовый конфиг, тестконтейнеры, решается вопрос с секьюрити, наполнением и очисткой БД и тд
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(…)
@TestExecutionListeners(…)
@ActiveProfile("test")
// куча других аннотаций
public abstract class BaseIntegrationTest {
// тестконтейнеры
// заглушки
}

Остальные классы наследуются от базового:
class UserIT extends BaseIntegrationTest {
@Autowired
  private MockMvc mockMvc;
  @Test
  public void shouldCreateUser() {…}
}

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

На практике редко используется один базовый класс, чаще это иерархия под разные случаи. При грамотном проектировании и сознательности разработчиков интеграционные тесты выполняются за адекватное время даже для больших проектов👌
57👍35🔥21👎2