Пирамида бегуна
🏃♂️Когда я занялся бегом и получил по неопытности свою первую травму, после которой больше месяца восстанавливался - я начал думать и искать причины, чтобы уменьшить шанс повторить такие, мягко говоря, неприятные ситуации.
📌 К счастью, все оказалось довольно просто и банально - это пренебрежение основами.
Вообще, для достижение успеха в спорте и даже любой другой деятельности/профессии, например, такой как электрик, предприниматель, программист, и т.д. - можно использовать принцип пирамиды.
🗝 Суть ее заключается в том, что без закладывания первого уровня, не следует переходить на второй. Без второго - на третий, и т.д. И уж тем более нельзя пропускать их, перепрыгивая сразу через уровень.
🗝 Следующий важный момент - поддержка уровней, которые мы уже прошли. Ибо все в этом мире идет по пути наименьшего сопротивления и экономии ресурсов. В случае спорта - человек просто будет терять форму: зачем содержать столько дорогостоящих в обслуживании мышц, если мы давненько лежим на диване 😁
Поэтому пирамида бегуна будет выглядеть приблизительно так:
1️⃣ уровень - здоровый образ жизни, хороший сон и еда, нормальный уровень стресса и т.д.
2️⃣ уровень - общая физическая подготовка (ОФП), т.е. делать упражнения для укрепления здоровья и развития наиболее полезных и необходимых в жизни физических качеств, например, выносливость, гибкость, сила и т.д.
3️⃣ уровень - специальная физическая подготовка (СФП), бег
Как можно заметить, бег находится аж на последнем уровне. В моем же случае - я просто пропустил 2 уровень или, другими словами говоря, пренебрег основами для занятия любым видом спорта.
❓Как думаешь, как выглядела бы Пирамида программиста?
🏃♂️Когда я занялся бегом и получил по неопытности свою первую травму, после которой больше месяца восстанавливался - я начал думать и искать причины, чтобы уменьшить шанс повторить такие, мягко говоря, неприятные ситуации.
📌 К счастью, все оказалось довольно просто и банально - это пренебрежение основами.
Вообще, для достижение успеха в спорте и даже любой другой деятельности/профессии, например, такой как электрик, предприниматель, программист, и т.д. - можно использовать принцип пирамиды.
🗝 Суть ее заключается в том, что без закладывания первого уровня, не следует переходить на второй. Без второго - на третий, и т.д. И уж тем более нельзя пропускать их, перепрыгивая сразу через уровень.
🗝 Следующий важный момент - поддержка уровней, которые мы уже прошли. Ибо все в этом мире идет по пути наименьшего сопротивления и экономии ресурсов. В случае спорта - человек просто будет терять форму: зачем содержать столько дорогостоящих в обслуживании мышц, если мы давненько лежим на диване 😁
Поэтому пирамида бегуна будет выглядеть приблизительно так:
1️⃣ уровень - здоровый образ жизни, хороший сон и еда, нормальный уровень стресса и т.д.
2️⃣ уровень - общая физическая подготовка (ОФП), т.е. делать упражнения для укрепления здоровья и развития наиболее полезных и необходимых в жизни физических качеств, например, выносливость, гибкость, сила и т.д.
3️⃣ уровень - специальная физическая подготовка (СФП), бег
Как можно заметить, бег находится аж на последнем уровне. В моем же случае - я просто пропустил 2 уровень или, другими словами говоря, пренебрег основами для занятия любым видом спорта.
❓Как думаешь, как выглядела бы Пирамида программиста?
🔥11👍7🤔4
Java Road Map
Я прекрасно знаю и понимаю, как трудно найти актуальную информацию по Java, а главное в какой последовательности ее изучать.
На просторах интернета - тысячи различных материалов. Причем большая часть из них - откровенно говоря вредна. А как известно, переучиваться в разы сложнее и отнимает колоссально много времени, которое в свою очередь является самым ценным человеческим ресурсом.
Поэтому я создал Java Road Map, в котором не только структурировал и описал последовательность изучения материала, но и ПОЧЕМУ необходимо изучать именно так.
Весь путь займет не мало времени, но этого будет достаточно, чтобы чувствовать себя уверенно на любых позициях: от Junior до Senior. Более опытным специалистам - выявить свои пробелы.
А индекс по курсам можно использовать, чтобы еще больше декомпозировать Java Road Map с точностью до конкретного времени в видео, где я рассказываю ту или иную тему.
Я прекрасно знаю и понимаю, как трудно найти актуальную информацию по Java, а главное в какой последовательности ее изучать.
На просторах интернета - тысячи различных материалов. Причем большая часть из них - откровенно говоря вредна. А как известно, переучиваться в разы сложнее и отнимает колоссально много времени, которое в свою очередь является самым ценным человеческим ресурсом.
Поэтому я создал Java Road Map, в котором не только структурировал и описал последовательность изучения материала, но и ПОЧЕМУ необходимо изучать именно так.
Весь путь займет не мало времени, но этого будет достаточно, чтобы чувствовать себя уверенно на любых позициях: от Junior до Senior. Более опытным специалистам - выявить свои пробелы.
А индекс по курсам можно использовать, чтобы еще больше декомпозировать Java Road Map с точностью до конкретного времени в видео, где я рассказываю ту или иную тему.
👍62🔥16❤3💩3👎1👏1💯1
Структура классов в Java
Нет идеального варианта того, как следует структурировать содержимое классов: его поля, методы, конструкторы, вложенные классы.
❗️Но что действительно важно для разработчиков?
Давайте представим, что вы впервые видите какой-то класс.
Отсюда есть два основных варианта:
- вы начнете его читать с самого начала СВЕРХУ ВНИЗ (как страницу книги)
- сразу перепрыгните в какой-то конкретный метод из другой части кода и можете еще исследовать близлежащие зависимые методы
📌 Поэтому напрашивается здесь общее правило: каждый класс должен иметь какой-то логический порядок и этот порядок легко объяснить, а главное - понять другому разработчику.
👀 Как этот порядок вижу я?
Первое
Отталкиваться от 2-ух основных компонентов объекта любого класса - состояния (поля класса) и API (public/protected методы).
И помнить, что static члены не относятся к объекту класса, они принадлежат непосредственно объекту класса Class, поэтому их лучше перечислять в самом начале:
1. static поля
2. static методы
3. Обычные поля
4. Конструкторы
5. API (public/protected методы)
Второе
Что делать с оставшимися НЕ открытыми методами и вложенными классами?
Тут я вижу 2 варианта:
- перечислить их в самом низу класса (что-то вроде “дополнения” к классу)
- перечислить сразу после метода, от которого они зависят (что-то вроде “примечания” к методу)
Поэтому здесь уже решать разработчику класса, будет это больше чувствоваться как “дополнение” к классу либо как “примечание” к конкретному методу.
#dmdev_ликбез
Нет идеального варианта того, как следует структурировать содержимое классов: его поля, методы, конструкторы, вложенные классы.
❗️Но что действительно важно для разработчиков?
Давайте представим, что вы впервые видите какой-то класс.
Отсюда есть два основных варианта:
- вы начнете его читать с самого начала СВЕРХУ ВНИЗ (как страницу книги)
- сразу перепрыгните в какой-то конкретный метод из другой части кода и можете еще исследовать близлежащие зависимые методы
📌 Поэтому напрашивается здесь общее правило: каждый класс должен иметь какой-то логический порядок и этот порядок легко объяснить, а главное - понять другому разработчику.
👀 Как этот порядок вижу я?
Первое
Отталкиваться от 2-ух основных компонентов объекта любого класса - состояния (поля класса) и API (public/protected методы).
И помнить, что static члены не относятся к объекту класса, они принадлежат непосредственно объекту класса Class, поэтому их лучше перечислять в самом начале:
1. static поля
2. static методы
3. Обычные поля
4. Конструкторы
5. API (public/protected методы)
Второе
Что делать с оставшимися НЕ открытыми методами и вложенными классами?
Тут я вижу 2 варианта:
- перечислить их в самом низу класса (что-то вроде “дополнения” к классу)
- перечислить сразу после метода, от которого они зависят (что-то вроде “примечания” к методу)
Поэтому здесь уже решать разработчику класса, будет это больше чувствоваться как “дополнение” к классу либо как “примечание” к конкретному методу.
#dmdev_ликбез
👍50🔥7👌4
👀 О чем этот канал и кто находится по ту сторону экрана?
Сразу скажу - этот канал не является сухой теорией о Java, потому что, во-первых, это скучно, а во-вторых, есть мои курсы DMdev, где теории с практикой более чем достаточно как для начинающих, так и для Senior разработчиков.
Начать знакомство с Java и DMdev можно с бесплатного курса на YouTube💻
Кто я такой и почему мне можно доверять?
Меня зовут Денис Матвеенко - и в первую очередь я не блогер, не предприниматель, а Software Engineer в Google. (именно поэтому, да простите меня подписчики, контент здесь не по расписанию, а по вдохновению и свободному времени😅)
Еще пару фактов обо мне:
- 10+ лет практического опыта в качестве Java разработчика
- работал в 7 различных компаниях: как аутсорсинговых, так и продуктовых
- 5+ лет преподаю Java: для начинающих и не только
#my_little_story - по этому хештегу рассказываю подробно свою историю с момента зарождения мысли "хочу стать программистом"
🗣 В этом канале я планирую делиться своим опытом, знаниями, идеями, своим видением мира и своими мыслями, которые могут быть интересны разработчикам любого уровня и не только.
Ибо выучить Java по телеграм каналам, давайте будем честны друг с другом,можно невозможно.
Моя суперспособность: умею декомпозировать и структурировать информацию + объяснять сложное человеческим языком
Моя слабость: у меня не очень хорошая память (а информации в программировании много), поэтому я предпочитаю ПОНИМАТЬ, а не ЗАПОМИНАТЬ
🗝 Секрет моего карьерного роста: любовь к программированию и ничего более
👉 Кстати, в этом посте поделился, как росла моя зп с самого начала карьеры
И еще несколько интересных постов для тебя:
1️⃣ Почему я предпочитаю инженерный подход в программировании?
2️⃣ Cдвиги парадигм, которые происходят у изучающих Java
3️⃣ Почему логирование ошибки и сразу ее пробрасывание дальше - является антипаттерном?
4️⃣ Best practices in code review
#dmdev_code_review - ищем ошибки в коде и разбираемся, как их исправить
#dmdev_qa - отвечаю на ваши вопросы
Задать анонимный вопрос можно тут:
https://forms.gle/FLHEHQ7GcSNjmtku5
В качестве подарка - забирай дорожную карту джависта - Java Roadmap с нуля до Senior🎁
Сразу скажу - этот канал не является сухой теорией о Java, потому что, во-первых, это скучно, а во-вторых, есть мои курсы DMdev, где теории с практикой более чем достаточно как для начинающих, так и для Senior разработчиков.
Начать знакомство с Java и DMdev можно с бесплатного курса на YouTube💻
Кто я такой и почему мне можно доверять?
Меня зовут Денис Матвеенко - и в первую очередь я не блогер, не предприниматель, а Software Engineer в Google. (именно поэтому, да простите меня подписчики, контент здесь не по расписанию, а по вдохновению и свободному времени😅)
Еще пару фактов обо мне:
- 10+ лет практического опыта в качестве Java разработчика
- работал в 7 различных компаниях: как аутсорсинговых, так и продуктовых
- 5+ лет преподаю Java: для начинающих и не только
#my_little_story - по этому хештегу рассказываю подробно свою историю с момента зарождения мысли "хочу стать программистом"
🗣 В этом канале я планирую делиться своим опытом, знаниями, идеями, своим видением мира и своими мыслями, которые могут быть интересны разработчикам любого уровня и не только.
Ибо выучить Java по телеграм каналам, давайте будем честны друг с другом,
Моя суперспособность: умею декомпозировать и структурировать информацию + объяснять сложное человеческим языком
Моя слабость: у меня не очень хорошая память (а информации в программировании много), поэтому я предпочитаю ПОНИМАТЬ, а не ЗАПОМИНАТЬ
🗝 Секрет моего карьерного роста:
И еще несколько интересных постов для тебя:
1️⃣ Почему я предпочитаю инженерный подход в программировании?
2️⃣ Cдвиги парадигм, которые происходят у изучающих Java
3️⃣ Почему логирование ошибки и сразу ее пробрасывание дальше - является антипаттерном?
4️⃣ Best practices in code review
#dmdev_code_review - ищем ошибки в коде и разбираемся, как их исправить
#dmdev_qa - отвечаю на ваши вопросы
Задать анонимный вопрос можно тут:
https://forms.gle/FLHEHQ7GcSNjmtku5
В качестве подарка - забирай дорожную карту джависта - Java Roadmap с нуля до Senior🎁
👍48🔥17❤11
Class Clock
С введением нового пакета java.time в Java 8, очень сильно упростилась жизнь разработчиков при работе с датами.
О его плюсах, а также о минусах старых классов дат (которых не следует использовать!), я более подробно рассказываю в закрытом видео Date and Time. Теория. Часть 1, доступ к которому временно открыл для вас🔐
Сейчас же я хотел бы обратить внимание на класс java.time.Clock, который может отобразить текущее время с учетом таймзоны.
Но его не так часто используют на практике, т.к. легко заменить другими классами. Например:
⚙️ у почти всех java.time классов есть метод now() без параметров, который возвращает текущую дату и время
⚙️ класс System может также вернуть вам текущее количество миллисекунд
Но все-таки класс Clock очень примечателен тем, что его удобно использовать при тестировании вашего функционала.
Для этого вы просто храните его объект как поле класса (реже как параметр метода) и используете для получения текущей даты и времени:
Instant.now() -> Instant.now(clock)
LocalDate.now() -> LocalDate.now(clock)
LocalTime.now() -> LocalTime.now(clock)
В таком случае в тестах можно задавать нужную фиксированную дату и время с помощью объекта класса Clock
👇
Clock.fixed(Instant.parse("2022-03-18T17:50:10.00Z"), ZoneOffset.UTC)
Тем самым избавиться от flakiness, коим такие тесты подвержены, если создают объекты дат через вызов функции now() без параметров.
#dmdev_ликбез
С введением нового пакета java.time в Java 8, очень сильно упростилась жизнь разработчиков при работе с датами.
О его плюсах, а также о минусах старых классов дат (которых не следует использовать!), я более подробно рассказываю в закрытом видео Date and Time. Теория. Часть 1, доступ к которому временно открыл для вас🔐
Сейчас же я хотел бы обратить внимание на класс java.time.Clock, который может отобразить текущее время с учетом таймзоны.
Но его не так часто используют на практике, т.к. легко заменить другими классами. Например:
⚙️ у почти всех java.time классов есть метод now() без параметров, который возвращает текущую дату и время
⚙️ класс System может также вернуть вам текущее количество миллисекунд
Но все-таки класс Clock очень примечателен тем, что его удобно использовать при тестировании вашего функционала.
Для этого вы просто храните его объект как поле класса (реже как параметр метода) и используете для получения текущей даты и времени:
Instant.now() -> Instant.now(clock)
LocalDate.now() -> LocalDate.now(clock)
LocalTime.now() -> LocalTime.now(clock)
В таком случае в тестах можно задавать нужную фиксированную дату и время с помощью объекта класса Clock
👇
Clock.fixed(Instant.parse("2022-03-18T17:50:10.00Z"), ZoneOffset.UTC)
Тем самым избавиться от flakiness, коим такие тесты подвержены, если создают объекты дат через вызов функции now() без параметров.
#dmdev_ликбез
👍36👏3❤2
This media is not supported in your browser
VIEW IN TELEGRAM
В каждой шутке есть доля правды, какой вариант тебе больше знаком?) мне 1-ый и 3-ий 😅
1️⃣ Когда на собеседовании жестко проверяют алгоритмы, системный дизайн и уверяют, что у них high load и используются только современные технологии и фреймворки.
А приходишь на работу и фиксишь баги двухлетней давности
2️⃣ Когда джун слегка преувеличил свой опыт работы на собеседовании и ему дали выполнить первую сеньорскую задачу
3️⃣ Когда сказали разбить 20 летний монолит на микросервисы, а ты не знаешь с чего начать
4️⃣ Когда свичнулся в айти сферу, получил первую зп и не знаешь, что с ней делать и не веришь, что это все тебе
Или пиши свой вариант в коммент👇
1️⃣ Когда на собеседовании жестко проверяют алгоритмы, системный дизайн и уверяют, что у них high load и используются только современные технологии и фреймворки.
А приходишь на работу и фиксишь баги двухлетней давности
2️⃣ Когда джун слегка преувеличил свой опыт работы на собеседовании и ему дали выполнить первую сеньорскую задачу
3️⃣ Когда сказали разбить 20 летний монолит на микросервисы, а ты не знаешь с чего начать
4️⃣ Когда свичнулся в айти сферу, получил первую зп и не знаешь, что с ней делать и не веришь, что это все тебе
Или пиши свой вариант в коммент👇
😁39🔥9👍5🥰2👎1🤯1
Как замерить время выполнения?
Казалось бы, замерить время выполнения какого-то метода проще простого:
1. Вызываем один раз
2. Вызываем тестируемый метод и ждем его окончания
3. Вызываем еще раз
Но на самом деле такие математические операции со временем с помощью
Почему?
Все потому, что время от времени срабатывает механизм обновления машинных часов, где работает ваше Java приложение. И это обновление может запуститься в любой момент. А по закону подлости это случится как раз тогда, когда вы будете вызывать тестируемый метод из пункта 2, что приведет к ошибкам в расчетах.
Как тогда замерять?
Есть несколько вариантов, но наиболее предпочтительным для меня является класс Stopwatch из пакета com.google.common.base.
На картинке продемонстрировано, как его просто и удобно использовать.
Практика
Совсем недавно пришлось использовать Stopwatch для того, чтобы отслеживать время выполнения высоконагруженной Scheduled Job, которая считывала пачками (batch) события (events) и отправляла их на обработку. Причем также отслеживалось время выполнение каждой такой пачки. Таким образом, анализируя показатели времени, легко можно было варьировать нагрузку и изменять параметры Job: размер batch, количество потоков выполнения, период запуска Job и т.д.
#dmdev_ликбез
Казалось бы, замерить время выполнения какого-то метода проще простого:
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🔥12❤6😱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
Лаборатория 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_ликбез
Про этот метод написано невероятное количество книг и статей, он является излюбленным вопросом на собеседовании. И конечно же неспроста, ибо переопределить его вручную правильно действительно не простая задача, в которой часто допускают ошибки (одно описание контракта в документации чего стоит!).
Но есть вопрос более интересный: а нужно ли вообще переопределять метод 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
Обычно книги любят растягивать для большего объема, хотя какую-то действительно ценную идею или главную мысль можно донести многократно быстрее. Этим мне и показалась очень примечательной недавно прочитанная книга “Как люди думают” - невероятное количество интересных мыслей в рамках каждой небольшой главы.
Как обычно, я делаю пометки того, что мне понравилось, чтобы чуть что вернуться и возобновить в памяти. Наиболее интересные я опишу ниже, чуть менее - в комментарии к этому посту. Часть пометок будет сложнее понять без контекста книги - это нормально.
Если тебе какие-то из них тоже откликаются, то буду рад увидеть цифры заметок в комментариях.
1️⃣ От мыслительного процесса вы будете получать удовольствие, если за ним следует награда (вкусная еда, компьютерная игра и др.).
2️⃣ Только в наших силах решать, на что потратить такой драгоценный и ограниченный ресурс, как время.
3️⃣ Если ребёнку предложат постоянно бегать по полю с мячом от одних ворот до других, то ему это довольно скоро наскучит. А вот играть в футбол он может часами. Значит, нужно превратить творчество в игру.
4️⃣ Ограничения прекрасно будят фантазию.
5️⃣ Процент творчества в самом творчестве небольшой. Все остальное - терпение, настойчивость, вера в себя. И... независимость от мнения окружающих.
6️⃣ Иногда, зайдя в тупик, вместо того чтобы постараться сосредоточиться, можно наоборот расслабиться (банка с пчелами и мухами).
7️⃣ Не бойтесь делать странные вещи. Это всего лишь действия, не предусмотренные системой. Это прекрасная возможность увидеть, попробовать и почувствовать что-то новое.
8️⃣ Шкала ценностей практически всего, что вас окружает, находится в вашей голове. И эта шкала не может быть абсолютной. Только относительной. Корпорации тратят миллионы долларов, чтобы в крошечном кусочке вашего мозга немножко поменять отношение к их товару или услуге. А вы можете поменять отношение к целому миру самостоятельно. Совершенно бесплатно. И этим изменить свою жизнь.
#dmdev_top_books
👍47🔥8❤7
Избегать логики в конструкторах
📌 Самый простой и часто встречаемый конструктор просто инициализирует поля, присваивая им значения из соответствующих параметров. Если же это не так, и конструктор содержит более сложную логику, то это ведет ко многим неприятным моментам и даже проблемам:
1️⃣ Сложнее читается код, потому что простое создание объекта требует более глубокого анализа, чтобы понять, в каком состоянии этот объект окажется сразу после инициализации.
2️⃣ В методах может наблюдаться частично проинициализированное состояние объекта, если такие методы вызываются из конструктора. Более того, появляются дополнительные проблемы, если такие методы еще и переиспользуются или переопределяются в наследниках.
3️⃣ Сложнее тестировать такой класс, особенно если он используется и в других классах, которые тоже необходимо тестировать. Т.е. сложность тестирования всего приложения может неявно расти как снежный ком. В то время как простые конструкторы дают возможность разработчикам использовать объекты реальных классов, а не прибегать к таким инструментам как Mockito, которые в свою очередь накладывают свои ограничения (например, класс не должен быть final).
4️⃣ В случае использования DI frameworks, контекст приложения может не подняться в принципе, если в конструкторе держать еще более сложную логику. Например, запрос по сети в другой сервис, добавив сюда как обычно плохо настроенные для клиентов timeouts, retry механизмы и т.д. (было очень много инцидентов на эту тему).
Поэтому:
⚙️ Предпочитать простейшие конструкторы без логики внутри них
⚙️ Логику выносить в другие классы, билдеры или, в случае использования DI frameworks (Spring, Guice, etc) - в конфигурационные классы, представляя результат в виде отдельных бинов.
⚙️ Если есть сторонние запросы (как в пункте 4) - можно добавить ленивую инициализацию, чтобы избежать проблем с поднятием контекста
#dmdev_ликбез
📌 Самый простой и часто встречаемый конструктор просто инициализирует поля, присваивая им значения из соответствующих параметров. Если же это не так, и конструктор содержит более сложную логику, то это ведет ко многим неприятным моментам и даже проблемам:
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.
Приятного просмотра📽
👀 Они создавались не для широкого пользования. Все, чего я хотел на тот момент как любой ленивый программист - это автоматизировать каким-то образом начитку и демонстрацию материала, когда преподавал в IT academy. Ибо приходилось из года в год повторять одно и то же. Поэтому качество звука, видео и т.д. оставляли желать лучшего: все создавалось из подручных средств (или, как говорят, на коленке).
📝План был прост: записываю видео, заливаю на YouTube и отправляю своих студентов смотреть материал перед лекцией. На самой же лекции я просто отвечаю на вопросы, решаем другие задачи, разбираем более сложные моменты и нюансы.
И оказалось, что это невероятно мощный концепт, который получил большинство положительных отзывов: видео можно легко поставить на паузу, промотать на интересующий тебя момент или просто пересмотреть тот кусок, который не совсем понял. Более того, через повторение информация запоминается гораздо лучше - сначала дома по видео, затем онлайн со мной.
💻 Так со временем эти видео разлетелись по YouTube и начали набирать просмотры уже далеко за пределами учеников IT academy.
Поэтому я решил переснять этот курс, уделить ему больше времени и подробнее раскрыть материал, ибо он невероятно важен особенно для начинающих ребят, которые ни разу не сталкивались с программированием (пробудить интерес!).
Начиная с сегодняшнего дня я буду выпускать новое видео раз в сутки, и в течение месяца выйдет обновленная версия Java для начинающих Level 1 под новым названием Computer Science.
Приятного просмотра📽
🔥108👍30❤6
📚Чтение исходного кода
Часто вижу в комментариях, что довольно сложно понимать исходный код Java Core, фреймворков или инструментов вроде Maven и Gradle, когда я показываю его в своих видео.
Так и должно быть! И как минимум потому, что вы впервые видите чужой код и нужно больше времени, чтобы проанализировать новую информацию.
А демонстрирую я исходный код по несколько другим более важным причинам:
1️⃣ Как нужно подходить к изучению любого фреймворка или инструмента, с которым ты сталкиваешься впервые, чтобы понимать, что происходит
2️⃣ Как решать проблемы или задачи, которые отходят от базовых понятий или стандартных/шаблонных решений
3️⃣ Улучшаются code review навыки и чтение кода в принципе
4️⃣ Ты видишь интересные решения и архитектурные подходы, которые в последующем можешь переиспользовать у себя или даже комбинировать! Ибо эти решения действительно проверены на практике
Часто вижу в комментариях, что довольно сложно понимать исходный код Java Core, фреймворков или инструментов вроде Maven и Gradle, когда я показываю его в своих видео.
Так и должно быть! И как минимум потому, что вы впервые видите чужой код и нужно больше времени, чтобы проанализировать новую информацию.
А демонстрирую я исходный код по несколько другим более важным причинам:
1️⃣ Как нужно подходить к изучению любого фреймворка или инструмента, с которым ты сталкиваешься впервые, чтобы понимать, что происходит
2️⃣ Как решать проблемы или задачи, которые отходят от базовых понятий или стандартных/шаблонных решений
3️⃣ Улучшаются code review навыки и чтение кода в принципе
4️⃣ Ты видишь интересные решения и архитектурные подходы, которые в последующем можешь переиспользовать у себя или даже комбинировать! Ибо эти решения действительно проверены на практике
👍70🔥6🙏2❤1
Презентация финального веб-проекта по окончании 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. Дай знать, если видео было интересным.
Тогда я опубликую полную версию защиты всех проектов со второй ступени менторства последнего потока.
С такими навыками каждого будут рады видеть в достойной компании на позиции сильного 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 января - осталось
- старт 6 февраля - осталось
P.S. Дай знать, если видео было интересным.
Тогда я опубликую полную версию защиты всех проектов со второй ступени менторства последнего потока.
🔥33👍14❤1👎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 и…к последующим курсам!
Приятного просмотра 🍿
Со стороны пользователя - мне бы было удобно, чтобы все курсы были на одной единственной платформе.
Со стороны автора и в целом бизнеса - это также было бы удобно, желательно на своей собственной платформе 😁
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.
В нем нет большого практического занятия, где я как обычно объединяю и закрепляю предыдущий пройденный материал.
Дабы предотвратить и избежать ситуаций с видео, я подготовил большой практический урок.
Ведь это оказалось действительно существенным в понимании материала.
И это JUnit 5.
В нем нет большого практического занятия, где я как обычно объединяю и закрепляю предыдущий пройденный материал.
Дабы предотвратить и избежать ситуаций с видео, я подготовил большой практический урок.
Ведь это оказалось действительно существенным в понимании материала.
🔥40👍8🏆5🙏1
Практика JUnit 5
📊 Немного статистики:
- продолжительность видео 1:03:39
- затрачено времени на создание ~8 часов
- доступно на всех платформах
+ новая домашка для самостоятельного закрепления
👀 Смотреть на YouTube в свободном доступе
📊 Немного статистики:
- продолжительность видео 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 запрос вида:
Главное в конце не забыть отпустить Lock:
P.P.S. На картинке представлен пример использования такого подхода на чистом Java Core
Как-то раз мне нужно было реализовать периодический процесс, который запускался бы раз в 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🔥19❤3
Февраль месяц хоть и маленький, но тянулся для меня очень долго. А все потому, что он был насыщен большим количеством событий, происходящих в моей жизни: подготовка к отцовству, покупка квартиры в Варшаве, Google layoffs, планирование отпуска и переезда, тренировки к соревнованиям по бегу на 5 км и т.д.
Тем не менее, все это время я продолжал тщательную подготовку следующего курса. Я старался меньше отвлекаться на социальные сети, которые забирают не только кучу времени, сколько очень много твоего внимания - а все это дорогой и ограниченный человеческий ресурс.
Я прочел 2 книги, штудировал официальную документацию и исследовал свои предыдущие проекты в поисках практического применения и полезности тех или иных фич изучаемого инструмента.
Могу сказать, что почему-то до сих пор ни один источник не может предоставить полной картины происходящего. Уже в который раз убеждаюсь, что невозможно систематизировать знания и передать их в полном объеме используя лишь один источник информации: книги, видео, исходный код или даже примеры в реальных проектах.
И все же, на этой неделе я планирую выпустить первое видео на своем YouTube канале. Это будет новый курс, в котором я как обычно попытаюсь изложить материал, опираясь лишь на основы, которые у вас уже есть после просмотра предыдущих курсов DMdev.
Так что следи за новостями!
Тем не менее, все это время я продолжал тщательную подготовку следующего курса. Я старался меньше отвлекаться на социальные сети, которые забирают не только кучу времени, сколько очень много твоего внимания - а все это дорогой и ограниченный человеческий ресурс.
Я прочел 2 книги, штудировал официальную документацию и исследовал свои предыдущие проекты в поисках практического применения и полезности тех или иных фич изучаемого инструмента.
Могу сказать, что почему-то до сих пор ни один источник не может предоставить полной картины происходящего. Уже в который раз убеждаюсь, что невозможно систематизировать знания и передать их в полном объеме используя лишь один источник информации: книги, видео, исходный код или даже примеры в реальных проектах.
И все же, на этой неделе я планирую выпустить первое видео на своем YouTube канале. Это будет новый курс, в котором я как обычно попытаюсь изложить материал, опираясь лишь на основы, которые у вас уже есть после просмотра предыдущих курсов DMdev.
Так что следи за новостями!
👍100🔥41❤🔥7🎉3❤2🏆1
Релиз нового курса - первое видео уже на YouTube!
PS. Будет доступен по подписке Lead и со временем на других платформах (Udemy, GetCourse).
PS. Будет доступен по подписке Lead и со временем на других платформах (Udemy, GetCourse).
🔥108👍14🤩3💋3🏆2❤🔥1❤1🎉1
С ужасом заметил, что последний пост я написал тут больше месяца назад.
Как так вышло?
На самом деле все просто:
Был фокус и четкий план на телеграм = были посты
Нет фокуса = нет постов
Хочу вдохнуть новую жизнь сюда, ибо формат телеграма мне очень нравится!
Для этого нужна ваша помощь🙏
Буду очень благодарен, если накидаете в комменты, какие посты/рубрики/активности и в каком формате хотелось бы тут наблюдать.
Это может быть что-то разовое или на постоянной основе, что-то вроде традиции
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥54👍8🫡4❤🔥1👨💻1