DMdev talks
3.24K subscribers
156 photos
13 videos
89 links
Авторский канал Дениса Матвеенко, создателя DMdev - обучение Java программированию

То, что все ищут по Java:
https://taplink.cc/denis.dmdev

P.S. Когда не программирую - я бегаю:
https://t.iss.one/dmdev_pro_run
Download Telegram
Как замерить время выполнения?

Казалось бы, замерить время выполнения какого-то метода проще простого:
1. Вызываем один раз System.currentTimeMillis и сохраняем в переменную
2. Вызываем тестируемый метод и ждем его окончания
3. Вызываем еще раз System.currentTimeMillis и отнимаем результат из пункта 1

Но на самом деле такие математические операции со временем с помощью System.currentTimeMillis или других java.time методов вроде Clock.now может выдать некорректный результат.

Почему?
Все потому, что время от времени срабатывает механизм обновления машинных часов, где работает ваше Java приложение. И это обновление может запуститься в любой момент. А по закону подлости это случится как раз тогда, когда вы будете вызывать тестируемый метод из пункта 2, что приведет к ошибкам в расчетах.

Как тогда замерять?
Есть несколько вариантов, но наиболее предпочтительным для меня является класс Stopwatch из пакета com.google.common.base.
На картинке продемонстрировано, как его просто и удобно использовать.

Практика
Совсем недавно пришлось использовать Stopwatch для того, чтобы отслеживать время выполнения высоконагруженной Scheduled Job, которая считывала пачками (batch) события (events) и отправляла их на обработку. Причем также отслеживалось время выполнение каждой такой пачки. Таким образом, анализируя показатели времени, легко можно было варьировать нагрузку и изменять параметры Job: размер batch, количество потоков выполнения, период запуска Job и т.д.

#dmdev_ликбез
👍52🔥126😱2👏1
#10 Мой путь

Лаборатория EPAM Systems представляла собой обычный open space, где сидело несколько десятков таких же студентов как и я. Каждому выдали старенький компьютер, на котором постоянно все подвисало, и набор из 12 последовательных задач.

Каждая задача представляла собой мини проект, где ты глубже знакомился с различными новыми и старыми фреймворками (вроде Struts, Hibernate, Spring), XML, XSLT и даже JavaScript. На тот момент еще не было Spring Boot, и я часами боролся с несовместимостью версий, чтобы подружить тот же Spring и Hibernate.

Основной квест всей лаборатории - выполнить и защитить 8-12 задач, после чего тебя могут взять уже на реальный проект, когда понадобятся на нем джуны.

Защита проходила довольно просто - ты ждал появления ментора, поднимал руку, мол, есть что показать, и он тестировал твое приложение, смотрел код и спрашивал теорию в рамках задачи. К сожалению, на весь open space был выделен только один единственный ментор, поэтому было не так-то и просто сдать все задачи, даже когда они были готовы.

Из приятного: сразу после успешной сдачи первой задачи тебя официально устраивали в компанию EPAM Systems на позицию Junior Java Developer и начинали выдавать зарплату. Как сейчас помню тот самый момент, когда получил свои первые 300$. На то время это была очень существенная сумма для меня по сравнению со стипендией БГУИР. Казалось, что я могу теперь позволить себе почти все!

Лето подходило к концу, я выполнил 10 задач, а на проекты все никак не набирали джунов из лаборатории. У меня начало закрадываться чувство, что я простаиваю и не развиваюсь как следует без применения своих навыков на реальной практике. Я разговаривал несколько раз на эту тему со своим ментором, но ответ был один: мы можем только ждать появления свободных мест. Как только появятся - сразу же сообщат.

Так я прождал около месяца, после чего решил обновить свое резюме и искать работу в других компаниях...

#my_little_story
37👍25🔥4😢1
Method equals

Про этот метод написано невероятное количество книг и статей, он является излюбленным вопросом на собеседовании. И конечно же неспроста, ибо переопределить его вручную правильно действительно не простая задача, в которой часто допускают ошибки (одно описание контракта в документации чего стоит!).

Но есть вопрос более интересный: а нужно ли вообще переопределять метод equals?

👌Да, нужно, когда 2 объекта одного класса могут рассматриваться как взаимозаменяемые. Когда тебя не волнует, какой из двух этих объектов попадется тебе в коде.

🙅‍♂️Если же есть случаи, когда 2 объекта не взаимозаменяемы, то скорее всего тебе не следует переопределять метод equals - всем джавистам очевидно, что по умолчанию идет сравнение по ссылке.

Особенного неудобства доставляют mutable объекты, потому что они:
- не могут рассматриваться взаимозаменяемыми по своей природе, ибо изменяя состояние одного объекта, вы не изменяете другой
- подвержены багам при использовании во многих коллекциях, например, HashSet или ключом в HashMap

Прекрасным примером таких mutable объектов являются Hibernate Entities. Именно по этой причине так сложно написать хороший метод equals для них, если вообще возможно - про это я говорил в этом видео.

Поэтому:
1. Предпочитать инструменты для автоматической генерации метода equals (Lombok)
2. Предпочитать/использовать immutable объекты - для них смело можно переопределять equals (например, с помощью Lombok аннотации @Value)
3. Переопределяя equals - обязательно сразу после него нужно переопределить hashcode (опять же, используется в коллекциях на основании hash таблиц)
4. Переопределяя equals - убеждаемся, что 2 разных объекта имеют разный вывод метода toString (особенно важно при тестировании)

#dmdev_ликбез
👍33🔥4🤔1
Как люди думают

Обычно книги любят растягивать для большего объема, хотя какую-то действительно ценную идею или главную мысль можно донести многократно быстрее. Этим мне и показалась очень примечательной недавно прочитанная книга “Как люди думают” - невероятное количество интересных мыслей в рамках каждой небольшой главы.

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

Если тебе какие-то из них тоже откликаются, то буду рад увидеть цифры заметок в комментариях.

1️⃣ От мыслительного процесса вы будете получать удовольствие, если за ним следует награда (вкусная еда, компьютерная игра и др.).

2️⃣ Только в наших силах решать, на что потратить такой драгоценный и ограниченный ресурс, как время.

3️⃣ Если ребёнку предложат постоянно бегать по полю с мячом от одних ворот до других, то ему это довольно скоро наскучит. А вот играть в футбол он может часами. Значит, нужно превратить творчество в игру.

4️⃣ Ограничения прекрасно будят фантазию.

5️⃣ Процент творчества в самом творчестве небольшой. Все остальное - терпение, настойчивость, вера в себя. И... независимость от мнения окружающих.

6️⃣ Иногда, зайдя в тупик, вместо того чтобы постараться сосредоточиться, можно наоборот расслабиться (банка с пчелами и мухами).

7️⃣ Не бойтесь делать странные вещи. Это всего лишь действия, не предусмотренные системой. Это прекрасная возможность увидеть, попробовать и почувствовать что-то новое.

8️⃣ Шкала ценностей практически всего, что вас окружает, находится в вашей голове. И эта шкала не может быть абсолютной. Только относительной. Корпорации тратят миллионы долларов, чтобы в крошечном кусочке вашего мозга немножко поменять отношение к их товару или услуге. А вы можете поменять отношение к целому миру самостоятельно. Совершенно бесплатно. И этим изменить свою жизнь.

#dmdev_top_books
👍47🔥87
Избегать логики в конструкторах

📌 Самый простой и часто встречаемый конструктор просто инициализирует поля, присваивая им значения из соответствующих параметров. Если же это не так, и конструктор содержит более сложную логику, то это ведет ко многим неприятным моментам и даже проблемам:

1️⃣ Сложнее читается код, потому что простое создание объекта требует более глубокого анализа, чтобы понять, в каком состоянии этот объект окажется сразу после инициализации.

2️⃣ В методах может наблюдаться частично проинициализированное состояние объекта, если такие методы вызываются из конструктора. Более того, появляются дополнительные проблемы, если такие методы еще и переиспользуются или переопределяются в наследниках.

3️⃣ Сложнее тестировать такой класс, особенно если он используется и в других классах, которые тоже необходимо тестировать. Т.е. сложность тестирования всего приложения может неявно расти как снежный ком. В то время как простые конструкторы дают возможность разработчикам использовать объекты реальных классов, а не прибегать к таким инструментам как Mockito, которые в свою очередь накладывают свои ограничения (например, класс не должен быть final).

4️⃣ В случае использования DI frameworks, контекст приложения может не подняться в принципе, если в конструкторе держать еще более сложную логику. Например, запрос по сети в другой сервис, добавив сюда как обычно плохо настроенные для клиентов timeouts, retry механизмы и т.д. (было очень много инцидентов на эту тему).

Поэтому:
⚙️ Предпочитать простейшие конструкторы без логики внутри них
⚙️ Логику выносить в другие классы, билдеры или, в случае использования DI frameworks (Spring, Guice, etc) - в конфигурационные классы, представляя результат в виде отдельных бинов.
⚙️ Если есть сторонние запросы (как в пункте 4) - можно добавить ленивую инициализацию, чтобы избежать проблем с поднятием контекста

#dmdev_ликбез
👍37🔥4🙏1
2.5 года назад в разгар Covid вышли первые видео на YouTube канале DMdev - Java для начинающих Level 1

👀 Они создавались не для широкого пользования. Все, чего я хотел на тот момент как любой ленивый программист - это автоматизировать каким-то образом начитку и демонстрацию материала, когда преподавал в IT academy. Ибо приходилось из года в год повторять одно и то же. Поэтому качество звука, видео и т.д. оставляли желать лучшего: все создавалось из подручных средств (или, как говорят, на коленке).

📝План был прост: записываю видео, заливаю на YouTube и отправляю своих студентов смотреть материал перед лекцией. На самой же лекции я просто отвечаю на вопросы, решаем другие задачи, разбираем более сложные моменты и нюансы.

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

💻 Так со временем эти видео разлетелись по YouTube и начали набирать просмотры уже далеко за пределами учеников IT academy.

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

Начиная с сегодняшнего дня я буду выпускать новое видео раз в сутки, и в течение месяца выйдет обновленная версия Java для начинающих Level 1 под новым названием Computer Science.

Приятного просмотра📽
🔥108👍306
📚Чтение исходного кода
Часто вижу в комментариях, что довольно сложно понимать исходный код Java Core, фреймворков или инструментов вроде Maven и Gradle, когда я показываю его в своих видео.

Так и должно быть! И как минимум потому, что вы впервые видите чужой код и нужно больше времени, чтобы проанализировать новую информацию.

А демонстрирую я исходный код по несколько другим более важным причинам:

1️⃣ Как нужно подходить к изучению любого фреймворка или инструмента, с которым ты сталкиваешься впервые, чтобы понимать, что происходит

2️⃣ Как решать проблемы или задачи, которые отходят от базовых понятий или стандартных/шаблонных решений

3️⃣ Улучшаются code review навыки и чтение кода в принципе

4️⃣ Ты видишь интересные решения и архитектурные подходы, которые в последующем можешь переиспользовать у себя или даже комбинировать! Ибо эти решения действительно проверены на практике
👍70🔥6🙏21
Презентация финального веб-проекта по окончании 2-ой ступени менторства DMdev
С такими навыками каждого будут рады видеть в достойной компании на позиции сильного Junior Java Developer.

💻 В проекте использовались:
- Apache Maven для автоматизированной сборки
- JUnit 5 для покрытия кода unit и integration тестами
- Hibernate как основной ORM framework
- Liquibase для миграции SQL скриптов
- Spring Boot с Embedded Tomcat
- Множество различных Spring Starters (data-jpa, web, security, validation, thymeleaf, test, etc)

Более детальное описание можно найти в техническом задании

Смотри видео, задавай вопросы по проекту в комментариях.

А для тех, кто хочет стать участником менторства 2 ступени
👉 ссылка для записи с подробной информацией.

- старт 30 января - осталось 1 место 0 мест (ко мне)
- старт 6 февраля - осталось 4 2 места (к ментору Илье)

P.S. Дай знать, если видео было интересным.
Тогда я опубликую полную версию защиты всех проектов со второй ступени менторства последнего потока.
🔥33👍141👎1🤔1
This media is not supported in your browser
VIEW IN TELEGRAM
🔐 Lead Level on YouTube

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

Со стороны автора и в целом бизнеса - это также было бы удобно, желательно на своей собственной платформе 😁

Eсли бы не тысячи НО… которые усложняют такую реализацию. А после начала военных событий и вовсе почти “поставили на коленки”.

Именно поэтому мне и пришлось предоставлять доступ для граждан РФ на еще одной площадке GetCourse, а теперь и поддерживать ее.

Но как показывает практика, хоть официально на YouTube и Udemy жителям РФ запрещено совершать покупки - вы все-равно как-то это делаете 😅

💥 Поэтому сейчас будет, наверное, долгожданная новость и изменения в доступах к курсам DMdev на YouTube.

Добавился новый четвертый уровень спонсорства Lead, по которому открыт доступ ко всем курсам DMdev.

За 14,99$/месяц открывается доступ к Java Core, SQL, JDBC, HTTP.Servlets, Maven, JUnit 5, Groovy, Gradle, Hibernate, Spring, Bash и…к последующим курсам!

Приятного просмотра 🍿
👍39❤‍🔥14🔥10😁2
This media is not supported in your browser
VIEW IN TELEGRAM
Я получаю сотни комментариев в виде обратной связи от вас по моим курсам, и понял одну вещь: один курс отличается от всех остальных.

И это JUnit 5.

В нем нет большого практического занятия, где я как обычно объединяю и закрепляю предыдущий пройденный материал.

Дабы предотвратить и избежать ситуаций с видео, я подготовил большой практический урок.

Ведь это оказалось действительно существенным в понимании материала.
🔥40👍8🏆5🙏1
Практика JUnit 5

📊 Немного статистики
:
- продолжительность видео 1:03:39
- затрачено времени на создание ~8 часов
- доступно на всех платформах

+ новая домашка для самостоятельного закрепления

👀 Смотреть на YouTube в свободном доступе
🔥83👍29🎉7❤‍🔥1🏆1
Scheduled Job

Как-то раз мне нужно было реализовать периодический процесс, который запускался бы раз в 5-10 минут и выполнял определенную работу:
- анализ/изменения данных в базе
- отправка сообщений в Kafka
- отправка пуш уведомлений затронутым пользователям
- многое другое

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

Первое, что приходит на ум - это конечно Scheduled Job в одном потоке. Но in-memory вариант не подходил, потому что было несколько instances приложения. А значит на каждом запустилась бы такая Job.

Поэтому нужно прибегать к централизации запуска через базу данных. Здесь напрашивается опять же готовое решение Quartz scheduler. Но хотелось чего-то более легковесного и менее затратного в конфигурации, избегая кучи новых таблиц в базе данных только для поддержки Quartz.

И тут на помощь пришли Named Locks в MySQL (в PostgreSQL они называются Advisory Locks).

С их помощью в своей Scheduled Job просто необходимо выполнить предварительно SQL запрос вида:
SELECT GET_LOCK(‘anyUniqueNameOfLock’, 5);
Если запрос вернул 1, значит Lock получен и можно выполнять работу, иначе - другой instance твоего сервиса уже ее выполняет и можно ничего не делать.
Главное в конце не забыть отпустить Lock:
SELECT RELEASE_LOCK(‘anyUniqueNameOfLock’);

P.S. В Advisory Lock можно и этого не делать - после окончания транзакции lock будет автоматически снят, что действительно облегчает работу и не нужно обрабатывать дополнительно исключения в случае проблем с RELEASE_LOCK.

P.P.S. На картинке представлен пример использования такого подхода на чистом Java Core
👍63🔥193
Февраль месяц хоть и маленький, но тянулся для меня очень долго. А все потому, что он был насыщен большим количеством событий, происходящих в моей жизни: подготовка к отцовству, покупка квартиры в Варшаве, Google layoffs, планирование отпуска и переезда, тренировки к соревнованиям по бегу на 5 км и т.д.

Тем не менее, все это время я продолжал тщательную подготовку следующего курса. Я старался меньше отвлекаться на социальные сети, которые забирают не только кучу времени, сколько очень много твоего внимания - а все это дорогой и ограниченный человеческий ресурс.

Я прочел 2 книги, штудировал официальную документацию и исследовал свои предыдущие проекты в поисках практического применения и полезности тех или иных фич изучаемого инструмента.

Могу сказать, что почему-то до сих пор ни один источник не может предоставить полной картины происходящего. Уже в который раз убеждаюсь, что невозможно систематизировать знания и передать их в полном объеме используя лишь один источник информации: книги, видео, исходный код или даже примеры в реальных проектах.

И все же, на этой неделе я планирую выпустить первое видео на своем YouTube канале. Это будет новый курс, в котором я как обычно попытаюсь изложить материал, опираясь лишь на основы, которые у вас уже есть после просмотра предыдущих курсов DMdev.

Так что следи за новостями!
👍100🔥41❤‍🔥7🎉32🏆1
Релиз нового курса - первое видео уже на YouTube!

PS. Будет доступен по подписке Lead и со временем на других платформах (Udemy, GetCourse).
🔥108👍14🤩3💋3🏆2❤‍🔥11🎉1
🗄 DMdev talks: перезагрузка

С ужасом заметил, что последний пост я написал тут больше месяца назад.

Как так вышло?

На самом деле все просто:
Был фокус и четкий план на телеграм = были посты
Нет фокуса = нет постов

Хочу вдохнуть новую жизнь сюда, ибо формат телеграма мне очень нравится!

Для этого нужна ваша помощь🙏

Буду очень благодарен, если накидаете в комменты, какие посты/рубрики/активности и в каком формате хотелось бы тут наблюдать.
Это может быть что-то разовое или на постоянной основе, что-то вроде традиции (например, каждые первые лунные сутки скидывать статистику с YouTube 😅)

На основании этого составлю себе план к действию и буду радовать вас почаще, чем раз в месяц😁
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥54👍8🫡4❤‍🔥1👨‍💻1
Часто мне задают вопросы такого плана - когда не понятно как реализовать или упростить уже существующий функционал.

Как раз реальная задача, которая требует действительно гибкого решения, ибо время показало, что этот код меняется часто, а значит требует рефакторинга.

Как можно было бы изменить код, чтобы автоматически при добавлении нового обработчика для определенного типа - не требовалось менять основную логику с добавлением еще одного if-else?

Можно словами в комментариях, можно прям скринами с кодом.

Если наберем несколько интересных вариантов, то я напишу свои мысли по этому поводу 😎
#dmdev_qa
👍25❤‍🔥4🔥3
Общими усилиями в комментариях мы пришли к гибкому решению!
Его я отобразил на картинке.

Единственное что я изменил - это тип процесса, сделав его Class<T> вместо enum для демонстрации альтернативного подхода.
В этом есть свои плюсы и минусы, как и в любом решении.

Плюсы:
- не нужно заводить перечисления (enum) и делать соответствия между ним и процессом
- не нужно передавать в ProcessService дополнительно этот enum, когда мы хотим получить обработчик процесса (или добавлять доп поле в каждый процесс)
- во время выполнения мы не получим ошибки, что получили из Map не тот обработчик (класс процесса сам же является и ключом)

Минусы:
- без enum не виден весь список возможных процессов
- не напишешь хороший тест, что на каждый процесс есть свой обработчик
- пришлось в ProcessService сделать явное приведение типов, потому что метод getClass в классе Object возвращает Class<?>

Что бы ты выбрал все-таки: enum vs Class<T>?
#dmdev_qa
🔥16👍91🤔1
Backwards compatibility

При создании любого открытого API, будь то HTTP, gRPC endpoint, public метод в Java - необходимо помнить про обратную совместимость.

А суть его в следующем:
код существующих клиентов открытого API не должен сломаться при обновлении этого API. Старые клиенты должны уметь работать с новой версией API.

К сожалении, не всегда очевидно - обратно совместимо ли какое-то изменении в API или нет.

Но есть несколько правил, которых можно придерживаться для этого:

1. Новые компоненты (поля, методы, перечисления) - можно добавлять без проблем. Главное на стороне клиентов не делать строгую валидацию (например, фейлить ответ от сервера, если пришло новое поле)

2. Не делать поля обязательными в существующих сообщениях (в новых сообщениях тоже стараться делать поля optional)

3. Не удалять или переименовать уже существующие компоненты (переименование - это аналог “удалить + добавить поле”). Более того, придется продолжать заполнять старые поля, даже если они стали избыточными (redundant)

4. Не менять типы существующих полей

5. Осторожно работать с enum: если используется только в запросах - то добавить новое значение безболезненно, чего нельзя сказать про новые значения в ответах от сервера, где уже нужно писать клиент соответствующим образом

Вывод
Не так-то просто писать открытый API, особенно если им пользуется большое количество клиентов.
Да и становится понятно, почему в Java Core столько старых классов и методов 🙂
👍34🔥6❤‍🔥3💩1
Сode review н-нада?

Многие поддержали данное предложение, что ж, давайте попробуем реализовать его!

Кто хочет, чтобы я провел code review вашего кода - присылайте ссылку на github в комменты под этим постом.
Я рандомно выберу один проект и в следующем посте опубликаю краткое резюме по коду с ссылкой на код с моими комментариями

Условия участия:
- Проект опубликован на github
- Весь код в виде одного пул реквеста или коммита
- Чем больше кода - тем больше добавить описания о нем в README файле (чтобы я понимал о чем проект)
- Не удалять пул реквест или коммит после code review
- Согласие на то, что ваш разбор попадет в этот канал
- Ссылки жду до 6 мая включительно

P.S. Если зайдет рубрика, то можем ввести ее на постоянной основе, например, каждое первое число
#dmdev_code_review
👍47🔥16👏2❤‍🔥1
15.000 подписчиков на YouTube!
Это в 1,5 раза больше людей, чем в городе, котором я вырос.

И всех этих людей связывает один общий интерес - Java.

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

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

За это время:
- уже более 1.000.000 просмотров
- 666 видео
- 12 курсов (пройдя которые - действительно можно стать разработчиком)

Благодарю каждого за доверие и активное участие!
Без вас - ничего этого не было бы🙌🏻

P.S. 🔔 Напоминаю, что сегодня последний день, как я жду ваши ссылки на гитхаб для code review (подробнее в посте выше)
🔥82👍16🎉8❤‍🔥2😈1
#dmdev_code_review
Как и обещал, выбрал одного из участников, чтобы провести code review.

Хотелось бы отметить общие частовстречаемые ошибки, которые в то же самое время очень важны:

1. Не следует изменять статические поля в нестатическом контексте. Чаще всего это приводит к ошибкам в многопоточности или попросту неверно работает код.

2. Четко разбивать приложение на слои и следовать строгой коммуникации между ними. Например, избегая выполнения sql запросов напрямую из сервлетов. Иначе это приведет к спаггети коду и тесной взаимосвязи всего со всеми, что в принципе делает возможность рефакторинга крайне затруднительной.

3. Не стоит писать код на исключениях - клиентский код потом становится громоздким с кучей try/catch блоков. Пробрасывать исключения следует тогда, когда действительно произошла ИСКЛЮЧИТЕЛЬНАЯ ситуация, которую никак не избежать. Например, гораздо приятнее возвращать true/false в методе delete вместо пробрасывания исключения, если такой сущности не оказалось по переданному id.

4. Связанно с предыдущим пунктом: не нужно проглатывать исключение, пробрасывая свое кастомное - иначе теряется stacktrace рутовой ошибки и будет очень сложно понять что произошло. Если нужно обернуть одно исключение в другое - просто передавайте его как параметр в конструктор: new DatabaseException(sqlException)

5. Разумно подходить к использованию Optional & Streams. Какой-то код лучше писать в функциональном стиле, какой-то в императивном, какой-то в комбинации двух предыдущих. Но в любом случае стоит граммотно использовать все подходы. Возьмем простой случай: возвращать Optional из метода, который может вернуть null. И, наоборот, если метод всегда возвращает объект - то не стоит оборачивать его в Optional, ибо это доставляет неудобства клиенту.

6. Давать хорошие имена переменным, методам, классам - всему в коде. Иначе очень сильно усложняется чтение кода, на которое программист тратит большую часть своего рабочего времени. Особенно избегать таких имен, которые подразумевают только ЧТЕНИЕ, а по факту там происходит изменения состояния объектов - т.е. ЗАПИСЬ. Например, findProduct(productId) - а внутри изменение состояния объекта Product.

P.S. Весь список комментариев по code review можно найти в пул реквесте по ссылке

P.P.S. Если есть вопросы по коду/моим замечаниям, что я оставил - то можете задавать их прям здесь под постом в комментариях
🔥49👍11❤‍🔥4