← Назад к вопросам

С какими архитектурами работал

1.0 Junior🔥 291 комментариев
#REST API и микросервисы#Soft Skills и карьера

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Архитектурные подходы и паттерны в моей практике

В моей 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);
    }
}

Выводы по архитектурам

АрхитектураКогда использоватьСложность
MonolithicMVP, стартапыLow
MicroservicesМасштабируемые системыVery High
Event-DrivenReal-time, async systemsHigh
LayeredСредние CRUD приложенияMedium
DDDComplex business logicHigh
CQRSHigh-load read/writeVery High

Мой опыт: Начинаю с монолита, переходил на микросервисы по мере роста. DDD помогает когда бизнес-логика сложная. Event-driven для real-time требований.