Upload
ying
View
999
Download
0
Embed Size (px)
DESCRIPTION
Experience report on applying DDD to discover and refactor domain fundamental value objects
Citation preview
So We Thought We Knew Money
Ying Hu Sam [email protected] [email protected]
Custom House Global Foreign Exchange
Outline
• Background• The problem in the system• Distilling the domain model and the discovery
of the value objects• Refactoring, differences before and after• Compromises and pitfalls
The Domain
• Foreign exchange is all we do
In our system…
• Variable names of primitive data types public class Contract { decimal tradingRate; bool isRateDirect; string tradeCurrency; decimal tradeAmount; string settlementCurrency; decimal settlementAmount; decimal Markup; … …
decimal GetRate(string unitCurrency, string referenceCurrency);
• Method names, parameters, return types
Implicit Domain ConceptPublic Class Contract{ decimal CalculateSettlementAmount(
bool isRateDirect,decimal tradeAmount,decimal tradingRate)
{if (isRateDirect)
return tradeAmount * tradingRate;else
return tradeAmount / tradingRate; }
decimal settlementAmount = CalculateSettlementAmount(true, 200m, 1.12m);
//……}
Public Class Contract{ decimal ApplyMarkup( decimal rate, decimal markup, bool isPercentageMarkup, bool isBuyMarkup) { if (isBuyMarkup) { if (isPercentageMarkup)
return rate* (1-markup); else
return rate-markup; } else { if (isPercentageMarkup)
return rate* (1+markup); else
return rate+markup; } }
decimal newRate = ApplyMarkup(1.12, 0.02, true, false);
}
Distilling the Domain
• Domain Driven Design– Excessive use of primitive data types– Lack of ubiquitous language
• Distilling Domain Model (phase one)– Discovery of domain fundamental value objects– Refactoring
Value Objects - Rate • Encapsulate domain logicClass Contract{ decimal CalculateSettlementAmount(
bool isRateDirect,decimal tradeAmount,decimal tradingRate)
{if (isRateDirect)
return tradeAmount * tradingRate;else
return tradeAmount / tradingRate;
}
// …….
decimal settlementAmount =CalculateSettlementAmount(true, 200m, 1.12m);
Class Rate{ Currency unitCurrency; Currency settlementCurrency; decimal value; public Money Convert (Money money);}
Class Contract { Money settlementMoney = tradingRate.Convert(tradeMoney);}
Class Contract
public decimal ApplyMarkup( decimal rate, decimal markup, bool isPercentageMarkup, bool isBuyMarkup){ if (isBuyMarkup) { if (isPercentageMarkup)
return rate* (1-markup); else
return rate-markup; } else { if (isPercentageMarkup)
return rate* (1+markup); else
return rate+markup; }}
decimal newRate = ApplyMarkup(1.12, 0.02, true, false);
Value Objects - Markup
Class Markup
public Rate AppliedTo(Rate rate);
Class Contract
Rate newRate = markup.AppliedTo(oldRate);
Value Objects
• Simplifying interfacespublic decimal CalculateProfit(
string tradeCurrency, decimal tradeAmount,string settlementCurrency, decimal settlementAmount )
public Money CalculateProfit(money tradeMoney, money settlementMoney)
• Type safedecimal GetRate(
string unitCurrency,string referenceCurrency);
Rate GetRate(Currency unitCurrency,Currency referenceCurrency);
Currency gbp = CurrencyList.Get(“GBP”);
Refactoring
• Shared code base (CVS)• Unit test suites• Continuous integration• 2 developers working on refactoring, others
working on upcoming release• 2 weeks to redesign and refactor• Tool: Jetbrain’s Resharper
Compromises…• Refactor important interfaces
public class Order{ private decimal settlementAmount; private string settlementCurrency;
public string SettlementCurrency { get { return settlementCurrency; } }
public decimal SettlementAmount { get { return settlementAmount;} }}
public class Order{ private decimal settlementAmount; private string settlementCurrency;
public Money SettlementMoney { get{ return new Money(settlementCurrency,settlementAmount); } }}
…And Pitfallspublic class Rate{
public static implicit operator decimal(Rate rate){
return rate.Value;}
public Money AddMoney(Money target, Money moneyToAdd) {
return target + Convert(moneyToAdd); }
}
X
Today and Beyond
• More domain fundamental objects are discovered.
• More interfaces and classes have been refactored
• Richer, evolving domain model• Confidence and skills to refactor
Summary
• Domain Driven Design: make hidden domain concept explicit– http://www.domaindrivendesign.com
• A concrete example of refactoring: replacing primitive types with value objects.
• Share our experiences as well as pitfalls.
Thank you for your attention
• IAnticorruption – A Domain Driven Approach To More Robust Integration
by Sam Peng and Ying Hu