digital-garden/dev/architecture/Связность.md

106 lines
9.8 KiB
Markdown
Raw Normal View History

2024-11-24 20:43:38 +03:00
---
aliases:
- Cohesion
- связности
2024-11-25 10:05:47 +03:00
- связность
2024-11-24 20:43:38 +03:00
tags:
- maturity/🌱
date: 2024-11-24
---
Связность (cohesion) — это мера того, насколько функции внутри одного модуля связаны друг с другом и работают вместе для выполнения конкретной задачи. Высокая связность означает, что модуль фокусируется на одной задаче и все его компоненты направлены на достижение этой цели. Например, модуль обработки платежей включает только функции, связанные с платежами, что делает его логически целостным.;
Примеры применения
- [[../../../../wiki/zero/00 Микросервисная архитектура|Микросервисная архитектура]]. Сервис с высокой связностью сосредоточен на конкретной бизнес-задаче, например, управлении пользователями или платежами. Это позволяет эффективно выполнять свою функцию и поддерживать независимость сервиса. Например, сервис управления пользователями может добавлять, обновлять и удалять пользователей без взаимодействия с другими сервисами, что делает его легким в поддержке.
- **Пакеты в монолитной системе**. В монолитных системах правильное разделение на пакеты может значительно улучшить связность. Например, отдельный пакет для работы с базой данных должен иметь высокую связность внутри себя, чтобы все его компоненты были направлены на работу с данными.
- Классы в [[ООП|объектно-ориентированном программировании]]. Классы с высокой связностью содержат методы, направленные на выполнение одной конкретной задачи, что упрощает их поддержку и тестирование.
**Преимущества высокой связности**
- **Повышение переиспользуемости**. Высокая связность модулей позволяет их легче переиспользовать, так как все необходимые функции сосредоточены в одном месте.
- **Упрощение модификации**. Модуль с высокой связностью легче модифицировать, так как все его компоненты работают вместе для достижения одной цели.
**Антипаттерны и частые ошибки**
- **Божественный объект (God Object)**. Это пример нарушения принципа высокой связности, когда один класс или модуль берет на себя слишком много обязанностей и имеет зависимости на многие другие части системы. Такой дизайн затрудняет понимание и модификацию кода.
**Рекомендации**
- [[Single Responsibility Principle|Принцип единственной ответственности]] (SRP). Каждый модуль или класс должен иметь одну четко определенную ответственность, что повышает связность и облегчает поддержку кода.
- Регулярный [[../efficiency/Рефакторинг кода|рефакторинг]]. Постоянное улучшение кода помогает повысить связность внутри модулей, устраняя излишние обязанности и сосредоточивая функции на одной задаче.
## Антипример микросервисной архитектуры
Рассмотрим пример интернет-магазина, в котором реализовано три разных вида доставки: доставка в пункт выдачи, доставка курьером и доставка в магазин. Для каждой из этих задач были созданы отдельные микросервисы: `PickupPointService`, `CourierDeliveryService` и `StoreDeliveryService`.
На первый взгляд, это выглядит как хороший подход, однако на практике каждое из этих решений может развиваться в разных направлениях и иметь различные бизнес-требования. В будущем может оказаться, что добавление новых функций в один из сервисов требует изменения логики и усложняет взаимодействие между сервисами, что может привести к дублированию бизнес-логики в нескольких местах.
Кроме того, чтобы посчитать время доставки, каждый из этих сервисов должен знать и запросить время комплектации заказа. Это означает, что одно и то же время комплектации будет запрашиваться несколько раз разными сервисами, что приводит к избыточным обращениям и усложняет координацию между сервисами.
В таких случаях объединение этой логики могло бы уменьшить сложность и избежать проблем с несогласованностью изменений в разных сервисах. Это пример того, когда дублирование и разделение по типу доставки могут изначально выглядеть оправданными, но на практике могут усложнить поддержку системы.
## Примеры кода
Высокая связность (Good Cohesion)
```java
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(String name, String email) {
// Логика создания пользователя
User user = new User(name, email);
return userRepository.save(user);
}
public User getUserById(Long id) {
// Логика получения пользователя по ID
return userRepository.findById(id);
}
}
```
В этом примере класс `UserService` имеет высокую связность, так как все его методы связаны с управлением пользователями и взаимодействием с `UserRepository`. Высокая связность делает класс легче поддерживаемым, поскольку все функции находятся в одном месте, что упрощает внесение изменений и тестирование, а также способствует лучшей организации кода и уменьшению сложности.
Низкая связность (Bad Cohesion)
```java
public class UserUtility {
private final UserRepository userRepository;
private final EmailService emailService;
public UserUtility(UserRepository userRepository, EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
public User createUser(String name, String email) {
// Логика создания пользователя
User user = new User(name, email);
return userRepository.save(user);
}
public void sendWelcomeEmail(User user) {
// Логика отправки приветственного письма
emailService.sendEmail(user.getEmail(), "Welcome!");
}
public void deleteUser(Long id) {
// Логика удаления пользователя
userRepository.deleteById(id);
}
}
```
В этом примере класс `UserUtility` имеет низкую связность, так как в нем сочетаются разные обязанности: управление пользователями, отправка email, удаление пользователей. Такой класс сложно поддерживать и тестировать, так как его методы не связаны одной конкретной задачей.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-11-24]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->