Что такое solid в программировании
Перейти к содержимому

Что такое solid в программировании

  • автор:

SOLID (объектно-ориентированное программирование)

SOLID это аббревиатура пяти основных принципов дизайна классов в объектно-ориентированном проектировании — Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion.

Описание

Буква Означает Описание
S SRP Принцип единственной обязанности На каждый объект должна быть возложена одна единственная обязанность.
O OCP Принцип открытости/закрытости Программные сущности должны быть открыты для расширения, но закрыты для изменения.
L LSP Принцип подстановки Барбары Лисков Объекты в программе могут быть заменены их наследниками без изменения свойств программы. См. также контрактное программирование.
I ISP Принцип разделения интерфейса Много специализированных интерфейсов лучше, чем один универсальный.
D DIP Принцип инверсии зависимостей Зависимости внутри системы строятся на основе абстракций. Модули верхнего уровня не зависят от модулей нижнего уровня. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

История

Аббревиатура SOLID была предложена Робертом Мартином.

Литература

  • Роберт С. Мартин, Джеймс В. Ньюкирк, Роберт С. Косс Быстрая разработка программ. Принципы, примеры, практика — Вильямс, 2004, ISBN 5-8459-0558-3, ISBN 0-13-597444-5

Ссылки

  • Principles Of OOD (англ.) — Описание и ссылки на подробные статьи о SOLID.
  • Хороший дизайн должен быть SOLID: TOP-5 архитектурных принципов (рус.)
  • Принципы проектирования классов (рус.)
  • Доступно о SOLID (рус.)
  • Разработка программного обеспечения
  • Объектно-ориентированное программирование
  • Проектирование программного обеспечения
  • Принципы программирования

Wikimedia Foundation . 2010 .

Полезное

Смотреть что такое «SOLID (объектно-ориентированное программирование)» в других словарях:

  • Принцип разделения интерфейса — (англ. Interface Segregation Principle, ISP) один из пяти принципов проектирования классов в объектно ориентированном программировании. Следование этому принципу помогает системе оставаться гибкой при внесении изменений в логику работы и… … Википедия
  • Принцип подстановки Барбары Лисков — (англ. Liskov Substitution Principle, LSP) в объектно ориентированном программировании является специфичным определением подтипа предложенным Барбарой Лисков в 1987 году на конференции в основном докладе под названием Абстракция данных и… … Википедия
  • Принцип подстановки Лисков — Принцип подстановки Барбары Лисков (англ. Liskov Substitution Principle, LSP) в объектно ориентированном программировании является специфичным определением подтипа предложенным Барбарой Лисков в 1987 году на конференции в основном докладе… … Википедия
  • Принцип инверсии зависимостей — (англ. Dependency Inversion Principle, DIP) важный принцип объектно ориентированного программирования, используемый для уменьшения связанности в компьютерных программах. Входит в пятёрку принципов SOLID. Формулировка Модули верхних… … Википедия
  • Принцип единственной обязанности — В объектно ориентированном программировании принцип единственной обязанности обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены… … Википедия
  • Цикл разработки программного обеспечения — Эта статья предлагается к удалению. Пояснение причин и соответствующее обсуждение вы можете найти на странице Википедия:К удалению/30 июля 2012. Пока процесс обсуждения … Википедия
  • Обратная связь: Техподдержка, Реклама на сайте
  • �� Путешествия

Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.

  • Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
  • Искать во всех словарях
  • Искать в переводах
  • Искать в ИнтернетеИскать в этой же категории

Принципы SOLID на примерах Python

Принципы SOLID на примерах Python-кода, с подробным объяснением преимуществ и возможных недостатков каждого принципа.

Вероятно, вы не раз слышали о так называемых SOLID принципах. Но что на самом деле означает каждый из принципов SOLID и как правильно применять их на практике? Вы найдёте ответы в данной статье.

Что такое SOLID принципы?

Современная разработка требует передовых навыков и глубоких знаний сложных принципов программирования. Одной из наиболее важных структур, используемых сегодня в разработке программного обеспечения, являются принципы SOLID — они же пять основных принципов объектно-ориентированного программирования.

Понимание SOLID является обязательным для всех разработчиков, и в этой статье мы объясним их простым языком.

Расшифровка SOLID

Аббревиатура SOLID включает в себя название пяти принципов «хорошего дизайна», когда речь идет о разработке программного обеспечения. Акроним SOLID означает следующие принципы:

  1. Принцип единственной ответственности (Single Responsibility Principle – SRP): Каждый класс должен иметь только одну причину для изменения. Это означает, что класс должен быть ответственным только за одну конкретную функцию или задачу. Этот принцип помогает сделать классы более связанными, легко понятными и поддерживаемыми.
  2. Принцип открытости/закрытости (Open/Closed Principle – OCP): Программные сущности, такие как классы, модули и функции, должны быть открыты для расширения, но закрыты для модификации. Вместо изменения существующего кода, следует добавлять новый код для внесения изменений. Это позволяет создавать более стабильные и гибкие системы.
  3. Принцип подстановки Лисков (Liskov Substitution Principle – LSP): Объекты в программе должны быть заменяемыми экземплярами их базовых типов, не нарушая корректность программы. Это означает, что код, который работает с базовым типом, должен работать и с любым его подтипом, не вызывая ошибок или неожиданного поведения. Этот принцип обеспечивает согласованность в использовании наследования и полиморфизма.
  4. Принцип разделения интерфейса (Interface Segregation Principle – ISP): Клиенты не должны зависеть от интерфейсов, которые они не используют. Вместо создания общих интерфейсов следует создавать специфические интерфейсы, предназначенные для конкретных клиентов. Это позволяет избежать излишней связности между компонентами системы и улучшить модульность.
  5. Принцип инверсии зависимостей (Dependency Inversion Principle – DIP): Классы должны зависеть от абстракций, а не от конкретных реализаций. Высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба типа модулей должны зависеть от абстракций. Этот принцип помогает уменьшить связанность между компонентами системы и повысить их переиспользуемость.

Все эти пять принципов SOLID способствуют созданию гибкого и легко поддерживаемого кода, а также улучшают модульность, переиспользуемость и расширяемость системы.

Акроним SOLID принципов был сформулирован Робертом С. Мартином, также известным как «Дядя Боб», одним из самых влиятельных разработчиков программного обеспечения в области разработки программного обеспечения.

Хотя многим эти принципы могут показаться сложными, мы постараемся объяснить их простым и понятным способом.

Принцип единой ответственности

Мы начнем с принципа единой ответственности, который гласит, что каждый класс или компонент кода должен иметь только одну ответственность. Это также означает, что у него должна быть только одна причина для изменения. Чтобы проиллюстрировать принцип, давайте рассмотрим пример.

Предположим, у нас есть файл с именем «автомобиль» с кодом, отвечающим за эксплуатацию, управление, контроль и мониторинг автомобиля. В соответствии с принципом единой ответственности каждая из этих задач должна быть разделена на отдельный файл или компонент. Также стоит отметить, что SRP применяется не только к классам, но и к функциям и методам.

SOLID примеры на Python — принцип единой ответственности

Концепция принципа единой ответственности (SRP) заключается в том, что класс должен иметь только одну причину для изменения. Давайте рассмотрим пример с классом User , который нарушает этот принцип:

class User: def __init__(self, username, email): self.username = username self.email = email def save(self): # Логика сохранения пользователя в базе данных pass def send_email(self, message): # Логика отправки электронной почты пользователю pass def generate_report(self): # Логика генерации отчета пользователя pass 

В этом примере класс User имеет несколько ответственностей. Он отвечает за сохранение пользователя в базе данных, отправку электронной почты и генерацию отчета. Как результат, класс становится сильно связанным и трудным для понимания и поддержки.

Давайте применим принцип единой ответственности, разделив класс User на несколько отдельных классов с единой ответственностью:

class User: def __init__(self, username, email): self.username = username self.email = email def save(self): # Логика сохранения пользователя в базе данных pass class EmailSender: def send_email(self, user, message): # Логика отправки электронной почты пользователю pass class ReportGenerator: def generate_report(self, user): # Логика генерации отчета пользователя pass 

Теперь каждый класс имеет только одну ответственность. Класс User отвечает только за данные пользователя и сохранение их в базе данных. Класс EmailSender занимается отправкой электронной почты, а класс ReportGenerator отвечает за генерацию отчета пользователя.

Это пример применения принципа единой ответственности, который помогает разделить функциональность на более мелкие и специализированные классы, упрощает понимание кода и делает его более гибким для изменений.

Визуальное представление SRP

Визуализация SRP, как одного из SOLID принципов, может быть представлена в виде диаграммы классов, где каждый класс имеет только одну ответственность. Каждый класс должен быть ответственным только за выполнение одной конкретной функции или задачи. Если класс имеет несколько ответственностей, это может указывать на нарушение SRP:

----------------------- | Класс 1 | |---------------------| | - Метод 1 | | - Метод 2 | | - Метод 3 | ----------------------- | | ----------------------- | Класс 2 | |---------------------| | - Метод 4 | | - Метод 5 | ----------------------- | | ----------------------- | Класс 3 | |---------------------| | - Метод 6 | | - Метод 7 | ----------------------- 

В этой визуализации каждый класс представлен прямоугольником, и у каждого класса есть только свои собственные методы, относящиеся только к его ответственности.

Важно отметить, что это просто концептуальное представление, и сама диаграмма может быть намного более сложной в реальном приложении. Однако основная идея заключается в том, чтобы иметь ясное представление о том, что каждый класс имеет только одну ответственность, и у классов нет перекрестных зависимостей между своими ответственностями.

Резюмируя

Принцип единой ответственности требует, чтобы классы имели только одну ответственность. Это может показаться простым, но это одна из самых важных концепций, которые необходимо понимать при разработке высококачественного программного обеспечения. Идея в том, что каждая часть кода должна отвечать только за одну задачу. Например, у класса должны быть только связанные методы и переменные для его конкретной задачи, и ничего больше.

Принцип открытого-закрытого

Теперь рассмотрим принцип открытого-закрытого. Он предполагает, что программные компоненты должны быть открыты для расширения и закрыты для любых модификаций. Другими словами, когда создаются новые функции, код следует расширять, не затрагивая его существующей структуры. Для этого разработчики могут использовать комбинацию наследования и полиморфизма. Важным преимуществом соблюдения принципа «открыто-закрыто» является снижение риска непредвиденных ошибок при внесении изменений.

SOLID примеры на Python — принцип открытого-закрытого

Принцип открытого-закрытого (Open/Closed Principle – OCP) заключается в том, что программные сущности, такие как классы, модули и функции, должны быть открыты для расширения, но закрыты для модификации. Давайте рассмотрим пример с классами Shape и AreaCalculator , где будем применять принцип OCP:

from abc import ABC, abstractmethod from math import pi class Shape(ABC): @abstractmethod def calculate_area(self): pass class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def calculate_area(self): return self.width * self.height class Circle(Shape): def __init__(self, radius): self.radius = radius def calculate_area(self): return pi * self.radius ** 2 class AreaCalculator: def calculate_total_area(self, shapes): total_area = 0 for shape in shapes: total_area += shape.calculate_area() return total_area 

В этом примере у нас есть абстрактный класс Shape , который определяет метод calculate_area() . Затем у нас есть два класса-наследника Rectangle и Circle , которые реализуют этот метод для расчета площади прямоугольника и круга соответственно.

Класс AreaCalculator отвечает за вычисление общей площади для набора фигур. Он использует SOLID принцип OCP, поскольку он открыт для расширения новыми типами фигур, но закрыт для модификации своей основной логики. Если мы хотим добавить новый тип фигуры, например, треугольник, мы можем создать новый класс Triangle , реализующий метод calculate_area() , и передать его в AreaCalculator.calculate_total_area() без изменения самого AreaCalculator :

class Triangle(Shape): def __init__(self, base, height): self.base = base self.height = height def calculate_area(self): return 0.5 * self.base * self.height # Использование shapes = [Rectangle(4, 5), Circle(3), Triangle(6, 2)] calculator = AreaCalculator() total_area = calculator.calculate_total_area(shapes) print(total_area) 

Таким образом, принцип открытого-закрытого позволяет нам добавлять новые типы фигур, расширяя функциональность, без изменения существующего кода в AreaCalculator . Это делает код более гибким и устойчивым к изменениям.

Резюмируя

Принцип открытого-закрытого гласит, что классы должны быть открыты для расширения, но закрыты для модификации. Расширение класса не должно требовать модификации существующего кода. Это гарантирует, что код может быть изменен и расширен с минимальным нарушением остальной части кодовой базы.

Принцип подстановки Барбары Лисков

Принцип подстановки Лисков — еще одна важная концепция. Он предполагает, что объекты подклассов должны быть полностью взаимозаменяемы с объектами своих родительских классов, т. е. любой дочерний класс должен вести себя точно так же, как родительский класс. Это также известно как «полиморфизм подтипов» и помогает разработчикам создавать более управляемый и надежный код.

SOLID примеры на Python — принцип подстановки Барбары Лисков

Принцип подстановки Барбары Лисков (Liskov Substitution Principle – LSP) гласит, что объекты должны быть заменяемыми экземплярами их базовых типов без нарушения корректности программы. Давайте рассмотрим пример с классами Rectangle (Прямоугольник) и Square (Квадрат), чтобы проиллюстрировать принцип LSP:

class Rectangle: def __init__(self, width, height): self.width = width self.height = height def set_width(self, width): self.width = width def set_height(self, height): self.height = height def get_area(self): return self.width * self.height class Square(Rectangle): def set_width(self, width): self.width = width self.height = width def set_height(self, height): self.width = height self.height = height 

В этом примере класс Rectangle представляет прямоугольник с методами для установки ширины и высоты, а также для получения площади.

Класс Square наследуется от Rectangle и переопределяет методы set_width() и set_height() . В случае квадрата ширина и высота всегда должны быть одинаковыми, поэтому при установке одного измерения класс Square автоматически устанавливает и другое измерение равным ему.

Однако данный пример нарушает SOLID принцип LSP. Рассмотрим следующий код:

def print_area(rectangle): rectangle.set_width(4) rectangle.set_height(5) area = rectangle.get_area() print(f"Area: ") rectangle = Rectangle(4, 5) square = Square(4) print_area(rectangle) # Результат: Area: 20 print_area(square) # Результат: Area: 16 (ожидалось 20) 

В этом примере мы вызываем функцию print_area() , которая ожидает объект типа Rectangle . Когда мы передаем rectangle , результат площади правильный (20), потому что ширина и высота были установлены независимо. Однако, когда мы передаем square, ожидаемая площадь должна быть также 20, но фактически получаем 16. Это происходит из-за изменения поведения методов set_width() и set_height() в классе Square .

Таким образом, класс Square не является полностью заменяемым объектом для класса Rectangle , нарушая принцип LSP. Чтобы исправить это, мы можем пересмотреть дизайн иерархии классов, чтобы избежать нарушения принципа LSP, или использовать интерфейсы и абстракции для достижения корректного поведения при замене объектов.

Резюмируя

Принцип подстановки Лисков гласит, что любой экземпляр подтипа должен иметь возможность заменить экземпляр своего базового типа. Это означает, что подтипы не должны нарушать поведение своих базовых типов. По сути, базовый класс и любые подклассы должны быть взаимозаменяемыми без нарушения кода.

Принцип разделения интерфейса

Принцип разделения интерфейса довольно прост и гласит, что разработчики не должны полагаться на огромные классы с множеством методов. Вместо этого разработчикам следует создавать множество меньших классов с меньшим количеством методов. Это помогает уменьшить сложность кода и упростить управление программой.

SOLID примеры на Python — принцип разделения интерфейса

Принцип разделения интерфейса (Interface Segregation Principle – ISP) гласит, что клиенты не должны зависеть от интерфейсов, которые они не используют. Вместо создания общих интерфейсов следует создавать специфические интерфейсы для конкретных клиентов. Давайте рассмотрим пример с интерфейсами для различных устройств вывода ввода:

from abc import ABC, abstractmethod class InputDevice(ABC): @abstractmethod def read_input(self): pass class OutputDevice(ABC): @abstractmethod def write_output(self, data): pass class Keyboard(InputDevice): def read_input(self): # Логика чтения ввода с клавиатуры pass class Mouse(InputDevice): def read_input(self): # Логика чтения ввода с мыши pass class Monitor(OutputDevice): def write_output(self, data): # Логика вывода данных на монитор pass class Printer(OutputDevice): def write_output(self, data): # Логика вывода данных на принтер pass 

В этом примере у нас есть абстрактные классы InputDevice и OutputDevice , представляющие интерфейсы для устройств ввода и вывода соответственно. Затем мы определяем конкретные классы Keyboard , Mouse , Monitor и Printer , которые реализуют соответствующие методы.

Применяя SOLID принцип ISP, мы разделяем интерфейсы на более специфические, чтобы клиенты могли зависеть только от интерфейсов, которые они используют. Например, если клиенту нужен только ввод с клавиатуры, он может зависеть только от интерфейса InputDevice и использовать класс Keyboard :

def process_input(device): data = device.read_input() # Логика обработки ввода keyboard = Keyboard() process_input(keyboard) 

В этом примере функция process_input() принимает объект, реализующий интерфейс InputDevice , и обрабатывает его ввод. Здесь мы передаем объект Keyboard , который соответствует интерфейсу InputDevice . Таким образом, клиент зависит только от необходимого интерфейса и не зависит от лишних методов или классов.

Таким образом, принцип разделения интерфейса позволяет создавать более специфические интерфейсы для клиентов, избегая излишней связанности и улучшая модульность и переиспользуемость кода.

Резюмируя

Принцип разделения интерфейса гласит, что классы не должны зависеть от методов, которые они не используют. Это помогает улучшить читаемость кода, а также обеспечить сильную связность. Другими словами, классы, которые зависят от других классов, не должны зависеть больше, чем им нужно для выполнения своей работы.

Принцип инверсии зависимостей

Наконец, у нас есть принцип инверсии зависимостей, который предполагает, что классы не должны напрямую полагаться на другие классы, а вместо этого должны зависеть от абстракций. Это помогает значительно снизить сложность кода и сделать программу менее подверженной ошибкам.

SOLID примеры на Python — принцип инверсии зависимостей

Принцип инверсии зависимостей (Dependency Inversion Principle – DIP) гласит, что классы должны зависеть от абстракций, а не от конкретных реализаций. Высокоуровневые модули не должны зависеть от низкоуровневых модулей. Оба типа модулей должны зависеть от абстракций. Давайте рассмотрим пример с классами Notification и EmailSender , чтобы проиллюстрировать принцип DIP:

from abc import ABC, abstractmethod class Notification(ABC): @abstractmethod def send_notification(self, message): pass class EmailSender(Notification): def send_notification(self, message): # Логика отправки уведомления по электронной почте pass class SMSNotification(Notification): def send_notification(self, message): # Логика отправки уведомления по SMS pass class User: def __init__(self, username, email): self.username = username self.email = email self.notification_service = EmailSender() def send_notification(self, message): self.notification_service.send_notification(message) 

В этом примере класс User зависит от конкретной реализации EmailSender в качестве сервиса уведомлений. Это создает прямую связь между User и EmailSender , что делает классы сложнее для тестирования и внесения изменений.

Чтобы применить SOLID принцип DIP, мы изменяем User , чтобы он зависел от абстракции Notification , а не от конкретной реализации:

class User: def __init__(self, username, email, notification_service): self.username = username self.email = email self.notification_service = notification_service def send_notification(self, message): self.notification_service.send_notification(message) 

Теперь User принимает объект notification_service , реализующий интерфейс Notification , через конструктор. Это позволяет передавать различные реализации уведомлений, такие как EmailSender или SMSNotification , без изменения самого User :

email_sender = EmailSender() user = User("John", "john@example.com", email_sender) user.send_notification("Hello!") sms_notification = SMSNotification() user = User("Jane", "jane@example.com", sms_notification) user.send_notification("Hi there!") 

Теперь User зависит от абстракции Notification и может быть легко настроен для работы с различными реализациями уведомлений. Это уменьшает связанность между классами, делает их более гибкими и легкими для тестирования и модификации.

Резюмируя

Принцип инверсии зависимостей гласит, что код должен зависеть от абстракций, а не от конкретики. Это означает, что код не должен зависеть от конкретных реализаций, а скорее от абстракции, которая затем реализуется. Это помогает повысить гибкость и повторное использование кода.

Заключение

Принципы SOLID важны для понимания любого разработчика программного обеспечения. Важно помнить, что эти принципы следует применять при разработке программного обеспечения для достижения наилучших результатов. SOLID принципы могут помочь обеспечить простоту сопровождения и расширения кода в будущем. Хорошо понимая SOLID принципы, вы сможете писать код, который будет лучше структурирован, прост в масштабировании и обслуживании.

Принципы SOLID на примерах Python 1

Примечание Рейтинг степени важности в разработке (0-10) является относительной оценкой и может различаться в зависимости от конкретной ситуации и контекста разработки.

Надеемся, что принципы SOLID на Python примерах оказались полезны и доступны для понимания.

SOLID — принципы объектно‑ориентированного программирования

SOLID — это аббревиатура пяти основных принципов проектирования в объектно‑ориентированном программировании — Single responsibility, Open-closed, Liskov substitution, Interface segregation и Dependency inversion.

В переводе на русский: принципы единственной ответственности, открытости / закрытости, подстановки Барбары Лисков, разделения интерфейса и инверсии зависимостей)

Аббревиатура SOLID была предложена Робертом Мартином, автором нескольких книг, широко известным в сообществе разработчиков. Следование принципам позволяет строить на базе ООП масштабируемые и сопровождаемые программные продукты с понятной бизнес‑логикой. Код, который написан с соблюдением принципов SOLID, проще понимать, поддерживать, расширять или изменять его функциональность.

Расшифровка:

  • Single responsibility — принцип единственной ответственности
  • Open-closed — принцип открытости / закрытости
  • Liskov substitution — принцип подстановки Барбары Лисков
  • Interface segregation — принцип разделения интерфейса
  • Dependency inversion — принцип инверсии зависимостей

Принцип единственной обязанности / ответственности (single responsibility principle / SRP) обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены исключительно на обеспечение этой обязанности. Подробнее про SRP →

Принцип открытости / закрытости (open-closed principle / OCP) декларирует, что программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения. Это означает, что эти сущности могут менять свое поведение без изменения их исходного кода. Подробнее про OCP →

Принцип подстановки Барбары Лисков (Liskov substitution principle / LSP) в формулировке Роберта Мартина: «функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом». Подробнее про LSP →

Принцип разделения интерфейса (interface segregation principle / ISP) в формулировке Роберта Мартина: «клиенты не должны зависеть от методов, которые они не используют». Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют. Подробнее про ISP →

Принцип инверсии зависимостей (dependency inversion principle / DIP) — модули верхних уровней не должны зависеть от модулей нижних уровней, а оба типа модулей должны зависеть от абстракций; сами абстракции не должны зависеть от деталей, а вот детали должны зависеть от абстракций. Подробнее про DIP →

Статья опубликована в 2019 и была обновлена в 2023 году

Тематические статьи

Принцип программирования YAGNI — «Вам это не понадобится»

Принцип заключается в том, что возможности, которые не описаны в требованиях к системе, просто не должны реализовываться.

В результате разработка ненужных функций не сжигает бюджет проекта, а разработчики не тратят оплачиваемое время на реализацию и дальнейшее сопровождение в реальности ненужного функционала. Избыточный функционал сжигает больше всего ресурсов именно на сопровождении: больше написанного кода — труднее сопровождать и выше вероятность появления «багов». И тут очень уместна поговорка: «лучший код — это ненаписанный код».

методологии разработки
веб-разработка
Статья опубликована в 2019 и обновлена в 2023 году

Принцип программирования KISS — делайте вещи проще

KISS — это принцип проектирования и программирования, при котором простота системы декларируется в качестве основной цели или ценности.

Большая часть программных систем необосновано перегружена практически ненужными функциями, что ухудшает удобство их использование конечными пользователями, а также усложняет их поддержку и развитие разработчиками. Следование принципу KISS позволяет разрабатывать решения, которые не обладают этими недостатками: они просты в использовании и в сопровождении.

методологии разработки
веб-разработка
Статья опубликована в 2019 и обновлена в 2023 году

Принцип программирования DRY — don’t repeat yourself / не повторяйте себя

Следование принципу DRY позволяет добиться высокой сопровождаемости программного продукта: внесение изменений и тестирование значительно упрощаются.

Если код не дублируется, то для изменения логики достаточно внесения исправлений всего в одном месте. Также значительно проще тестировать одну (пусть и более сложную) функцию, а не набор из десятков однотипных. При следовании DRY упрощается и повторное использование функций, вынесенных из сложных алгоритмов, что позволяет сократить время разработки и тестирования новой функциональности.

веб-разработка
методологии разработки
Статья опубликована в 2018 и обновлена в 2023 году

Стандарты кодирования — залог хорошей сопровождаемости проекта

Любая командная разработка может быть эффективной только в том случае, если участники команды имеют общее видение.

Если над проектом работает команда, а не один‑два разработчика, то обязательно должен быть стандарт оформления кода — набор правил и соглашений, которые описывают базовые принципы оформления программного кода, используемого совместно группой разработчиков.

методологии разработки
веб-разработка
Статья опубликована в 2014 и обновлена в 2023 году

Флаги функций (Feature Flags)

Флаги функций позволяют отделить развертывание функций от развертывания кода, обеспечивают возможности для A/B-тестирования и предоставляют механизм быстрого отключения проблемных функций

Принципы SOLID в картинках

Если вы знакомы с объектно-ориентированным программированием, то наверняка слышали и о принципах SOLID. Эти пять правил разработки ПО задают траекторию, по которой нужно следовать, когда пишешь программы, чтобы их проще было масштабировать и поддерживать. Они получили известность благодаря программисту Роберту Мартину.

В Сети множество отличных статей, где рассказывается о принципах SOLID, но иллюстрированных среди них мне практически не попадалось. Из-за этого таким людям со склонностью к визуальному восприятию информации – таким, как я – бывает сложно схватывать суть и не отвлекаться.

Основная цель этой статьи – лучше усвоить принципы SOLID через отрисовку иллюстраций, а также определить назначение каждого принципа. Дело в том, что некоторые из принципов кажутся похожими, но функции выполняют разные. Может получиться так, что одному принципу следуешь, а другой при этом нарушаешь, хотя с виду особой разницы между ними нет.

Чтобы проще читалось, я упоминаю здесь только классы, однако всё сказанное в статье применимо также к функциям, методам и модулям, так что имейте это в виду.

Принципы SOLID

S – Single Responsibility (Принцип единственной ответственности)

Каждый класс должен отвечать только за одну операцию.

Если класс отвечает за несколько операций сразу, вероятность возникновения багов возрастает – внося изменения, касающиеся одной из операций вы, сами того не подозревая, можете затронуть и другие.

Принцип служит для разделения типов поведения, благодаря которому ошибки, вызванные модификациями в одном поведении, не распространялись на прочие, не связанные с ним типы.

O — Open-Closed (Принцип открытости-закрытости)

Классы должны быть открыты для расширения, но закрыты для модификации.

Когда вы меняете текущее поведение класса, эти изменения сказываются на всех системах, работающих с данным классом. Если хотите, чтобы класс выполнял больше операций, то идеальный вариант – не заменять старые на новые, а добавлять новые к уже существующим.

Принцип служит для того, чтобы делать поведение класса более разнообразным, не вмешиваясь в текущие операции, которые он выполняет. Благодаря этому вы избегаете ошибок в тех фрагментах кода, где задействован этот класс.

L — Liskov Substitution (Принцип подстановки Барбары Лисков)

Если П является подтипом Т, то любые объекты типа Т, присутствующие в программе, могут заменяться объектами типа П без негативных последствий для функциональности программы.

В случаях, когда класс-потомок не способен выполнять те же действия, что и класс-родитель, возникает риск появления ошибок.

Если у вас имеется класс и вы создаете на его базе другой класс, исходный класс становится родителем, а новый – его потомком. Класс-потомок должен производить такие же операции, как и класс-родитель. Это называется наследственностью.

Необходимо, чтобы класс-потомок был способен обрабатывать те же запросы, что и родитель, и выдавать тот же результат. Или же результат может отличаться, но при этом относиться к тому же типу. На картинке это показано так: класс-родитель подаёт кофе (в любых видах), значит, для класса-потомка приемлемо подавать капучино (разновидность кофе), но неприемлемо подавать воду.

Если класс-потомок не удовлетворяет этим требованиям, значит, он слишком сильно отличается от родителя и нарушает принцип.

Принцип служит для того, чтобы обеспечить постоянство: класс-родитель и класс-потомок могут использоваться одинаковым образом без нарушения работы программы.

I — Interface Segregation (Принцип разделения интерфейсов)

Не следует ставить клиент в зависимость от методов, которые он не использует.

Когда классу приходится производить действия, не несущие никакой реальной пользы, это выливается в пустую трату ресурса, а в случае, если класс выполнять эти действия не способен, ведёт к возникновению багов.

Класс должен производить только те операции, которые необходимы для осуществления его функций. Все другие действия следует либо удалить совсем, либо переместить, если есть вероятность, что они понадобятся другому классу в будущем.

Принцип служит для того, чтобы раздробить единый набор действий на ряд наборов поменьше – таким образом, каждый класс делает то, что от него действительно требуется, и ничего больше.

D — Dependency Inversion (Принцип инверсии зависимостей)

Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те, и другие должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Для начала объясню термины, которые здесь применяются, простыми словами.

Модули (или классы) верхнего уровня = классы, которые выполняют операцию при помощи инструмента
Модули (или классы) нижнего уровня = инструменты, которые нужны для выполнения операций
Абстракции – представляют интерфейс, соединяющий два класса
Детали = специфические характеристики работы инструмента

Согласно данному принципу, класс не должен соединяться с инструментом, который применяет для выполнения операции. Вместо этого он должен быть соединён с интерфейсом, который поможет установить связь между инструментом и классом.

Кроме того, принцип гласит, что ни интерфейс, ни класс, не обязаны вникать в специфику работы инструмента. Напротив, это инструмент должен подходить под требования интерфейса.

Этот принцип служит для того, чтобы устранить зависимость классов верхнего уровня от классов нижнего уровня за счёт введения интерфейсов.

Обобщая сказанное

Мы разобрали все пять принципов и сформулировали для каждого назначение. Всё это призвано помочь вам писать код, который можно модифицировать, расширять и тестировать с минимумом проблем. Спасибо, что прочитали; надеюсь, вы получили не меньше удовольствия, чем я в процессе работы над статьёй.

  • объектно-ориентированное по
  • принципы разработки
  • solid
  • Блог компании Productivity Inside
  • Совершенный код

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *