Skip to content

Beiträge

Die Geheimzutat kodifizieren

16. September 2019 • 5 Min. Lesezeit

Die Geheimzutat kodifizieren

Jede Anwendung hat ihre Geheimzutat, ihren Grund für die Existenz. Die Kodifizierung der Geheimzutat ist entscheidend für das Schreiben wartbarer und erfolgreicher Anwendungen.

Moment. Was ist Kodifizierung? Geduld, mein Freund, wir kommen dorthin.

Lassen Sie uns zunächst eine Hypothese aufstellen:

Sie wurden gerade zum Lead Software Engineer befördert (Herzlichen Glückwunsch!). Die erste Aufgabe Ihres CEOs ist die Entwicklung eines neuen Produkts für das Unternehmen. Es ist eine von Grund auf neu entwickelte Buchhaltungsanwendung. Die Führungskräfte sind der Meinung, dass eine maßgeschneiderte Buchhaltungslösung ihnen einen Vorteil gegenüber der Konkurrenz verschafft.

Ein paar Monate sind vergangen, die meisten übergreifenden Belange sind entwickelt (hurra!). Das Team konzentriert sich nun auf das Herzstück der Anwendung: die Geschäftsdomäne (die Geheimzutat). Hier beginnt die Kodifizierung der Geheimzutat.

Kodifizierung bedeutet, einem wesentlichen Konzept in der Geschäftsdomäne eine Struktur zu geben.

In der Buchhaltung ist das Kurs-Gewinn-Verhältnis (KGV) ein Maß für die Gewinne eines Unternehmens. Ein hohes KGV deutet auf ein hohes Gewinnwachstum in der Zukunft hin. Das KGV wird berechnet, indem der Marktwert pro Aktie (Aktienkurs) durch den Gewinn pro Aktie (Gewinn – Dividenden / Anzahl der ausstehenden Aktien) geteilt wird.

Eine einfache und, wie ich behaupte, naive Implementierung:

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};
    }
}

Wenn dies nur an einer Stelle verwendet wird, ist das in Ordnung. Was ist, wenn Sie das KGV in anderen Bereichen verwenden?

Wie hier in PriceEarnings.cs

var priceEarningsRatio = price/earnings;

Und hier in AccountSummary.cs

var priceEarningsRatio = price/earnings;

Und hier drüben in StockSummary.cs

var priceEarningsRatio = price/earnings;

Das KGV ist zentral für diese Anwendung, aber wie es implementiert ist, fest codiert an verschiedenen Stellen, lässt die Bedeutung des KGV in einem Meer von Code untergehen. Es ist nur ein weiterer Baum im Wald.

Sie öffnen auch das Risiko, das Verhältnis an einer Stelle zu ändern, aber nicht an der anderen. Dies kann nachgelagerte Berechnungen durcheinanderbringen. Diese Art von Fehlern sind notorisch schwer zu finden.

Oft nehmen Tester an, dass wenn es in einem Bereich funktioniert, es in allen Bereichen korrekt ist. Warum sollte die Anwendung nicht denselben Code verwenden, um das KGV für die gesamte Anwendung zu generieren? Ist das nicht der Sinn der objektorientierten Programmierung?

Ich kann mir vorstellen, dass ein solcher Fehler in die Produktion gelangt und erst bei einem Besuch Ihres Vorgesetzten entdeckt wird, der wissen will, warum sich die KGV-Berechnungen der SEC von dem unterscheiden, was das Unternehmen eingereicht hat. Das ist keine gute Position.

Lassen Sie uns unsere KGV-Implementierung noch einmal betrachten und sehen, wie wir unseren ersten Versuch verbessern können.

In Buchhaltungssystemen sind Formeln wichtig, lassen Sie uns Struktur um Formeln schaffen, indem wir ein Interface hinzufügen:

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

Jede Formel wird nun mit diesem Interface implementiert, was uns Konsistenz und Vorhersagbarkeit gibt.

Hier ist unser verbessertes KGV nach der Implementierung unseres Interfaces:

Wir haben ein PriceEarningsModel hinzugefügt, um die benötigten Daten in unsere Calculate-Methode zu übergeben.

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

Mit unserem PriceEarningsModel haben wir eine Implementierung des IFormula-Interfaces für das KGV erstellt.

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

Wir haben nun das KGV kodifiziert. Es ist ein erstklassiges Konzept in unserer Anwendung. Wir können es überall verwenden. Es ist testbar, und eine Änderung wirkt sich auf die gesamte Anwendung aus.

Zur Erinnerung, hier ist die Implementierung, mit der wir begonnen haben:

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};
    }
}

Es ist einfach und erledigt die Arbeit. Das Problem ist, dass das KGV, das ein Kernkonzept in unserer Buchhaltungsanwendung ist, nicht hervorsticht. Ingenieure, die mit der Anwendung oder der Geschäftsdomäne nicht vertraut sind, werden seine Bedeutung nicht verstehen.

Unsere verbesserte Implementierung verwendet unsere neue KGV-Klasse. Wir injizieren die PriceEarningsRatioFormula-Klasse in unsere AccountSummary-Klasse.

Wir ersetzen unser fest codiertes KGV durch unsere neue PriceEarningsRatioFormula-Klasse.

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};
    }
}

Man könnte argumentieren, dass es mit der PriceEarningsRationFormula etwas mehr Aufwand gibt als bei der vorherigen Implementierung, und ich würde zustimmen. Es gibt etwas mehr Zeremonie, aber die Vorteile sind die kleine Zunahme an Code und Zeremonie durchaus wert.

Erstens gewinnen wir die Fähigkeit, das KGV für die gesamte Anwendung zu ändern. Wir haben auch eine einzige Implementierung zum Debuggen, falls Defekte auftreten.

Schließlich haben wir das Konzept der PriceEarningsRatioFormula in der Anwendung kodifiziert. Wenn ein neuer Ingenieur dem Team beitritt, wird er wissen, dass Formeln für die Anwendung und die Geschäftsdomäne wesentlich sind.

Es gibt andere Methoden der Kodifizierung (Kapselung) der Domäne, wie Microservices und Assemblies. Jeder Ansatz hat seine Vor- und Nachteile, Sie und Ihr Team müssen entscheiden, was für Ihre Anwendung am besten ist.

Die Einbettung wichtiger Domänenkonzepte in Klassen und Interfaces schafft wiederverwendbare Komponenten und konzeptuelle Grenzen. Dies macht eine Anwendung leichter verständlich, reduziert Defekte und senkt die Barrieren für das Onboarding neuer Ingenieure.

Autor: Chuck Conway ist spezialisiert auf Software-Engineering und Generative KI. Verbinden Sie sich mit ihm in den sozialen Medien: X (@chuckconway) oder besuchen Sie ihn auf YouTube.

↑ Zurück nach oben

Das könnte dir auch gefallen