Ответ
В разработке на Go, как и в бэкенде в целом, я руководствуюсь общепринятыми принципами, которые особенно хорошо ложатся на философию языка.
SOLID — это основа объектно-ориентированного дизайна, но его принципы отлично адаптируются для Go:
- S (Single Responsibility Principle) — Принцип единственной ответственности. В Go это выражается в создании небольших, сфокусированных пакетов, структур и функций, каждая из которых решает одну конкретную задачу.
- O (Open/Closed Principle) — Принцип открытости/закрытости. В Go достигается через композицию (встраивание структур) и интерфейсы, а не через наследование. Мы можем расширять функциональность, создавая новые типы, удовлетворяющие интерфейсу, не изменяя существующий код.
- L (Liskov Substitution Principle) — Принцип подстановки Барбары Лисков. Поскольку в Go нет наследования, принцип применяется к интерфейсам. Любая реализация интерфейса должна соответствовать его контракту, не нарушая ожиданий клиента.
- I (Interface Segregation Principle) — Принцип разделения интерфейса. Это ключевой принцип в Go. Язык поощряет создание маленьких, узкоспециализированных интерфейсов (например,
io.Reader). Клиенты должны зависеть только от тех методов, которые им действительно нужны. -
D (Dependency Inversion Principle) — Принцип инверсии зависимостей. Модули верхних уровней не должны зависеть от модулей нижних уровней. И те, и другие должны зависеть от абстракций (интерфейсов). Это делает код модульным, слабо связанным и легко тестируемым.
// Модуль зависит от интерфейса Storage, а не от конкретной реализации type Storage interface { Save(data string) error } type Service struct { storage Storage // Зависимость через интерфейс (DIP) }
Другие важные принципы:
- DRY (Don’t Repeat Yourself) — Не повторяйся. Избегание дублирования кода через вынесение общей логики в переиспользуемые функции и пакеты.
- KISS (Keep It Simple, Stupid) — Делай проще. Философия Go полностью соответствует этому принципу. Предпочтение отдается простому и понятному коду, а не сложным абстракциям.
- YAGNI (You Aren’t Gonna Need It) — Вам это не понадобится. Не добавлять функциональность "про запас". Это помогает сохранять кодовую базу чистой и сфокусированной на текущих требованиях.
Ответ 18+ 🔞
Так, слушай сюда, про эти ваши принципы. Ну, SOLID, блядь. Все их талдычат, а половина нихуя не понимает, как это в Go прикрутить. Ёпта, сейчас разжую.
Ну, S — это типа одна штука — одна работа. Не делай из своей функции или структуры швейцарский нож, который и бутерброд намажет, и в космос слетает. Сделал SendEmail — пусть только письма и шлет, а не логи пишет и в базу статистику кладет. Просто, как три копейки.
O — открытость/закрытость. В Го нету этого вашего наследования, слава богу. Тут всё через интерфейсы и композицию. Хочешь новую фичу? Напиши новый тип, который впишется в старый интерфейс, и подсунь его. Старый код даже не чихнет. Красота.
L — подстановка Лисков. Короче, если твой тип говорит, что он удовлетворяет интерфейсу Reader, то он должен читать, сука, а не притворяться читателем, а сам втихаря писать в лог. Не обманывай компилятор, а то он тебе потом отомстит.
I — а вот это, блядь, святое в Go! Принцип разделения интерфейса. Не лепи кучу методов в один интерфейс на все случаи жизни. Сделай маленькие, как io.Reader и io.Writer. Хочешь и читать, и писать? Так объедини их, ёпта: type ReadWriter interface { Reader; Writer }. Клиент берет только то, что ему надо, и не тащит за собой овердохуища ненужного кода. Гениально и просто.
D — инверсия зависимостей. Мозг немного сломать можно, но суть простая: высокоуровневый модуль не должен знать, с какой конкретно базой или API он работает. Он должен знать только абстракцию — интерфейс. Смотри:
// Модуль зависит от интерфейса Storage, а не от конкретной реализации
type Storage interface {
Save(data string) error
}
type Service struct {
storage Storage // Зависимость через интерфейс (DIP)
}
Вот так. Подсовываешь ему в тестах мок, в продакшене — постгресс, а он и не заметит подмены. Гибко, тестируемо, красиво. Пиздец как правильно.
Ну и остальная хуйня:
- DRY — не повторяйся, долбоёб. Вынес общую логику в функцию. Нашел копипасту в трёх местах — значит, ты уже облажался.
- KISS — делай проще, идиот. Это вообще девиз Go. Не выёбывайся с навороченными паттернами, если можно решить задачу парой прямолинейных функций. Компилятор и коллеги скажут спасибо.
- YAGNI — тебе это не понадобится. Не пиши архитектуру для марсианской колонии, когда делаешь сайт-визитку. Сделал то, что просили, и иди нахуй. Всё остальное — преждевременная оптимизация и вынос мозга самому себе.
Вот и вся философия. Ничего сложного, если голову включать. А если не включать — получишь лапшу, которую через месяц и сам не разберёшь.