SOLID
👆 SOLID - одни из самых известных принципов для написания качественного ООП кода. Насколько бы простыми и интуитивно понятными они не казались - в своем конечном варианте они были сформулированы только в 2000м году Робертом Мартином.
👉 Я тоже считаю считаю их очень важными для написания качественного читаемого кода. Читаемость (или читабельность) - это вообще один из самых важных факторов вашего кода - ведь будь то большой проект или маленький пет-проект - вам приходится именно читать код в разы больше, чем его писать. Любой баг, любая фича, любой вопрос - это повод к тому, чтобы сесть и прочитать кусок кода.
👇 В первый раз когда я про это прочитал и осознал - у меня буквально перевернулся взгляд на то, как писать код, почему его надо писать по-другому. Итак:
🪑 SRP (Single Responsibility Principle) - Принцип единственной ответственности. О том, что каждый класс должен отвечать за одну и только одну функциональность.
🚪 OCP (Open-Closed Principle) - Принцип открытости закрытости. О том, что классы должны быть открыты для расширения, но закрыты для изменения.
👨👩👧 LSP (Liskov Substitution Principle) - Принцип подстановки Барбары Лисков. О правильном поведении при наследовании.
🧩 ISP (Interface-Segregation Principle) - Принцип разделения интерфейса. О том, как правильно использовать интерфейсы и абстракции.
🔃 DIP (Dependency Inversion Principle) - Принцип инверсии зависимостей. О правильной организации зависимостей на разных уровнях программы.
💬 В следующих постах периодически буду раскрывать подробнее что тут происходит.
#SOLID #Principles
👆 SOLID - одни из самых известных принципов для написания качественного ООП кода. Насколько бы простыми и интуитивно понятными они не казались - в своем конечном варианте они были сформулированы только в 2000м году Робертом Мартином.
👉 Я тоже считаю считаю их очень важными для написания качественного читаемого кода. Читаемость (или читабельность) - это вообще один из самых важных факторов вашего кода - ведь будь то большой проект или маленький пет-проект - вам приходится именно читать код в разы больше, чем его писать. Любой баг, любая фича, любой вопрос - это повод к тому, чтобы сесть и прочитать кусок кода.
👇 В первый раз когда я про это прочитал и осознал - у меня буквально перевернулся взгляд на то, как писать код, почему его надо писать по-другому. Итак:
🪑 SRP (Single Responsibility Principle) - Принцип единственной ответственности. О том, что каждый класс должен отвечать за одну и только одну функциональность.
🚪 OCP (Open-Closed Principle) - Принцип открытости закрытости. О том, что классы должны быть открыты для расширения, но закрыты для изменения.
👨👩👧 LSP (Liskov Substitution Principle) - Принцип подстановки Барбары Лисков. О правильном поведении при наследовании.
🧩 ISP (Interface-Segregation Principle) - Принцип разделения интерфейса. О том, как правильно использовать интерфейсы и абстракции.
🔃 DIP (Dependency Inversion Principle) - Принцип инверсии зависимостей. О правильной организации зависимостей на разных уровнях программы.
💬 В следующих постах периодически буду раскрывать подробнее что тут происходит.
#SOLID #Principles
Оператор
Чем больше программирую, тем больше не люблю оператор
На ревью это для меня теперь главный триггер чтоб начать разбираться в чем была необходимость добавлять тут
#if #SRP
if
Чем больше программирую, тем больше не люблю оператор
if
и стараюсь избегать его использования. Все дело в том, что из-за него вы начинаете генерировать ветки кода, что усложняет его понимание. Более того ваш код сложнее тестировать т.к. на тот же метод нужно написать больше тестов чтоб покрыть ими все возможные ветки выполнения. Например, 3 структуры if-else
в теле метода уже генерируют до 8 возможных разных веток выполнения кода.if
почти всегда можно заменить используя паттерны поведения и на выходе получить безусловный код и более правильную архитектуру.На ревью это для меня теперь главный триггер чтоб начать разбираться в чем была необходимость добавлять тут
if
и, к сожалению, часто такой необходимости действительно нет, но сама кажущаяся простота оператора, особенно с маленькими ветками, не вызывает подозрений и программисты просто его используют. Просто потому что здесь и сейчас это самое простое решение. Но в перспективе оно очень дорогое. Пробуйте избегать этого.#if #SRP
Solid
Single Responsibility Principle
SRP - по-моему, один из самых простых и самых важных принципов. Каждая часть, каждый компонент системы должен отвечать за одну и только одну функциональность. Проще всего понять что система/компонент/класс удовлетворяет этому условию - это если можно дать максимально простой ответ на вопрос “что делает эта часть?” без использования “и”/”или”.
Причем в более сложных системах даже передача данных и управление поведением - это тоже разные сферы ответственности.
Основные триггеры что ваш компонент не удовлетворяет принципу SRP:
👉 При ответе на вопрос “Для чего он нужен?” вам хочется использовать частицы “и”/”или”.
👉 Вы используете оператор
👉 Вы передаете туда булеву переменную. Использование булевой переменной в качестве параметра является антипаттерном, т.к. уже подразумевает, что она будет использоваться в операторе
#if #SRP
Single Responsibility Principle
SRP - по-моему, один из самых простых и самых важных принципов. Каждая часть, каждый компонент системы должен отвечать за одну и только одну функциональность. Проще всего понять что система/компонент/класс удовлетворяет этому условию - это если можно дать максимально простой ответ на вопрос “что делает эта часть?” без использования “и”/”или”.
Причем в более сложных системах даже передача данных и управление поведением - это тоже разные сферы ответственности.
Основные триггеры что ваш компонент не удовлетворяет принципу SRP:
👉 При ответе на вопрос “Для чего он нужен?” вам хочется использовать частицы “и”/”или”.
👉 Вы используете оператор
if
в теле метода. Уже писал чуть более подробно об этом выше по хештегу #if. Само по себе ветвление означает, что что поведение запрограммировано с условием “или”.👉 Вы передаете туда булеву переменную. Использование булевой переменной в качестве параметра является антипаттерном, т.к. уже подразумевает, что она будет использоваться в операторе
if
или в комбинации с другими переменными. В общем - в очередной раз появляются условности и ветки.#if #SRP
sOlid
OCP или Open-Closed Principle довольно интересная штука. На моей практике этот принцип в целом довольно редко применяется. Возможно это связано с довольно быстрым современным миром и быстро меняющимися требованиями в agile-процессах. Тем не менее умственными упражнениями такое вполне достижимо и в реальной разработке можно (и нужно) к этому стремиться.
👉 OCP - это принцип при котором классы закрыты для изменений, но открыты для расширений.
💥 Итак, идея вот в чем. Представьте что архитектура и код в вашем проекте имеют такое свойство, что вы не можете никогда менять старый код ради нового функционала - только писать новое поведение, новые классы и т.д. Разумеется, ради исправления реальных багов, старый код можно править. А ради изменения поведения каких то классов вам нужно будет заново имплементировать какой-либо интерфейс и написать это поведение с нуля. К чему это приведет? Это приведет к тому что весь код работающий в вашем проекте будет без багов и проблем (разумеется - если ваши интерфейсы протестированы).
☝️ Более того, стремление к реализации такого принципа приведет к более лаконичной и аккуратной архитектуре - представьте, что перед стартом задачи вам скажут, что после релиза вы не сможете изменять существующие строки в классах проекта, а только дописывать новые методы и классы. Вы сразу более активно начнете пользоваться интерфейсами, абстракциями, сделаете ваши классы низкосвязанными - ведь вам не захочется в будущем переписывать весь проект ради реализации новой прихоти менеджера из-за очень высокой связности классов внутри проекта.
🧠 Попробуйте взглянуть на вашу последнюю задачу или реализованный модуль с точки зрения OCP - сможете ли вы изменить поведение части бизнес-логики не внося изменения в основные файлы? Сможете ли реализовать дополнительную функциональность не добавляя
#SOLID #Principles #OCP
OCP или Open-Closed Principle довольно интересная штука. На моей практике этот принцип в целом довольно редко применяется. Возможно это связано с довольно быстрым современным миром и быстро меняющимися требованиями в agile-процессах. Тем не менее умственными упражнениями такое вполне достижимо и в реальной разработке можно (и нужно) к этому стремиться.
👉 OCP - это принцип при котором классы закрыты для изменений, но открыты для расширений.
💥 Итак, идея вот в чем. Представьте что архитектура и код в вашем проекте имеют такое свойство, что вы не можете никогда менять старый код ради нового функционала - только писать новое поведение, новые классы и т.д. Разумеется, ради исправления реальных багов, старый код можно править. А ради изменения поведения каких то классов вам нужно будет заново имплементировать какой-либо интерфейс и написать это поведение с нуля. К чему это приведет? Это приведет к тому что весь код работающий в вашем проекте будет без багов и проблем (разумеется - если ваши интерфейсы протестированы).
☝️ Более того, стремление к реализации такого принципа приведет к более лаконичной и аккуратной архитектуре - представьте, что перед стартом задачи вам скажут, что после релиза вы не сможете изменять существующие строки в классах проекта, а только дописывать новые методы и классы. Вы сразу более активно начнете пользоваться интерфейсами, абстракциями, сделаете ваши классы низкосвязанными - ведь вам не захочется в будущем переписывать весь проект ради реализации новой прихоти менеджера из-за очень высокой связности классов внутри проекта.
🧠 Попробуйте взглянуть на вашу последнюю задачу или реализованный модуль с точки зрения OCP - сможете ли вы изменить поведение части бизнес-логики не внося изменения в основные файлы? Сможете ли реализовать дополнительную функциональность не добавляя
IF
-ы, а лишь только добавляя новые методы и классы? В следующей задаче попробуйте найти решение такое, чтоб любое будущее изменение функциональности требовало вносить минимальные изменения в существующие классы.#SOLID #Principles #OCP
soLid
LSP (Liskov Substitution Principle) - Принцип подстановки Барбары Лисков.
Меня лично всегда “конфьюзило” это неочевидное название принципа. Но - “так исторически сложилось”. Итак, о чем же он?
Он про наследование - в основном он призывает нас к тому, чтоб мы организовывали наш код таким образом, что в каком-либо месте подстановка одного объекта вместо объекта другого класса, но имплементирующего тот же интерфейс, - не приводило бы к изменению поведения методов где эти эти объекты используются. Иными словами - вызывающие методы не должны ничего знать о конкретных реализациях используемых ими интерфейсов и уж тем более как-то изменять свое поведение в зависимости от того, объект какого типа они получили на входе.
Пример:
В примере выше можно было бы заменить и проверку по звуку на, например, проверку по
Правильно так:
LSP (Liskov Substitution Principle) - Принцип подстановки Барбары Лисков.
Меня лично всегда “конфьюзило” это неочевидное название принципа. Но - “так исторически сложилось”. Итак, о чем же он?
Он про наследование - в основном он призывает нас к тому, чтоб мы организовывали наш код таким образом, что в каком-либо месте подстановка одного объекта вместо объекта другого класса, но имплементирующего тот же интерфейс, - не приводило бы к изменению поведения методов где эти эти объекты используются. Иными словами - вызывающие методы не должны ничего знать о конкретных реализациях используемых ими интерфейсов и уж тем более как-то изменять свое поведение в зависимости от того, объект какого типа они получили на входе.
Пример:
interface Animal {
String getSound();
}
class Dog implements Animal {
public String getSound() {
return "woof";
}
}
class Cat implements Animal {
public String getSound() {
return "meow";
}
}
void doSomething(Animal animal) {
String sound = animal.getSound();
if (sound.equals("woof")) {
System.out.print("Dog");
} else {
System.out.print("Cat");
}
System.out.println(" says " + sound);
}
В примере выше можно было бы заменить и проверку по звуку на, например, проверку по
instanceof
. В любом случае в методе doSomething
после этого появляется знание о деталях реализации интерфейса. Более того так мы нарушили и принцип #OCP - теперь для добавления новой имплементации Animal нам придется и обновлять метод doSomething
.Правильно так:
interface Animal {
String getSound();
String getName();
}
class Dog implements Animal {
public String getSound() {
return "woof";
}
public String getName() {
return "Dog";
}
}
class Cat implements Animal {
public String getSound() {
return "meow";
}
public String getName() {
return "Cat";
}
}
void doSomething(Animal animal) {
System.out.println(animal.getName() + " says " + animal.getSound());
}
solId
ISP
interface segregation principle
принцип разделения интерфейсов заключается в том, что лучше иметь более узкоспециализированные интерфейсы и уже через их имплементацию реализовывать определенное поведение у конкретных классов. Разумеется смысл тут в генерации низкосвязанного кода - когда методы и модули зависимы не от больших объектов и интерфейсов, а именно от узких интерфейсов. Наверное один из самых ярких примеров - это
Любопытная деталь в том, что мы достаточно редко анализируем альтернативно возможные реализации нашего кода/модуля потому что в целом мы всегда можем справиться с архитектурными недостатками. Но стоит один раз переписать модуль сделав акцент на ISP как становятся понятны плюсы. Особенно если мы хотим вынести кусок модуля в виде библиотеки. Именно в процессах, критичных к низкой связности, и чувствуется огромный потенциал подходов основанных на правильном использовании интерфейсов.
Только не нужно уходить в крайности. Я встречал очень много проектов с пунктиком по поводу использования интерфейсов, но их неправильное использование ничего кроме боли не приносит
ISP
interface segregation principle
принцип разделения интерфейсов заключается в том, что лучше иметь более узкоспециализированные интерфейсы и уже через их имплементацию реализовывать определенное поведение у конкретных классов. Разумеется смысл тут в генерации низкосвязанного кода - когда методы и модули зависимы не от больших объектов и интерфейсов, а именно от узких интерфейсов. Наверное один из самых ярких примеров - это
Iterable
или Comparable
в базовой поставке Java. Только представьте, насколько менее удобно было бы использовать циклы или методы сравнения, будь они основаны на более толстых интерфейсах или даже отдельных реализациях. Например, насколько сложнее стала бы наша жизнь при необходимости использовать в циклах только наследников класса Collection
.Любопытная деталь в том, что мы достаточно редко анализируем альтернативно возможные реализации нашего кода/модуля потому что в целом мы всегда можем справиться с архитектурными недостатками. Но стоит один раз переписать модуль сделав акцент на ISP как становятся понятны плюсы. Особенно если мы хотим вынести кусок модуля в виде библиотеки. Именно в процессах, критичных к низкой связности, и чувствуется огромный потенциал подходов основанных на правильном использовании интерфейсов.
Только не нужно уходить в крайности. Я встречал очень много проектов с пунктиком по поводу использования интерфейсов, но их неправильное использование ничего кроме боли не приносит
Немного о паттернах
Сейчас я веду несколько лекций на одном из курсов повышения квалификации программистов. Так вот, готовясь к лекции по паттернам проектирования у меня появилась одна интересная мысль.
Представьте что вы идете к стоматологу и вам предлагают выбрать - идти к стоматологу, который недавно выпустился из университета и имеет стаж работы 2 года, или идти к стоматологу без образования, но со стажем работы в 5 лет. И давайте притворимся, что кто-то его пустил работать без образования и это норма. Так вот, к какому вы пойдете? Уверен что многие предпочтут пойти к первому - потому что какое бы образование ни было, оно все равно позволяет хоть на каком-то уровне понимать причины болезней и применять те инструменты, которые позволят достичь результата. Конечно у стоматолога с 5-летним стажем скорее всего лучше получается управляться с инструментами, но в нужных ли ситуациях он их применяет? Понимает ли он почему и зачем определенный инструмент нужно брать в той или иной ситуации.
И с паттернами в разработке та же история, - это очень мощные инструменты в руках разработчика, но непонимание зачем они нужны и какие проблемы решают ведут к тому что инструменты используются неверно. В последние пару месяцев я собеседовал пару десятков человек уровня Junior/middle, и только половина из них хорошо отвечает на вопрос "какую боль или проблему решает этот инструмент?".
Поэтому моя лекция, изначально называвшая "паттерны", превратилась в лекцию "паттерны и чистый код", причем про Clean Code там 80% материала, а про паттерны - оставшиеся крохи. Потому что именно в этом цель применения паттернов - сделать код читабельным, тестируемым, менее подверженным багам и т.д.
Паттерны сами по себе не решают ни одной бизнес-задачи, но они позволяют уже готовым решениям работать более эффективно и, главное, более долгосрочно. Но только при условии их применения в нужном месте и в нужное время.
Интересный эффект попыток применить принципы Clean Code заключаются в том, что инструменты (т.е. паттерны) вы можете переизобрести заново самостоятельно, но уже с очень глубоким пониманием концепций их работы и проблем, которые они могут решить.
Сейчас я веду несколько лекций на одном из курсов повышения квалификации программистов. Так вот, готовясь к лекции по паттернам проектирования у меня появилась одна интересная мысль.
Представьте что вы идете к стоматологу и вам предлагают выбрать - идти к стоматологу, который недавно выпустился из университета и имеет стаж работы 2 года, или идти к стоматологу без образования, но со стажем работы в 5 лет. И давайте притворимся, что кто-то его пустил работать без образования и это норма. Так вот, к какому вы пойдете? Уверен что многие предпочтут пойти к первому - потому что какое бы образование ни было, оно все равно позволяет хоть на каком-то уровне понимать причины болезней и применять те инструменты, которые позволят достичь результата. Конечно у стоматолога с 5-летним стажем скорее всего лучше получается управляться с инструментами, но в нужных ли ситуациях он их применяет? Понимает ли он почему и зачем определенный инструмент нужно брать в той или иной ситуации.
И с паттернами в разработке та же история, - это очень мощные инструменты в руках разработчика, но непонимание зачем они нужны и какие проблемы решают ведут к тому что инструменты используются неверно. В последние пару месяцев я собеседовал пару десятков человек уровня Junior/middle, и только половина из них хорошо отвечает на вопрос "какую боль или проблему решает этот инструмент?".
Поэтому моя лекция, изначально называвшая "паттерны", превратилась в лекцию "паттерны и чистый код", причем про Clean Code там 80% материала, а про паттерны - оставшиеся крохи. Потому что именно в этом цель применения паттернов - сделать код читабельным, тестируемым, менее подверженным багам и т.д.
Паттерны сами по себе не решают ни одной бизнес-задачи, но они позволяют уже готовым решениям работать более эффективно и, главное, более долгосрочно. Но только при условии их применения в нужном месте и в нужное время.
Интересный эффект попыток применить принципы Clean Code заключаются в том, что инструменты (т.е. паттерны) вы можете переизобрести заново самостоятельно, но уже с очень глубоким пониманием концепций их работы и проблем, которые они могут решить.
https://habr.com/ru/post/521062/
Вчера написали пост на хабр про программу Ноль Смертей (Vision Zero), которой в России занимаются пока что активисты. Я в этой истории немного учавствую в качеству разработчика телеграм бота для репортов аварий. Если кому-то вдруг хочется поучавствовать в чем-то опенсорс, социальном и на котлине одновременно - то welcome https://github.com/asundukov/crash_map - там пока не добавлены issues, но идейки как доработать конечно уже есть.
Вчера написали пост на хабр про программу Ноль Смертей (Vision Zero), которой в России занимаются пока что активисты. Я в этой истории немного учавствую в качеству разработчика телеграм бота для репортов аварий. Если кому-то вдруг хочется поучавствовать в чем-то опенсорс, социальном и на котлине одновременно - то welcome https://github.com/asundukov/crash_map - там пока не добавлены issues, но идейки как доработать конечно уже есть.
Хабр
Ноль смертей: как выжить в ДТП
В прошлом году проект “Карта ДТП” опубликовал исходные коды сайта по анализу дорожно-транспортных происшествий. Наша работа получила большой отклик, и мы продолжили развитие. Теперь работает мобильная...
У меня новая фраза-фаворит с последнего рабочего митинга (да-да, некоторые уже работают):
"It's double broken"
"It's double broken"
сегодня ночью @quattique написала новый пост после долго отсутствия и это напомнило мне и про мой маленький уютный канальчик который покрывается пылью.
И так как я пока сходу не готов писать лонгриды (хотя есть о чем) напишу про короткую рекрутерскую тему - не так давно узнал что у нас крутая дорогая рефералка в американскую компанию. Так что если у вас вдруг есть знакомые Java-разработчики (или вы сами таковой) с 3+ годами опыта работы и если вы хотите подзарботать $2-2.5к просто за рекоммендацию - то welcome ко мне в личку. А сами вакансии очень приятные - полная удаленка, привязка зп к долларам, опционы, работа в международной команде (с коллегами из америки) так что английский тоже must have 🙃
И так как я пока сходу не готов писать лонгриды (хотя есть о чем) напишу про короткую рекрутерскую тему - не так давно узнал что у нас крутая дорогая рефералка в американскую компанию. Так что если у вас вдруг есть знакомые Java-разработчики (или вы сами таковой) с 3+ годами опыта работы и если вы хотите подзарботать $2-2.5к просто за рекоммендацию - то welcome ко мне в личку. А сами вакансии очень приятные - полная удаленка, привязка зп к долларам, опционы, работа в международной команде (с коллегами из америки) так что английский тоже must have 🙃
Задачка, которую я придумал год назад и периодически спрашиваю на собеседованиях. Интересный факт что знания которые требуются чтоб на нее ответить - это джуновые знания Java и школьный курс математики. Но не каждый Senior способен дать правильный ответ. Попробуйте ее решить и только потом посмотреть в комментарии и пишите туда ваш ответ, можно приблизительный, обсудим!
Вот ее текст:
Сколько различных объектов класса String можно создать таких, чтобы их hashcode был одинаковым (например, чтоб он был равен 42)?
Вот ее текст:
Сколько различных объектов класса String можно создать таких, чтобы их hashcode был одинаковым (например, чтоб он был равен 42)?
Недавно обнаружил у себя на проекте примерно такое.
Это даже побудило меня написать статью, которую я наверное скорое опубликую. В этом куске кода есть одна серьезная проблема и ворох проблем поменьше, очень похоже, кстати, на задачки на собесах.
Пишите в комменты что здесь не так.
И кстати, если у кого-то есть интересные примеры кусков кода, или даже с собеседований - тоже скидывайте, хочу серию разборов сделать что такое хорошо и что такое плохо.
Это даже побудило меня написать статью, которую я наверное скорое опубликую. В этом куске кода есть одна серьезная проблема и ворох проблем поменьше, очень похоже, кстати, на задачки на собесах.
Пишите в комменты что здесь не так.
И кстати, если у кого-то есть интересные примеры кусков кода, или даже с собеседований - тоже скидывайте, хочу серию разборов сделать что такое хорошо и что такое плохо.
Всегда казалось, что проблемы связанные с equals и hashCode настолько редковстречающиеся что чего толку их изучатью А вчера увидел парочку в коде, причем их редковстречаемость вполне перевешивает их потенциальную серьезность.
Что было: hibernate entity у которой был переопределен только equals, при том что equals сравнивал только id-поля. Были написаны тесты - например, в одном из них создавался HashSet из пары этих entites, entities были не сохранены в БД поэтому их id были равны нулю. В итоге при вставке в Set они вставлялись всегда в новый бакет, но фактически были равны межды собой (конечно тут еще отдельныее вопросики про использование mutable объектов в set). Просто добавление правильного hashCode сломало работу тестов т.к. в сет стал попадать только один элемент, пришлось доработать еще и equals.
Но, вообще, иногда волосы встают дыбом когда понимаю потенциальные проблемы которые может доставить отсутствие вот этих важных 3-9 строчек кода.
А вот недавно студенты скидывали отличное StackOverflow обсуждение как вообще работать с equals/hashCode и JPA: https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma
Что было: hibernate entity у которой был переопределен только equals, при том что equals сравнивал только id-поля. Были написаны тесты - например, в одном из них создавался HashSet из пары этих entites, entities были не сохранены в БД поэтому их id были равны нулю. В итоге при вставке в Set они вставлялись всегда в новый бакет, но фактически были равны межды собой (конечно тут еще отдельныее вопросики про использование mutable объектов в set). Просто добавление правильного hashCode сломало работу тестов т.к. в сет стал попадать только один элемент, пришлось доработать еще и equals.
Но, вообще, иногда волосы встают дыбом когда понимаю потенциальные проблемы которые может доставить отсутствие вот этих важных 3-9 строчек кода.
А вот недавно студенты скидывали отличное StackOverflow обсуждение как вообще работать с equals/hashCode и JPA: https://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma
Всегда хочется объект, который используется в singleton-сервисе или контроллере, сделать полем класса (или static-полем класса если сам объект пересоздается), чтоб избежать его создания на каждый реквест. Именно так я сделал, когда начинал работать с Java и вынес в поле класса SimpleDateFormat. Через пару недель иногда стали прилетать ерроры. Оказалось, что этот класс не ThreadSafe и при работе в многопоточном режиме при попытке одновременного парсинга из разных потоков оно может падать.
Выхода тут несколько:
- отказаться от common-объектов и создавать каждый раз новенький SimpleDateFormat
- обернуть SimpleDateFormat ThreadLocal-переменную, чтоб создавать каждый экземпляр не более одного раза в каждом потоке
- использовать альтернативы FastDateFormat из Commons Lang или DateTimeFormat из JodaTime библиотеки
я предпочитаю второй вариант.
А вообще все вышеописанное относится к любым stateful-объектам. Будте осторожны и всегда проверяйте, что используемые вами инструменты являются ThreadSafe при работе в многопоточной среде.
Выхода тут несколько:
- отказаться от common-объектов и создавать каждый раз новенький SimpleDateFormat
- обернуть SimpleDateFormat ThreadLocal-переменную, чтоб создавать каждый экземпляр не более одного раза в каждом потоке
- использовать альтернативы FastDateFormat из Commons Lang или DateTimeFormat из JodaTime библиотеки
я предпочитаю второй вариант.
А вообще все вышеописанное относится к любым stateful-объектам. Будте осторожны и всегда проверяйте, что используемые вами инструменты являются ThreadSafe при работе в многопоточной среде.
Недавно меня спросили - чем плохо большое количество аргументов в методе или конструкторе?
1. Это сложно читать в коде и на ревью, если IDE без подстветки - можно запросто перепутать пару аргументов
2. Если эти аргументы передаются через 2-3 слоя - то возникают длинные портянки аргументов где опять же очень легко многое напутать, а добавление/изменение чего-либо приводит к каскадным фиксам.
Как избежать большого количества параметров, передаваемых в метод?
способ 1: Рефакторинг
Если метод не удоволтворяет принципу #SRP, то при его рефакторинге количество параметров явно уменьшиться
способ 2: Группировка параметров в один объект
Если метод удовлетворяет принципу #SRP - значит и параметры этого метода можно как-то сгруппировать. Можно их сгруппировать в один объект, который, в свою очередь создавать с помощью #builder
способ 3: Вынос аргументов метода в поля класса
В некоторых ситуациях есть возможность все аргументы метода или их часть вынести в качестве полей класса, тогда сам класс можно создавать с помощью #builder, а потом вызывать метод с минимальным колиеством дополнительных аргументов
1. Это сложно читать в коде и на ревью, если IDE без подстветки - можно запросто перепутать пару аргументов
2. Если эти аргументы передаются через 2-3 слоя - то возникают длинные портянки аргументов где опять же очень легко многое напутать, а добавление/изменение чего-либо приводит к каскадным фиксам.
Как избежать большого количества параметров, передаваемых в метод?
способ 1: Рефакторинг
Если метод не удоволтворяет принципу #SRP, то при его рефакторинге количество параметров явно уменьшиться
способ 2: Группировка параметров в один объект
Если метод удовлетворяет принципу #SRP - значит и параметры этого метода можно как-то сгруппировать. Можно их сгруппировать в один объект, который, в свою очередь создавать с помощью #builder
способ 3: Вынос аргументов метода в поля класса
В некоторых ситуациях есть возможность все аргументы метода или их часть вынести в качестве полей класса, тогда сам класс можно создавать с помощью #builder, а потом вызывать метод с минимальным колиеством дополнительных аргументов
На LeetCode начался November Challenge. А здесь ребята собрались чтоб делиться своими успехами и обсуждать задачки: https://t.co/S2xMdrWPmT
я тоже решил поучавствовать и уже выполнил задание первого дня 🤟🏻 сходу было не особо то и легко - давно не было алгоритмической практики, но мозги так иногда разминать мегаполезно.
я тоже решил поучавствовать и уже выполнил задание первого дня 🤟🏻 сходу было не особо то и легко - давно не было алгоритмической практики, но мозги так иногда разминать мегаполезно.
Вчера долго разбирал одну проблему в бизнес логике - внутри транзакции происходила попытка отправить письмо.
Попытка эта фейлилась, чем запускала ветку отправки отчета об этом фейле, и в отчетный метод передавался id сущности в процессе обработки которой произошел сбой. Проблема в томб что отчетный механизм начинал новую транзакцию, и мы попадали в очень типичный дедлок, когда двум разным коннектам к БД нужна стала блокировка на одну запись.
Как сделать правильно:
И вообще любые транзакции надо делать максимально легкими и пытаться избегать любых внешних вызовов, иначе на консистентность данных начинают влиять внешние сервисы, а это очень сложно разгребать.
@Transactional
public void method() {
try {
//logic
} catch (Exception e) {
// report with a new transaction
}
}
Попытка эта фейлилась, чем запускала ветку отправки отчета об этом фейле, и в отчетный метод передавался id сущности в процессе обработки которой произошел сбой. Проблема в томб что отчетный механизм начинал новую транзакцию, и мы попадали в очень типичный дедлок, когда двум разным коннектам к БД нужна стала блокировка на одну запись.
Как сделать правильно:
public void method() {
try {
// call transactional method
} catch (Exception e) {
// call report with a new transaction
}
}
И вообще любые транзакции надо делать максимально легкими и пытаться избегать любых внешних вызовов, иначе на консистентность данных начинают влиять внешние сервисы, а это очень сложно разгребать.