Skip to content

Посты

Кодификация секретного соуса

16 сентября 2019 г. • 5 мин чтения

Кодификация секретного соуса

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

Подождите. Что такое кодификация? Терпение, мой друг, мы до этого дойдем.

Сначала давайте выдвинем гипотезу:

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

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

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

В бухгалтерском учете соотношение цены (P) к прибыли (E) (P/E Ratio) является показателем прибыли компании. Высокое соотношение P/E предполагает высокий рост прибыли в будущем. Соотношение P/E рассчитывается путем деления рыночной стоимости акции (цена акции) на прибыль на акцию (прибыль – дивиденды / количество акций в обращении).

Простая и, я утверждаю, наивная реализация:

public class Metric
{
    public string Name { get; set; }
    public decimal Value {get; set}
    public int Order {get; set;}
}
public class AccountingSummary
{
    public Metric[] GetMetrics(decimal price, decimal earnings)
    {
        var priceEarningsRatio = price/earnings;
        
        var priceEarningsRatioMetric = new Metric 
        {
            Name = "P/E Ratio",
            Value = priceEarningsRatio,
            Order = 0
        }
        return new [] {priceEarningsRatioMetric};
    }
}

Если это используется только в одном месте, то это нормально. А что если вы используете соотношение P/E в других областях?

Например, здесь в PriceEarnings.cs

var priceEarningsRatio = price/earnings;

И здесь в AccountSummary.cs

var priceEarningsRatio = price/earnings;

И вот здесь в StockSummary.cs

var priceEarningsRatio = price/earnings;

Соотношение P/E является основой этого приложения, но то, как оно реализовано, жестко закодировано в различных местах, делает важность соотношения P/E потерянной в море кода. Это просто еще одно дерево в лесу.

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

Часто тестировщики предполагают, что если что-то работает в одной области, то это правильно во всех областях. Почему бы приложению не использовать один и тот же код для генерации соотношения P/E для всего приложения? Разве не в этом суть объектно-ориентированного программирования?

Я могу представить, как подобная ошибка попадает в продакшн и не обнаруживается до визита вашего руководителя, который требует знать, почему расчеты P/E соотношения SEC отличаются от того, что подала компания. Это не очень хорошее место для нахождения.

Давайте пересмотрим нашу реализацию соотношения P/E и посмотрим, как мы можем улучшить нашу первую попытку.

В бухгалтерских системах формулы — это важная вещь, давайте создадим структуру вокруг формул, добавив интерфейс:

public interface IFormula
{
    decimal Calculate<T>(T model);
}

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

Вот наше улучшенное соотношение P/E после реализации нашего интерфейса:

Мы добавили PriceEarningsModel для передачи необходимых данных в наш метод Calculate.

public class PriceEarningsModel
{
    public decimal Price {get; set;}
    public decimal Earnings {get; set;}
}

Используя наш PriceEarningsModel, мы создали реализацию интерфейса IFormula для соотношения P/E.

public class PriceEarningsRatioFormula : IFormula
{
    public decimal Calculate<PriceEarningsModel>(PriceEarningsModel model)
    {
        return model.Price / model.Earnings;
    }
}

Теперь мы кодифицировали соотношение P/E. Это концепция первого класса в нашем приложении. Мы можем использовать ее где угодно. Она тестируема, и изменение влияет на все приложение.

Напоминаю, вот реализация, с которой мы начали:

public class Metric
{
    public string Name { get; set; }
    public decimal Value {get; set}
    public int Order {get; set;}
}
public class AccountingSummary
{
    public Metric[] GetMetrics(decimal price, decimal earnings)
    {
        var priceEarningsRatio = price/earnings;
        
        var priceEarningsRatioMetric = new Metric 
        {
            Name = "P/E Ratio",
            Value = priceEarningsRatio,
            Order = 0
        }
        return new [] {priceEarningsRatioMetric};
    }
}

Она проста и выполняет свою работу. Проблема в том, что соотношение P/E, которое является основной концепцией в нашем бухгалтерском приложении, не выделяется. Инженеры, не знакомые с приложением или бизнес-доменом, не поймут его важность.

Наша улучшенная реализация использует наш новый класс соотношения P/E. Мы внедряем класс PriceEarningsRatioFormula в наш класс AccountSummary.

Мы заменяем наше жестко закодированное соотношение P/E нашим новым классом PriceEarningsRatioFormula.

public class AccountingSummary
{
    private PriceEarningsRatioFormula _peRatio;
    
    public AccountingSummary(PriceEarningsRatioFormula peRatio)
    {
        _peRatio = peRatio;
    }
    
    public Metric[] GetMetrics(decimal price, decimal earnings)
    {
        var priceEarningsRatio = _peRatio.Calculate(new PriceEarningsModel 
        { 
            Price = price, 
            Earnings = earnings
        });
        
        var priceEarningsRatioMetric = new Metric 
        {
            Name = "P/E Ratio",
            Value = priceEarningsRatio,
            Order = 0
        }
        return new [] {priceEarningsRatioMetric};
    }
}

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

Во-первых, мы получаем возможность изменить соотношение P/E для всего приложения. У нас также есть единая реализация для отладки в случае возникновения дефектов.

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

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

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

Автор: Чак Конвей специализируется на разработке программного обеспечения и генеративном ИИ. Свяжитесь с ним в социальных сетях: X (@chuckconway) или посетите его на YouTube.

↑ Наверх

Вам также может понравиться