Применение шаблона Удавка для разложения устаревшей системы на микросервисы Часть 1 – CodesCode.

Изучите предметно-специфические примеры разбиения унаследованной системы на микросервисную архитектуру для POS / электронной системы торговли.

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

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

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

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

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

Обзор унаследованной системы продуктового магазина

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

  1. Сервис корзины покупок
  2. Сервис обработки платежей с возможностью возврата
  3. Сервис управления инвентарем: количество продукта должно уменьшаться при продаже и увеличиваться при возврате заказа.

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

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

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

Теперь рассмотрим основные модели классов и операции, необходимые для каждого сервиса.

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

Сервис корзины покупок

public class Product{    public Guid Id { get; set; }    public string Name { get; set; }    public decimal Price { get; set; }    public int StockQuantity { get; set; }    public Category ProductCategory { get; set; }}public class Category{    public Guid Id { get; set; }    public string Name { get; set; }}public class ShoppingCartItem{    public Product Product { get; set; }    public int Quantity { get; set; }}public class ShoppingCart{    public Guid Id { get; set; }    public List<ShoppingCartItem> Items { get; set; }    public Customer Customer { get; set; }    public DateTime CreatedAt { get; set; }}public class Order{    public Guid Id { get; set; }    public List<ShoppingCartItem> Items { get; set; }    public Customer Customer { get; set; }    public decimal TotalAmount { get; set; }    public DateTime CreatedAt { get; set; }}

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

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

public class BillingService : IBillingService{	public Order CreateOrder(Customer customer, List<ShoppingCartItem> items)    {        return new Order        {            Id = Guid.NewGuid(), //Создать новый идентификатор заказа            Items = items,            Customer = customer,            TotalAmount = CalculateTotalAmount(items),            CreatedAt = DateTime.Now        };    }    private decimal CalculateTotalAmount(List<ShoppingCartItem> items)    {        decimal totalAmount = 0;        foreach (var item in items)        {            totalAmount += item.Product.Price * item.Quantity;        }        return totalAmount;    }}

В идеале в общем проекте вам нужно создать интерфейс для IBillingService. Он должен выглядеть следующим образом:

public interface IBillingService{   public Order CreateOrder(Customer customer, List<ShoppingCartItem> items);}

Теперь вы можете выполнить юнит-тестирование операции CreateOrder.

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

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

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

 Служба обработки платежей

public class Payment{    public Guid Id { get; set; }    public decimal Amount { get; set; }    public PaymentStatus Status { get; set; }    public DateTime PaymentDate { get; set; }    public PaymentMethod PaymentMethod { get; set; }}public enum PaymentStatus{    Pending,    Approved,    Declined,}public enum PaymentMethod{    CreditCard,    DebitCard,    PayPal,}public class Receipt{    public Guid Id { get; set; }    public Order Order { get; set; }    public decimal TotalAmount { get; set; }    public DateTime IssuedDate { get; set; }}public class PaymentService : IPaymentService{    private PaymentGateway paymentGateway;    public PaymentService()    {        this.paymentGateway = new PaymentGateway();    }    public Payment MakePayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails)    {        // В реальной системе вы обработали бы детали платежа и проверили их перед вызовом платежного шлюза.        return paymentGateway.ProcessPayment(amount, paymentMethod, paymentDetails);    }}public class ReceiptService : IReceiptService{    public Receipt GenerateReceipt(Order order)    {        var receipt = new Receipt        {            Id = Guid.NewGuid(),            Order = order,            TotalAmount = order.TotalAmount,            IssuedDate = DateTime.Now        };        return receipt;    }}

В этом проекте службы вам нужно создать и реализовать следующие интерфейсы:

public Interface IPaymentService{    public Payment MakePayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails); }public Interface IReceiptService{    public Receipt GenerateReceipt(Order order);}public Interface IPaymentRepository{   public Payment ProcessPayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails)} public class PaymentGateway : IPaymentRepository{    public Payment ProcessPayment(decimal amount, PaymentMethod paymentMethod, string paymentDetails)    {        // Упрощенная логика обработки платежей для демонстрации        var payment = new Payment        {            Id = Guid.NewGuid(),            Amount = amount,            Status = PaymentStatus.Pending,            PaymentDate = DateTime.Now,            PaymentMethod = paymentMethod        };        // В реальной системе вы бы подключились к платежному шлюзу и обработали платеж, соответственно обновив статус платежа.        // Например, вы можете использовать внешнюю библиотеку обработки платежей или API для обработки транзакции.        // Здесь симулируется успешный платеж для демонстрационных целей.        payment.Status = PaymentStatus.Approved;        return payment;    }}

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

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

Служба управления запасами

public class Product{    public Guid Id { get; set; }    public string Name { get; set; }    public decimal Price { get; set; }    public int QuantityInStock { get; set; }    public Category ProductCategory { get; set; }}public class Category{    public Guid Id { get; set; }    public string Name { get; set; }}public class Supplier{    public Guid Id { get; set; }    public string Name { get; set; }    public string ContactEmail { get; set; }}public class PurchaseOrder{    public Guid Id { get; set; }    public Supplier Supplier { get; set; }    public List<PurchaseOrderItem> Items { get; set; }    public DateTime OrderDate { get; set; }    public bool IsReceived { get; set; }}public class PurchaseOrderItem{    public Product Product { get; set; }    public int QuantityOrdered { get; set; }    public decimal UnitPrice { get; set; }}public interface IInventoryManagementService{    void ReceivePurchaseOrder(PurchaseOrder purchaseOrder);    void SellProduct(Product product, int quantitySold);}public class InventoryManagementService : IInventoryManagementService{    public void ReceivePurchaseOrder(PurchaseOrder purchaseOrder)    {        if (purchaseOrder.IsReceived)        {            throw new InvalidOperationException("Заказ уже размещен.");        }        foreach (var item in purchaseOrder.Items)        {            item.Product.QuantityInStock += item.QuantityOrdered;        }        purchaseOrder.IsReceived = true;    }    public void SellProduct(Product product, int quantitySold)    {        if (product.QuantityInStock < quantitySold)        {            throw new InvalidOperationException("Товара нет в наличии.");        }        product.QuantityInStock -= quantitySold;    }}

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

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


Leave a Reply

Your email address will not be published. Required fields are marked *