Skip to content

Посты

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

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

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

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

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

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

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

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

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

В бухгалтерском учете коэффициент цена (P) к прибыли (E) (коэффициент P/E) — это измерение прибыли компании. Высокий коэффициент 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 для всего приложения? Разве это не суть объектно-ориентированного программирования?

Я могу представить себе ошибку, которая попадает в production и не обнаруживается до визита вашего руководителя, который требует узнать, почему расчеты коэффициента 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 в приложении. Когда новый инженер присоединится к команде, он будет знать, что формулы являются существенными для приложения и бизнес-домена.

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

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

Автор: Chuck Conway — инженер AI с почти 30-летним опытом разработки программного обеспечения. Он создает практические системы AI — конвейеры контента, агенты инфраструктуры и инструменты, которые решают реальные проблемы — и делится тем, что он узнает на этом пути. Свяжитесь с ним в социальных сетях: X (@chuckconway) или посетите его на YouTube и на SubStack.

↑ Вернуться в начало

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