Распишу один из самых часто задаваемых вопросов на собеседованиях - принципы SOLID.
S: Single Responsibility Principle (Принцип единственной ответственности). Класс должен решать только какую-то одну задачу. Видел в интернетах много высосанных из пальца примеров, попробую дать примеры из жизни. К основному нарушению этого принципа я бы отнес замешивание в одном месте бизнесового и инфраструктурного кода. Имеем класс с методом с какой-то ядреной бизнес логикой, и тут, ВНЕЗАПНО нам нужно получить дополнительные данные. Не выходя из метода открываем подключение к БД, формируем запрос, читаем ответ, продолжаем бизнес логику. Чувствуете запах?:) Или другой вариант - замешиваем в одном классе получение данных из брокера и их бизнесовую обработку.
Ну и классический пример - антипаттерн singleton. Плоха не единственность экземпляра класса, а самоплальная логика обеспечения единственности.
O: Open-Closed Principle (Принцип открытости-закрытости). Классы должны быть открыты для расширения и закрыты для модификации. Самый простой пример, попирающий этот принцип - использование else if бесконечных размеров, куда по мере развития добавляются новые вариации ветвлений со своей логикой. Самое интересное начинается спустя несколько лет, когда приходится спиливать лишние загибы ветвлений или что-то изменять, оставляя часть функционала неизменной. Альтернатива - больше использовать следующий принцип.
L: Liskov Substitution Principle (Принцип подстановки Барбары Лисков). Объекты в программе должны быть заменяемы их наследниками без изменения корректности программы. В целом - самый очевидный принцип, который осознанно нарушают достаточно редко.
I: Interface Segregation Principle (Принцип разделения интерфейса). Классы не должны реализовывать методы только для совместимости с абстракцией предка. Самый простой путь нарушить предыдущий принцип - реализовывать часть методов только для сохранения совместимости. Как правило, это делается спустя рукава или без полного погружения в контекст.
D: Dependency Inversion Principle (Принцип инверсии зависимостей). Классы должны зависеть не от других классов, а от интерфейсов, чтобы в любой момент можно было подменить реализацию. Очевидная на бумаге вещь, но до чего же лениво ей следовать!
#собес
#solid
S: Single Responsibility Principle (Принцип единственной ответственности). Класс должен решать только какую-то одну задачу. Видел в интернетах много высосанных из пальца примеров, попробую дать примеры из жизни. К основному нарушению этого принципа я бы отнес замешивание в одном месте бизнесового и инфраструктурного кода. Имеем класс с методом с какой-то ядреной бизнес логикой, и тут, ВНЕЗАПНО нам нужно получить дополнительные данные. Не выходя из метода открываем подключение к БД, формируем запрос, читаем ответ, продолжаем бизнес логику. Чувствуете запах?:) Или другой вариант - замешиваем в одном классе получение данных из брокера и их бизнесовую обработку.
Ну и классический пример - антипаттерн singleton. Плоха не единственность экземпляра класса, а самоплальная логика обеспечения единственности.
O: Open-Closed Principle (Принцип открытости-закрытости). Классы должны быть открыты для расширения и закрыты для модификации. Самый простой пример, попирающий этот принцип - использование else if бесконечных размеров, куда по мере развития добавляются новые вариации ветвлений со своей логикой. Самое интересное начинается спустя несколько лет, когда приходится спиливать лишние загибы ветвлений или что-то изменять, оставляя часть функционала неизменной. Альтернатива - больше использовать следующий принцип.
L: Liskov Substitution Principle (Принцип подстановки Барбары Лисков). Объекты в программе должны быть заменяемы их наследниками без изменения корректности программы. В целом - самый очевидный принцип, который осознанно нарушают достаточно редко.
I: Interface Segregation Principle (Принцип разделения интерфейса). Классы не должны реализовывать методы только для совместимости с абстракцией предка. Самый простой путь нарушить предыдущий принцип - реализовывать часть методов только для сохранения совместимости. Как правило, это делается спустя рукава или без полного погружения в контекст.
D: Dependency Inversion Principle (Принцип инверсии зависимостей). Классы должны зависеть не от других классов, а от интерфейсов, чтобы в любой момент можно было подменить реализацию. Очевидная на бумаге вещь, но до чего же лениво ей следовать!
#собес
#solid
👍7❤1
Эшу быдлокодит
Распишу один из самых часто задаваемых вопросов на собеседованиях - принципы SOLID. S: Single Responsibility Principle (Принцип единственной ответственности). Класс должен решать только какую-то одну задачу. Видел в интернетах много высосанных из пальца…
По горячим следам пример к букве I - разделению интерфейсов.
Например: пишем бота в телеграмме, у нас есть сущность - сообщение. Хочется(если честно - не очень) сделать какой-то интерфейс для типичных методов для работы с ним IMessage с методами GetText, GetAttachedMedia, LogToDB и т.д.
Но у нас есть нюанс: сообщения бывают входящие и исходящие. Исходящие после формирования надо отправлять в телегу, то есть нужен метод Send.
Но добавление этого метода в общий интерфейс заставит нас делать какую-то нерабочую фигню во входящем сообщении, потому интерфейсы надо разделить: ICommonMessage, а от него наследуются два интерфейса: IIncomeMessage и IOutcomeMessage, объявляющие свои специфические методы.
#собес
#solid
Например: пишем бота в телеграмме, у нас есть сущность - сообщение. Хочется
Но у нас есть нюанс: сообщения бывают входящие и исходящие. Исходящие после формирования надо отправлять в телегу, то есть нужен метод Send.
Но добавление этого метода в общий интерфейс заставит нас делать какую-то нерабочую фигню во входящем сообщении, потому интерфейсы надо разделить: ICommonMessage, а от него наследуются два интерфейса: IIncomeMessage и IOutcomeMessage, объявляющие свои специфические методы.
#собес
#solid
🔥5
Поступила идея ответить на следущий вопрос интервьюера: приведите примеры ситуаций, когда нарушение каждой из букв оправдано.
Одна ситуация общая на все: мы чиним упавший прод, на кону деньги / репутация. А дальше попробую привести примеры из более спокойных ситуаций.
S. Принцип единства ответственности. Самый первый приходящий на ум случай оправданного нарушения его - наша бизнес логика предполагает строгую транзакционность операции.
Начали выполнение - добавили запись в БД. Следущий шаг - ещё запись, в другое место.
Если все шаги выполнены успешно - коммитнули транзакцию.
Разумеется, можно делать по фен-шую, с сохранением каждого шага и его компенсацией в случае неудачи операции в целом. Но это уже сложная логика, требующая поддержки и какого-то централизованного подхода на уровне проекта.
А можно поступить проще: получить контекст ORM-ки на старте операции, по ходу вносить туда изменения. В случае, если дошли до финала - вызвать у контекста SaveChanges. А если что-то завалилось по пути - транзакция будет откачена, как будто ничего и не было.
#собес
#solid
Одна ситуация общая на все: мы чиним упавший прод, на кону деньги / репутация. А дальше попробую привести примеры из более спокойных ситуаций.
S. Принцип единства ответственности. Самый первый приходящий на ум случай оправданного нарушения его - наша бизнес логика предполагает строгую транзакционность операции.
Начали выполнение - добавили запись в БД. Следущий шаг - ещё запись, в другое место.
Если все шаги выполнены успешно - коммитнули транзакцию.
Разумеется, можно делать по фен-шую, с сохранением каждого шага и его компенсацией в случае неудачи операции в целом. Но это уже сложная логика, требующая поддержки и какого-то централизованного подхода на уровне проекта.
А можно поступить проще: получить контекст ORM-ки на старте операции, по ходу вносить туда изменения. В случае, если дошли до финала - вызвать у контекста SaveChanges. А если что-то завалилось по пути - транзакция будет откачена, как будто ничего и не было.
#собес
#solid
👍7
Перейдем к ситуациях, когда допустимо попирать следущую букву.
O. Принцип открытости-закрытости: классы должны быть открыты для расширения, но закрыты для модификации.
Оправдано нарушение этого принципа в случае, когда- наш проект не планируется активно дорабатывать.
Предположим, мы выполняем функции паллиативной поддепдки легаси проекта, который в обозримой перспективе будет отключен. Лучше писать как проще, чем умножать сущности изящными решениями. А чтобы не возникало искушения творческого использования написанных нами заплаток - запрещаем наследование классов, делая их sealed.
Другой вариант - наш проект - платформенное решение. Мы его делаем, тщательно фиксируем работоспособное состояние тестами, после чего распространяем между коллегами как инструмент, облегчающий решение каких-то типовых задач. Приоритет в таком случае произволительность и стабильность, а не академически правильный код. Изменения в проект вносятся крайне редко, во основном - багфиксы. Один такой мой проект уже года 2 крутится без багов и доработок.
#собес
#solid
O. Принцип открытости-закрытости: классы должны быть открыты для расширения, но закрыты для модификации.
Оправдано нарушение этого принципа в случае, когда- наш проект не планируется активно дорабатывать.
Предположим, мы выполняем функции паллиативной поддепдки легаси проекта, который в обозримой перспективе будет отключен. Лучше писать как проще, чем умножать сущности изящными решениями. А чтобы не возникало искушения творческого использования написанных нами заплаток - запрещаем наследование классов, делая их sealed.
Другой вариант - наш проект - платформенное решение. Мы его делаем, тщательно фиксируем работоспособное состояние тестами, после чего распространяем между коллегами как инструмент, облегчающий решение каких-то типовых задач. Приоритет в таком случае произволительность и стабильность, а не академически правильный код. Изменения в проект вносятся крайне редко, во основном - багфиксы. Один такой мой проект уже года 2 крутится без багов и доработок.
#собес
#solid
🔥4
Перейду к описанию кейсов, когда нарушение принципа, соответствующего следующей букве в аббревиатуре #solid оправдано.
L. Принцип подстановки Барбары Лисков: объекты в программе должны быть заменяемы их наследниками без изменения корректности программы.
Первый кейс напрашивается сам собой: ломать совместимость нужнотогда, когда нужно, а когда не нужно - не стоит, если на то есть технические или бизнесовые основания.
У нас есть некоторая апишка, часть методов которой приговорена к удалению. Для походов в нее используется внутренний пакет, скрывающий от подключивших его всю инфраструктурную кухню.
Хорошим тоном перед реальным удалением методов будет выпустить пакет с новой реализацией обращений к апишке, который вместо выполнения работы будет кидать исключения.
Этот пакет может быть использован как инструмент для подготовки к полному удалению методов: легко искать места, которые нужно доработать, при этом, в случае проблем, всегда можно быстро откатиться на прошлую версию и взять паузу.
Второй кейс: поломка корректности работы программы в целом нам не критична. Например - мы собираем какой-то стенд, имитирующий работы части нашей системы для тестирования (нагрузочного, регрессионного или ещё какого-то - не важно). В данном случае нам нужна корректная работа только той части методов, тестирование которой предусмотрено тест планом.
#собес
L. Принцип подстановки Барбары Лисков: объекты в программе должны быть заменяемы их наследниками без изменения корректности программы.
Первый кейс напрашивается сам собой: ломать совместимость нужно
У нас есть некоторая апишка, часть методов которой приговорена к удалению. Для походов в нее используется внутренний пакет, скрывающий от подключивших его всю инфраструктурную кухню.
Хорошим тоном перед реальным удалением методов будет выпустить пакет с новой реализацией обращений к апишке, который вместо выполнения работы будет кидать исключения.
Этот пакет может быть использован как инструмент для подготовки к полному удалению методов: легко искать места, которые нужно доработать, при этом, в случае проблем, всегда можно быстро откатиться на прошлую версию и взять паузу.
Второй кейс: поломка корректности работы программы в целом нам не критична. Например - мы собираем какой-то стенд, имитирующий работы части нашей системы для тестирования (нагрузочного, регрессионного или ещё какого-то - не важно). В данном случае нам нужна корректная работа только той части методов, тестирование которой предусмотрено тест планом.
#собес
👍1
Пришел через нарушить следущий из принципов #solid - буковку I - Interface segregation - принцип разделения интерфейсов, который я иллюстрировал вышел.
Рассмотрим ситуацию: мы - банк. У нас много денег и высока цена ошибки. Айти огромное, а системы крайне сложны.
Мы можем принять волевое решение: любое действие оборачиваем в абстракцию "операция", OperationBase, для упрощения разработки которых платформенными командами пишется внутренний фреймворк.
Итого на выходе мы имеем шаблон, в котором предусмотрено единообразным способом:
1. Логирование ошибок и основных этапов, система метрик, трассировка используемых запросов.
2. Простой механизм использования кэша, скрывающий особенности реализации: методы Put и Get
3. Механизм для проведения и отката распределенной транзакции.
4. Механизм увязывания операций в цепочки.
5. Механизм авторизации и аутентификации.
При разработке метода, для получения какой-то максимально банальной информации, типа числа баллов бонусной программы, начисленных в прошлом месяце, нам нужно уделить внимание не-реализации распределенных транзакций, осознать место нашей операции в общем ландшафте, поотключать ненужные метрики.
Ценой ощутимой избыточности, мы получаем полностью прозрачную систему, относительно простую в поддержке. При переходе разработчика между направлениями осознание происходящего происходит намного быстрее.
Открываем код операции и сразу видим: кэш используется с такими-то политиками, распределенных транзакций не предусмотрено, логи искать по такому-то ключу, бизнес логика лежит в заранее отведённом месте, начинаем изучать.
#собес
Рассмотрим ситуацию: мы - банк. У нас много денег и высока цена ошибки. Айти огромное, а системы крайне сложны.
Мы можем принять волевое решение: любое действие оборачиваем в абстракцию "операция", OperationBase, для упрощения разработки которых платформенными командами пишется внутренний фреймворк.
Итого на выходе мы имеем шаблон, в котором предусмотрено единообразным способом:
1. Логирование ошибок и основных этапов, система метрик, трассировка используемых запросов.
2. Простой механизм использования кэша, скрывающий особенности реализации: методы Put и Get
3. Механизм для проведения и отката распределенной транзакции.
4. Механизм увязывания операций в цепочки.
5. Механизм авторизации и аутентификации.
При разработке метода, для получения какой-то максимально банальной информации, типа числа баллов бонусной программы, начисленных в прошлом месяце, нам нужно уделить внимание не-реализации распределенных транзакций, осознать место нашей операции в общем ландшафте, поотключать ненужные метрики.
Ценой ощутимой избыточности, мы получаем полностью прозрачную систему, относительно простую в поддержке. При переходе разработчика между направлениями осознание происходящего происходит намного быстрее.
Открываем код операции и сразу видим: кэш используется с такими-то политиками, распределенных транзакций не предусмотрено, логи искать по такому-то ключу, бизнес логика лежит в заранее отведённом месте, начинаем изучать.
#собес
👍3