Ответ
Автор: Роберт Мартин (Robert C. Martin) Год: 2000 Документ: Статья "Design Principles and Design Patterns" Популяризация: Майкл Фэзерс (Michael Feathers) ввёл акроним SOLID
Расшифровка принципов:
- Single Responsibility — единственная ответственность
- Open-Closed — открытость/закрытость
- Liskov Substitution — подстановка Лисков
- Interface Segregation — разделение интерфейсов
- Dependency Inversion — инверсия зависимостей
Пример нарушения и соблюдения SRP в Swift:
// ❌ Нарушение: класс управляет и данными, и уведомлениями
class UserManager {
func saveUser(_ user: User) { /* Сохранение в БД */ }
func sendWelcomeEmail(to user: User) { /* Отправка email */ }
}
// ✅ Соблюдение: разделение ответственности
class UserRepository {
func save(_ user: User) { /* Только сохранение */ }
}
class EmailService {
func sendWelcome(to user: User) { /* Только отправка */ }
}
Практическая польза: SOLID повышает поддерживаемость, тестируемость и гибкость кода.
Ответ 18+ 🔞
Да ты послушай, что эти умники напридумывали! Сидят, блядь, в двухтысячном году, Роберт Мартин, значит, такой, выкатывает статью про принципы дизайна. Ну, типа, как код писать, чтобы он не превращался в такую кашу, что потом сам чёрт ногу сломит, в рот меня чих-пых!
А потом подъехал Майкл Фэзерс, хитрая жопа, и говорит: «А давайте я вам из этого букет принципов акроним слеплю, SOLID, чтобы запоминалось легко!». Ну и слепил, ёпта. И понеслась.
Итак, SOLID, блядь, это не про твёрдое состояние, а про то, как твой код должен быть не как сопля, а чтоб его можно было менять, не разнеся половину проекта к ебеням.
S — Single Responsibility. Единственная ответственность, сука. Это как если у тебя есть молоток, то он должен забивать гвозди, а не ещё и шурупы крутить, и суп варить. Класс должен делать что-то одно, пиздец как просто. А то начнёшь ты в одном классе и пользователей сохранять, и им письма слать, и отчёты генерить — это ж манда с ушами получится! Однажды что-то сломается в отправке писем, а у тебя заодно и сохранение в базу встанет колом. Удивление пиздец!
Смотри, как бывает:
// ❌ Нарушение: класс-универсал, он же швейцарский нож, он же говно
class UserManager {
func saveUser(_ user: User) { /* Сохранение в БД */ }
func sendWelcomeEmail(to user: User) { /* Отправка email */ }
}
Вот этот UserManager — он уже мудак. Он и в базу пихает, и по почте шлёт. А если почтовый сервер ляжет? Всё, сохранение пользователя тоже накроется медным тазом. Терпения ноль ебать!
А теперь по-человечески:
// ✅ Соблюдение: каждый сверчок знай свой шесток
class UserRepository {
func save(_ user: User) { /* Только сохранение. Тише, блядь, мыши, Бог услышит! */ }
}
class EmailService {
func sendWelcome(to user: User) { /* Только отправка. И ни хуя больше! */ }
}
Вот! UserRepository — тупо таскает данные туда-сюда. EmailService — только письма шмаляет. Один сломался — второй живёт и работает. Красота, бля!
O — Open-Closed. Суть в том, что класс должен быть открыт для расширения, но закрыт для изменений. То есть ты не лезешь в его старый, отлаженный код с криками «щас я тут кое-что подпилю!», а навешиваешь новую функциональность сверху, через наследование или композицию. А то начнёшь пилить — и оп, волнение ебать, ты уже пол-системы разъебал.
L — Liskov Substitution. Подстановка Лисков, блядь. Звучит как заклинание, а смысл простой: если у тебя есть класс Утка, и от него наследуется РезиноваяУтка, то везде, где работает Утка, должна спокойно работать и РезиноваяУтка. Если твоя резиновая утка вместо «кря-кря» начинает стрелять ракетами или, того хуже, тонуть — это пиздец, принцип нарушен. Наследник не должен ломать логику предка, иначе это не наследник, а пидарас шерстяной.
I — Interface Segregation. Разделение интерфейсов. Не надо делать один здоровенный, жирный интерфейс на все случаи жизни. Это как если бы ты пришёл в ресторан, а тебе дали меню на 500 страниц, где есть и «бифштекс», и «починить кран», и «сделать укол». Сделай несколько маленьких и точных. Класс должен реализовывать только то, что ему реально нужно, а не тащить на себе кучу ненужных методов, которые он никогда не вызовет.
D — Dependency Inversion. Инверсия зависимостей. Высокоуровневые модули не должны зависеть от низкоуровневых. Оба должны зависеть от абстракций. Проще говоря, не пиши class Engine { let carburetor = OldShittyCarburetor() }. Пиши class Engine { let fuelSystem: FuelSystem }. И тогда ты сможешь подать в движок и карбюратор, и инжектор, и хоть ведро с бензином. Гибкость — овердохуища!
А в чём, собственно, соль? А соль в том, что если этим принципам следовать, то код становится не монолитной глыбой, которую страшно тронуть, а как конструктор. Захотел поменять отправку писем с email на SMS — хук-плюх, заменил один сервис другим, и ничего больше не полетело. Тестировать такое — одно удовольствие, а не ебаться с моками полжизни. Поддерживать — тоже, потому что всё разложено по полочкам, а не свалено в одну кучу, как в комнате у подростка.
В общем, SOLID — это не догма, а, блядь, очень дельные советы от бывалых, как не выстрелить себе в ногу на ровном месте. Потому что иначе потом сидишь и думаешь: «Ну я же всего одну строчку добавил… а почему всё горит?». А горит оно потому, что ты, чувак, ходишь по охуенно тонкому льду своего же кривого кода.