С какими архитектурами работал
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Архитектурные подходы и паттерны в моей практике
В моей 10+ летней карьере я работал с различными архитектурными подходами, адаптируя их под требования проектов. Расскажу о наиболее значимых.
1. Монолитная архитектура (Monolithic)
Описание: Все компоненты в одном приложении, одна БД, один deployment.
PresentationLayer
↓
ApplicationLayer
↓
DomainLayer
↓
InfrastructureLayer
↓
Database (Single)
Когда использовал: На начальных этапах проектов, когда требования ещё не стабильны.
Пример проекта:
- Spring Boot приложение
- Single JAR с контроллерами, сервисами, репозиториями
- PostgreSQL с одной схемой
- JPA/Hibernate для ORM
Преимущества:
- Простота развёртывания (один JAR)
- Легче отлаживать (всё в одном процессе)
- Проще тестировать (end-to-end тесты)
Недостатки:
- Масштабируемость ограничена (вертикальная)
- Сложно масштабировать части отдельно
- Большой размер (долгая сборка, развёртывание)
- Один баг может положить всё приложение
2. Микросервисная архитектура (Microservices)
Описание: Множество независимых сервисов, каждый со своей БД и API.
API Gateway
↓
┌────────────┬──────────────┬──────────────┐
│ User │ Order │ Payment │
│ Service │ Service │ Service │
├────────────┼──────────────┼──────────────┤
│ User DB │ Order DB │ Payment DB │
└────────────┴──────────────┴──────────────┘
Message Queue (RabbitMQ, Kafka)
Service Discovery (Eureka, Consul)
API Gateway (Spring Cloud Gateway)
Когда использовал: В крупных проектах с разными требованиями масштабирования.
Пример архитектуры:
// User Service
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
@PostMapping
public UserDTO create(@RequestBody CreateUserRequest req) {
return userService.create(req);
}
}
// Order Service
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
@PostMapping
public OrderDTO create(@RequestBody CreateOrderRequest req) {
// Вызов User Service
UserDTO user = userServiceClient.getUser(req.getUserId());
return orderService.create(req, user);
}
}
// Service discovery
@EnableEurekaClient
@SpringBootApplication
public class OrderServiceApp { }
// Async communication
@Service
public class OrderEventProducer {
@Autowired
private RabbitTemplate template;
public void publishOrderCreated(Order order) {
template.convertAndSend("orders.exchange",
"order.created", order);
}
}
Преимущества:
- Независимое масштабирование (высоконагруженный сервис масштабируется отдельно)
- Независимое развёртывание (обновляю User Service без downtime Order Service)
- Гибкость технологий (один на Java, другой на Go)
- Отказоустойчивость (падение одного сервиса не влияет на другие)
Недостатки:
- Сложность (distributed transactions, eventual consistency)
- Сетевая задержка (service-to-service calls)
- Операционная сложность (много сервисов управлять)
- Distributed debugging (сложнее отлаживать)
3. Event-Driven архитектура
Описание: Компоненты взаимодействуют через события, асинхронно.
User Service Order Service Payment Service
↓ ↓ ↓
(User Created Event) → Message Bus (Kafka) → (Listens and Process)
Пример:
// Event
public record UserCreatedEvent(
UUID userId,
String email,
LocalDateTime createdAt
) {}
// Event Publisher
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createUser(CreateUserRequest req) {
User user = new User(req);
userRepository.save(user);
// Publish event
eventPublisher.publishEvent(
new UserCreatedEvent(user.getId(), user.getEmail(), LocalDateTime.now())
);
}
}
// Event Listener
@Service
public class WelcomeEmailService {
@EventListener
public void onUserCreated(UserCreatedEvent event) {
// Send welcome email asynchronously
emailService.sendWelcome(event.email());
}
}
// Kafka-based async
@Component
public class OrderCreatedEventListener {
@KafkaListener(topics = "orders.created")
public void onOrderCreated(OrderCreatedEvent event) {
paymentService.processPayment(event);
}
}
Преимущества:
- Слабая связанность (сервисы не знают друг о друге)
- Асинхронность (не блокирует основной процесс)
- Масштабируемость (легко добавить новых слушателей)
Недостатки:
- Сложность отладки (асинхронные потоки)
- Eventual consistency (данные временно несогласованы)
- Гарантии доставки (что если сообщение потеряется?)
4. Layered (N-tier) архитектура
Классическая слойная архитектура:
┌────────────────────────────┐
│ Presentation Layer │ (Controllers, REST endpoints)
├────────────────────────────┤
│ Application Layer │ (DTOs, Mappers, Use Cases)
├────────────────────────────┤
│ Domain Layer │ (Entities, Business Logic)
├────────────────────────────┤
│ Infrastructure Layer │ (Repositories, Database, External APIs)
└────────────────────────────┘
Пример:
// Presentation
@RestController
public class UserController {
@Autowired private UserService service;
@PostMapping("/api/v1/users")
public UserDTO create(@RequestBody CreateUserRequest req) {
return service.create(req);
}
}
// Application (Service)
@Service
public class UserService {
@Autowired private UserRepository repo;
public UserDTO create(CreateUserRequest req) {
User user = new User(req);
user = repo.save(user);
return new UserDTO(user); // DTO
}
}
// Domain (Entity)
@Entity
@Table(name = "users")
public class User {
@Id @GeneratedValue
private Long id;
private String email;
public void updateProfile(String newName) {
// Business logic
this.name = newName;
}
}
// Infrastructure (Repository)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
5. Domain-Driven Design (DDD)
Описание: Проектирование вокруг бизнес-логики (Domain), а не технологии.
Presentation (Controllers)
↓
Application Services (Use Cases)
↓
Domain Model (Entities, Value Objects, Aggregates, Services)
↓
Infrastructure (Repositories, External APIs)
Пример DDD:
// Value Object (бизнес концепция)
public class Email {
private final String value;
public Email(String value) {
if (!value.contains("@")) {
throw new InvalidEmailException();
}
this.value = value;
}
}
// Aggregate (группа сущностей)
@Entity
public class Order {
@EmbeddedId
private OrderId id;
private CustomerId customerId;
@OneToMany(cascade = CascadeType.ALL)
private List<OrderLine> lines;
// Business methods
public void addLine(Product product, int quantity) {
if (quantity <= 0) {
throw new InvalidQuantityException();
}
lines.add(new OrderLine(product, quantity));
}
public Money getTotal() {
return lines.stream()
.map(OrderLine::getSubtotal)
.reduce(Money.ZERO, Money::add);
}
}
// Repository (abstract interface)
public interface OrderRepository {
void save(Order order);
Order findById(OrderId id);
}
// Domain Service
@Service
public class OrderDomainService {
public void placeOrder(Order order, Customer customer) {
// Complex business logic
order.validate();
customer.validatePaymentMethod();
order.place(customer);
}
}
6. CQRS (Command Query Responsibility Segregation)
Описание: Разделение операций чтения (Query) и записи (Command).
Commands (write-side) Queries (read-side)
↓ ↓
Event Sourcing Read Models (optimized)
↓ ↓
┌───────────────────────────────────┐
│ Event Store │
└───────────────────────────────────┘
Пример:
// Command
public class CreateOrderCommand {
public final UUID orderId;
public final UUID customerId;
public final List<LineItem> items;
}
// Command Handler
@Service
public class CreateOrderCommandHandler {
public void handle(CreateOrderCommand cmd) {
Order order = new Order(cmd.orderId, cmd.customerId);
// Event sourcing: save events
eventStore.append(order.getId(), order.getEvents());
}
}
// Query
public class GetOrderQuery {
public final UUID orderId;
}
// Query Handler (read from read model)
@Service
public class GetOrderQueryHandler {
@Autowired
private OrderReadRepository readRepo;
public OrderReadModel handle(GetOrderQuery query) {
return readRepo.findById(query.orderId);
}
}
Выводы по архитектурам
| Архитектура | Когда использовать | Сложность |
|---|---|---|
| Monolithic | MVP, стартапы | Low |
| Microservices | Масштабируемые системы | Very High |
| Event-Driven | Real-time, async systems | High |
| Layered | Средние CRUD приложения | Medium |
| DDD | Complex business logic | High |
| CQRS | High-load read/write | Very High |
Мой опыт: Начинаю с монолита, переходил на микросервисы по мере роста. DDD помогает когда бизнес-логика сложная. Event-driven для real-time требований.