Тру-Джава
137 subscribers
31 photos
79 links
блог начинающего Java-программиста

Чат: https://t.me/trujavachat
Download Telegram
Всем привет!

Позавчера была борьба с забавным багом, такой эпик фейл с моей стороны. Пришлось мне работать с сущностью, у которой было поле-объект, помеченное @EmbeddedId, а у самого этого поля-объекта была аннотация @Embeddable.

Я до этого знала, что @Embeddable в принципе означает вложенный и, что все перечисленные поля вложенного класса, будут в виде этого класса присутствовать в классе верхнего уровня.

Что я не до конца понимала — это почему использовался именно @EmbeddedId, а не просто @Embedded, и по лени не перепроверив, решила, что это примерно одно и то же, а значит я спокойно могу добавить два нужных мне поля из таблицы во вложенный класс и по данным из этого вложенного класса найти потом запись в таблице.

В общем, ждал меня сюрприз. В базе данных запись я видела, но при дебаге с теми же данными запись в таблице мне не выдавалась. Что я только не перепробовала, и меняла запросы со сгенерированного, на кастомный на JHQL, потом на native SQL. Игралась с equals и hashCode. Через пару часов спросила у одного из старших коллег, он говорит, может ты не в той базе смотришь, на другом стенде? Но нет, база данных была та же. Профиль спринга был нужный.

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

Потом он попросил показать тот @Embeddable класс и увидел, что я туда добавила два поля. В этом, говорит, и была моя ошибка. Так я узнала, что @EmbeddedId означает составной первичный ключ в таблице и нельзя просто так бездумно добавлять дополнительные колонки к этому ключу.

Вот такой вот эпик фейл, но на ошибках учимся)))
🔥7👍6
Всем привет!

Вчера у меня начался отпуск. 🥳 Много нацелилась успеть сделать, но без жестких требований к себе, все-таки нужно и отдыхать))

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

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

Я думаю, что не пройду и первый этап с решением задач за ограниченное время, но собираюсь попробовать.

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

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

Но появился интерес к питону, решила с ним познакомиться поближе. В первую мою попытку лет ~10 назад, он меня очень быстро победил. Хочется взять реванш, плюс многие алгоритмы объясняют с псевдокодом, либо на питон, и возможно более хорошее понимание питона мне поможет и с алгоритмами.
🔥7👍6
Всем привет!)

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

Сначала даже чуть было не записалась на курсы по алгоритмам за >80 тыс 😱 Но меня вовремя отговорили)) Поэтому пошла на степик и нашла там java - тренажёр. Там от совсем простых задач начинается, думаю раз уж повторять надо с самого начала))

Ещё ездили тут в Москву на выходных и в поезде слушала Clean Code, так сказать, познакомиться с классикой)

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

Ещё продолжаю читать про паттерны, уже с января никак не дочитаю книгу Head First, последний паттерн, про который читала дался особенно тяжело - паттерн Команда/Command. Сложность для меня понять отличие от Стратегии и применение на практике. Думаю ещё поизучаю эти моменты)
🔥7👍2
Всем привет!

С понедельника участвую в небольшом челлендже 💪 на несколько человек. У меня две цели на месяц - дочитать "Чистый код" и по максимуму дорешать тренажёр из предыдущего поста.

Тренажер нравится, там есть задачки на 2 / 3 звезды и над ними приходится подумать. Одну так решила, зная, что неправильно, но после решения открывается доступ к решениям остальных студентов и увидела, как правильно сделать)

Потом попробовала повторить по памяти и всяко-разно потренироваться, понравилось) Там часто в решениях методы используют нестандартные, пометила себе несколько таких, чтобы знать)
🔥10
Всем привет!

Я продолжаю участие в челлендже, осталось 2 недели. Заодно решила побить свой рекорд непрерывной серии решения задач на степике. Там рекорд у меня 20 дней, сейчас пока 13, но проблема в том, что я дошла до более сложных задач, поэтому не знаю получится или нет.

По этому поводу в пятницу получилось довольно забавно. Часов в 8 вечера думаю, что-то я сегодня устала, дай-ка решу одну задачку, чисто для непрерывной серии. А задача под 2мя звездами на списки / массивы. В общем решала ее 3 часа, но все-таки решила)) Причем процент решения у нее был высокий и ни одной подсказки / вопроса в комментариях.

Но это не самый смешной случай с задачами, поэтому расскажу про другую задачу.

Решаю вчера задачи, и попалась мне задача — дан список с числами, расположенными по возрастанию, например [1, 2, 3] и нужно отдать на выходе сумму пропущенных чисел, в данном случае 2 и 4, т. е. вернуть 6. Осложнялась она тем, что на вход приходили числа класса Number и их сначала нужно было перевести в Integer.

Не то чтобы я долго над ней сидела, но мое решение, с ошибочно-ненужными 2мя условиями заняло 22 строки (со всем форматом и скобками), захожу в решения других людей. И что я вижу! Эта задача, оказывается, решается в 2 строки, чисто с математической стороны. 😁 Да еще и стримами) Там, конечно, гении стримов сидят, почти все задачи кто-нибудь решает используя только стримы.

Но еще активно пользуются методами из стандартной библиотеки. Например, я до этого не знала про метод Collections.reverse() — развернуть порядок списка на обратный, и про метод set() в интерфейсе List, он заменяет по индексу элемент на другой. Я делала это в несколько операций, сначала удалить старое значение по индексу из копии листа (чтобы не было ConcurrentModificationException), а потом добавить новое значение по индексу. А есть специальный метод🙈
🔥5👍41
Всем привет!

Продолжаю активно прокачивать алгоритмы. В задачнике дошла до 47%. Осталось несколько задач до 3х-звездных на списки. Лучшую свою серию на степике не улучшила, может быть как-нибудь в другой раз:)

Дочитала «Чистый код», книжка очень понравилась. Открыла для себя новый способ чтения — читать под аудиокнигу. Следующая моя цель на прочтение — «Гроккаем алгоритмы», нашла последнее издание от 2024 года, купила ее еще в варианте аудиокниги и начала читать.

На работе практически закончили переход на Domain Driven Design, перевели все микросервисы. Теперь у меня задача написать архюнит тест проверку, на то, чтобы этот дизайн не нарушался. Короткое видео о том, что такое DDD в общих чертах тут. Если кто-то еще не работал с архюнитами, то вот статьи с примерами на baeldung и хабре.
🔥81👏1
Всем привет!

Сегодня напишу про patch, о котором нам рассказывали ещё в Практикуме, но я никогда не пользовалась им до пары недель назад. Оказалось, что это очень удобная вещь.

У меня была ситуация, что не получалось сгенерировать правильный для меня объект через open api генератор. Я обратилась к техлиду, он сказал, что попробует и вернется.

Через какое-то время, он показал, как сделал и я попросила его прислать мне его вариант. Так, он научил меня использовать патч. Он создал его в идее и отправил мне в мессенджере, я выбрала в меню apply patch и у меня применились все изменения, которые я сразу закоммитила и отправила.

После этого, стала использовать этот способ в качестве быстрого бэкапа, потому что в merge реквесты обычно отправляю 1 коммит.

И эта привычка не коммитить и не работать в отдельной ветке сразу меня в пятницу чуть жестко не наказала😅 У меня была относительно большая задача на рефакторинг, я его делала дня два, у меня было 87 изменений и перед отправкой, я как обычно нажала обновить dev, чтобы из последней версии создать ветку, закоммитить и отправить.

Но обновления не подтянулись. Конфликт в измененном файле🙈 Мне вышло сообщение, что все мои изменения были положены на полку (shelve). Про нее я только знала, что один из преподавателей на стажировке потерял один раз все свои изменения, положив на полку свои изменения и как-то неправильно их пытаясь достать, удалил.

Седея по волосу в секунду, я открыла этот shelve, сначала выбрала silently unshelve, ничего не произошло)) В итоге выделила и нажала unshelve, мысленно формулируя, как я на дейлике в понедельник буду рассказывать, что все свои изменения эпично удалила.

Но всё досталось с полки успешно, закоммитила, отправила на проверку и потом несколько раз проверила, точно ли всё досталось правильно) несколько раз прогнав всевозможные тесты) Даже сегодня утром потратила часа полтора всё перепроверяя))

А здесь есть ещё классная статья про фишки идеи, здесь есть и про shelve и patch.
👍15🔥42👏1😁1
Всем привет!

На прошлой неделе закончился мой небольшой челлендж. За него прочитала книжку и дошла до 60 процентов в задачнике.

Появилась привычка понемногу читать по утрам, Гроккаем алгоритмы идет относительно бодро. Там есть интересные упражнения на закрепление. Одно из понравившихся - написать рекурсивный метод нахождения суммы списка.

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

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

Настолько я соскучилась по активному движению тасок, что даже в прошлые выходные заводила себе в пет-проекте issue и закрывала их пулл-реквестами) Подправила свои github actions, подключила еще одну ИИ проверку, которая ищет различные уязвимости.

Так, у меня не пропустился последний мой ПР, нашлась уязвимость в html (игралась с фронтом через thymeleaf и ИИ). Но возвращение html также и мои постман тесты поломало, поэтому, наверное, попробую пощупать другие инструменты для фронта, если не получится с html.

А в эти выходные делала игру - кликер в unity 🙈 Ребенок ждет обещанной игры уже 3й год 😁
🔥132😁2
Всем привет!

Вчера читала один дайджест с последними новостями в мире IT и интересными новыми статьями по Java.

Привлекло название одной статьи - Паттерны применения многопоточности на коммерческом проекте. Решила тоже ссылку на нее здесь оставить, потому что очень крутая статья)

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

У меня сохранено с десяток задач с разных отборов на стажировку в Яндекс и Тинькофф, в которых я участвовала года полтора-два назад. Собираюсь вернуться к ним и решить, как закончу книжку, потому что тогда у меня не было даже идей как их решать.
🔥12👍2
Всем привет!

Вчера дочитала "Гроккаем алгоритмы", появилось понимание некоторых алгоритмов и появилось понимание, что нужно ещё много много тренировок))

Поэтому на днях было несколько решений, во-первых, заменить прохождение задачника на решение задач на leetcode. Потому что 3х звездные задачи оказались скорее муторные на выведение ответа в определенном формате, чем сложные и хитрые на логику. В общем, проще говоря пока стало скучно их решать, где-то на 60 с небольшим процентах решила пока остановиться. Возможно потом вернусь, чтобы добить.

Во-вторых, записалась на очередной поток тренировок по алгоритмам в Яндексе. Набор всё ещё открыт, начало 24 октября.

Следующую книжку выбрала "Java Concurrency and Parallelism" (Jay Wang), издание тоже 24 года. Буду углубляться в тему многопоточности. В первой же главе написано, что есть разница между выполнением задач параллельно и в режиме многопоточности. Буду узнавать какая🤓

Пока идея с чтением книг последовательно для меня работает, а то перескакивание с книги на книгу часто отбивало желание читать вообще)) Ещё достаточно весело читать одновременно с аудиокнигой, но книги, где много кода, конечно, не очень подходят для аудиокниг, даже удивительно, что была версия аудиокниги для алгоритмов, в конце концов стало неудобно ее слушать и постоянно ставить на паузу, чтобы разобраться в коде и схемах, в итоге перестала)
👍8🔥4
Всем привет!

Решила написать небольшой отзыв на книжку про многопоточность из предыдущего поста.

Ощущение как будто читаешь какую-то рекламную брошюру по джаве😅 К концу первой главы, фразы в стиле, "но ничего, джава и об этом позаботилась" начали вызывать отторжение))) Это всё ещё совмещается с примерами танцев и получается, что "потоки движутся в ритме танго/вальса на переполненном облачном танцполе".

В итоге глаза стали стараться пропустить такие сравнения и "рекламу" джавы и осталось не так много и читать, только примеры кода. Так что, наверное, лучше посмотрю примеры кода в приложенном к книге проекте на гитхабе и переключусь на что-то другое. Может дальше стиль написания и меняется, но пока не зашёл совсем)
😁8🔥1
Всем привет!

С прошлой недели меня поставили помогать разгрузить техлида и одного сеньора и теперь я gateway по багам. Приходится разбираться, где проблема на бэке или фронте (иногда это не очевидно для меня) и переназначать, или брать в работу.

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

А из таких задач у меня были задачи на добавление второго профиля в микросервисы, как подготовка к миграции на другую базу данных. Один микросервис только успела перевести) Но надо сказать, что это достаточно монотонное дело. В этом плане поиск и исправление багов поинтереснее, но есть какое-то напряжение с ними)
🔥16👍3
Всем привет!

Сегодня занималась интересной проблемой / багом.

У нас на обучении об этом не говорили, например, но есть ограничения в запросах в базу данных, которые содержат конструкцию where что-то in (варианты).

У нас на проекте с самого начала подход разбивать такие запросы на партиции (дробить большой запрос в базу данных на несколько мелких).

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

Пришёл запрос, который попадал под это ограничение и выдавал сервис 500. Сегодня разделила его на партиции и покажу, как это может выглядеть в коде.

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

Например, мы ищем игрушки, id фирм которых находятся в условии in, тогда запрос в базу данных выглядит так:

Select t.* from toys t 
where t.brand_id >= :minId
and t.brand_id <= :maxId
and t.brand_id in (:ids)


А в коде, под синтаксис 21 джавы:

Collections.sort(brandIds);
ListUtils.partition(brandIds, maxSize).stream()
.map(partition -> repository.findByBrandIds(partition, partition.getFirst(), partition.getLast()))
.toList();


Переменная maxSize это задаваемое значение максимального размера партиции, оно не должно быть слишком большим, но и слишком маленький размер будет слишком долго обрабатываться, если список брендов будет доходить под несколько десятков тысяч.
👍10🔥5
Всем привет!

Сегодня попался пост про оценку личной производительности и о ее волнообразности. Немного навеяло о личной мотивации и захотелось поделиться одной классной статьёй и идеей в ней.

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

В статье противопоставляется поставление и достижение цели, - а зачастую расстройство от не достижения ее - и субъективная оценка по своим критериям.

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

Цитата из статьи - "смартировать свою жизнь — самый эффективный способ, чтобы перестать улыбаться".

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

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

Получается что нет стресса, что нужно что-то достичь, но есть критерий "узнала что-то новое в программировании", который постоянно поддерживает и подталкивает изучать новое и развиваться.
🔥12👍6
Всем привет!

В понедельник у меня начался отпуск. Сегодня утром мне уже стало скучновато без работы 😁

До отпуска у меня было несколько параллельных активностей. Примерно в одно время (2 месяца назад) я записалась на тренировку по алгоритмам и интенсив по джаве.

Рассчитывала, что интенсив закончится до тренировок, но оказалось, что они начались практически день в день и вебинары стали проходить в одно время и там и там с домашними заданиями.

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

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

Зато проверила в работе ИИ в качестве писателя юнит тестов (правда локальную слабоватую модель) и он с задачей не справился. Пришлось за ним искать и исправлять ошибки. 🤷‍♂

Сейчас в планах дочитать книжку Head First по паттернам (осталось меньше половины) и заново начать "кабанчика", потому что до этого половину прослушала чисто в аудио и не очень усвоилось и отложилось, может быть устрою челлендж себе прочитать ее до нового года, чтобы закрыть долги за этот год💪
🔥9
Всем привет!

Сегодня практически дочитала "Head First. Паттерны проектирования" (остался Appendix с кратким описанием нескольких паттернов).

Мне очень тяжело давалась она в начале, после одного паттерна (Команда) даже отложила книгу в очень далекий ящик.

Недавно вспомнила про нее и решила, что буду читать хотя бы по паре страниц в день. Не каждый день я про это вспоминала, но потом мне неожиданно понравилось 🤓

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

Особенно понравилось читать про Шаблонный метод, паттерн Состояния, Прокси и MVC (Model View Controller).

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

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

В общем, рекомендую! 🔥
🔥10👍1
Всем привет!

Сегодня расскажу про забавный случай кривых рук 👍

Связан он с классом ZipInputStream, который используется для чтения и дальнейшей работы с архивами с расширением ".zip".

Код из примера по приложенной ссылке:

try(ZipInputStream zin = new ZipInputStream(new FileInputStream("output.zip"))) {
    ZipEntry entry;
    String name;
            while((entry=zin.getNextEntry())!=null){
// работа с архивом

Тестировала я его работу и всё-то у меня не попадало в цикл с получением nextEntry у класса, всё null да null у меня было.

Думаю, архив-то у меня валидный, открывается, называется красиво "test.zip".

Уже и погуглила и ИИ поспрашивала, какие могут быть причины, что архив с файлом есть, а ZipInputStream его читать не хочет.

Направил в нужную сторону меня ответ ИИ, что валидный zip всегда имеет признак - первые 2 буквы PK - и в байтах, это значение 50 и 4В, а у меня был 55 и дальше другие значения (это я проверяла дебаггером, что у меня возвращает file.getBytes()).

Решила я получить свой файл через эндпоинт и случайно забыла в постмане выбрать отправить и сохранить, и мне пришел ответ в разных не особо читаемых символах в теле ответа. Первые символы были "7z".

Тут я вспомнила как я создавала свой тестовый архив - я добавила файл к архиву, сохранила не глядя в 7z и подумала, что я расширение что-ли не сменю? И вручную поменяла 7z на zip. 🤦‍♀

Он, конечно, у меня отлично открывался и сохранялся в разных системах, только внутри он себя ассоцировал с 7z архивом, а не zip.

Мораль - не надо лениться😅
😁11
Всем привет!

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

Первым делом, написала небольшой сервис (product-service), который использует реактивную NoSQL базу данных (MongoDb).

Пока в нем обычный CRUD стандартных операций. Кому интересно, сделала открытый репозиторий на гитхабе.

Следующим шагом будет добавить второй модуль, это будет order-service, который будет работать с реактивной PostgreSQL.

На эти два шага у меня есть примеры с одного индусского курса. Но мне кажется в этой серии статей на хабре тоже будет много хороших примеров.

Планирую тоже теоретическую часть почитать побольше, потому что индусы объясняют примерно так: "Это не будет работать, потому что нужно подписаться, и если я напишу вот так, то компилятор теперь счастлив, понятно? Двигаемся дальше" 😁

Третим шагом, я запланировала сделать gateway-service, который будет использовать Redis для кэширования сессии и не пропускать неавторизованных пользователей.
🔥11👍3👏1
Всем привет!

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

Где-то осенью со мной поделились ссылкой на бесплатный курс по алгоритмам от Яндекса, я до сих пор его не прошла.

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

Присоединяйтесь, кому тоже интересно, будем вместе потом обсуждать. 🤗

В тему, одной из самых запомнившихся задач, была задача написать рекурсивный алгоритм для проверки не является ли метод модифицирующим, если он помечен @Transactional(readOnly = true) (archunit тест).

Также, понравилось применять паттерны проектирования - стратегия для импорта и экспорта объектов через файлы и шаблонный метод (про него будет потом пост).

На следующий год, хочу "прочувствовать" алгоритмы, наконец, чтобы увидев один я могла сказать: "А, нужно использовать два указателя", или, "Хм, здесь отлично подойдет "разделяй и властвуй!" и суметь правильно применить и решить задачи легкого и среднего уровня с leetcode.

Также, нужно, наконец, дочитать Designing Data-intensive applications (кабанчик).

А у вас какие планы на следующий год?

Всех с Наступающим!
👍6🔥3
Всем привет!

Всех с наступившим Новым годом! 🎄

Пусть все мечты сбываются!🎁

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

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

Поэтому курс не особо рекомендую, но сама постараюсь допройти и перейти потом к книжке Грокаем алгоритмическое собеседование.

Ещё в планах, скорее мечтах, написать что-нибудь по Spring Security с актуализацией на все изменения синтаксиса, на все возможные варианты - базовая, с токеном jwt и AOuth2. И оформить это в какой-то бесплатный курс на степике.

Эта идея у меня давно, я даже пыталась сделать здесь регулярную серию по Spring Security, но здесь не очень формат для этого подходит, легко по темам не перескочить, а хэштеги я никогда не добавляла) Поэтому думаю платформа Stepik для этого идеально подойдёт)
🔥10