Принципы SOLID часто относят именно к ООП программированию, но это не обязательно, главное чтобы был инструмент для объединения функций - модуль.
Акроним SOLID включает в себя 5 принципов:
## Single Responsibility Principle / Принцип единой ответственности
**Каждый модуль должен решать одну задачу.**
Не должно быть огромных модулей "комбайнов" для решения всех задач приложения. Должны быть модули, решающие небольшие задачи, которые с помощью композиции объединяются в единый модуль и решают конечную задачу.
## Open-Closed Principle / Принцип открытости-закрытости
**Модули должны быть открыты для расширения, но закрыты для изменения.**
- Открыты для расширения: означает, что поведение сущности может быть расширено путём создания новых типов сущностей.
- Закрыты для изменения: в результате расширения поведения сущности, не должны вноситься изменения в код, который эту сущность использует.
Имеется ввиду, что ранее созданные модули должны как можно реже и меньше изменяться. Если требуется добавить новую функциональность, то нужно создать новый модуль на основе уже существующих, используя наследование, композицию и абстракции
Такой подходят позволяет уменьшить количество ошибок, связанных с регрессией кода
## Liskov Substitution Principle / Принцип подстановки Барбары Лисков
**Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом**
Тут проще всего понять на примере из ООП, в котором базовый тип - это базовый класс, а подтип - это дочерний класс. Если дочерний класс определяет абстрактный метод или переопределяет существующий, то такой метод должен делать то, что от него ожидается. Ожидание может быть сформировано из названия и описания метода
Например при определении метода writeToFile должна быть реализована функциональность записи в файл, а не вывод в консоль, завершение программы или пустой метод. Соблюдая это правило, можно будет без опасений использовать подтип на месте базового типа
## Interface Segregation Principle / Принцип разделения интерфейса
**Программные сущности не должны зависеть от методов, которые они не используют** или **Много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего назначения**
Короче говоря интерфейсы с множеством методов можно и нужно делить на множество узкоспециализированных, решающих одну задачу. В итоге нужно организовать интерфейсы так, чтобы не было случая, что тип имплементирует интерфейс, но используются не все методы интерфейса. В таком случае нужно делить интерфейс на более узкоспециализированные
## Dependency Inversion Principle / Принцип инверсии зависимостей
**Модули должны зависеть от абстракций, а не от конкретных реализаций**
Или более подробно:
**Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те, и другие должны зависеть от абстракции. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.**
Таким образом в ООП:
1) Базовые классы не должны ничего знать о дочерних классах. Типы дочерних классов не должны указываться в родительском классе и тем более не должны создаваться их экземпляры в родительском классе
2) Указывая тип свойства или параметра нужно указывать наиболее базовый подходящий класс из иерархии, чтобы на его месте без проблем можно было использовать дочерний класс. Для этого нужно использовать наследование с обычными и абстрактными классами и интерфейсы
#### Полезные ссылки
- [SOLID (Wikipedia)](https://ru.wikipedia.org/wiki/SOLID_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5))
- [Принципы SOLID на примерах (Habr)](https://habr.com/ru/articles/688530/)
- [SOLID ПРИНЦИПЫ простым языком (YouTube)](https://www.youtube.com/watch?v=TxZwqVTaCmA)