So We Thought We Knew Money

655 views
574 views

Published on

Experience report on applying DDD to discover and refactor domain fundamental value objects

Published in: Travel, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
655
On SlideShare
0
From Embeds
0
Number of Embeds
31
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

So We Thought We Knew Money

  1. 1. So We Thought We Knew Money Ying Hu Sam Peng [email_address] [email_address] Custom House Global Foreign Exchange
  2. 2. Outline <ul><li>Background </li></ul><ul><li>The problem in the system </li></ul><ul><li>Distilling the domain model and the discovery of the value objects </li></ul><ul><li>Refactoring, differences before and after </li></ul><ul><li>Compromises and pitfalls </li></ul>
  3. 3. The Domain <ul><li>Foreign exchange is all we do </li></ul>
  4. 4. In our system… <ul><li>Variable names of primitive data types </li></ul>public class Contract { decimal tradingRate; bool isRateDirect; string tradeCurrency; decimal tradeAmount; string settlementCurrency; decimal settlementAmount; decimal Markup; … … decimal GetRate( string unitCurrency, string referenceCurrency); <ul><li>Method names, parameters, return types </li></ul>
  5. 5. Implicit Domain Concept <ul><li>Public Class Contract </li></ul><ul><li>{ </li></ul><ul><li>decimal CalculateSettlementAmount ( </li></ul><ul><li>bool isRateDirect, </li></ul><ul><li>decimal tradeAmount, </li></ul><ul><li>decimal tradingRate) </li></ul><ul><li>{ </li></ul><ul><ul><li>if (isRateDirect) </li></ul></ul><ul><ul><li>return tradeAmount * tradingRate; </li></ul></ul><ul><ul><li>else </li></ul></ul><ul><ul><li>return tradeAmount / tradingRate; </li></ul></ul><ul><li>} </li></ul><ul><li>decimal settlementAmount = </li></ul><ul><li>CalculateSettlementAmount(true, 200m, 1.12m); </li></ul><ul><li>//…… </li></ul><ul><li>} </li></ul><ul><li>Public Class Contract </li></ul><ul><li>{ </li></ul><ul><li>decimal ApplyMarkup( </li></ul><ul><li>decimal rate, decimal markup, </li></ul><ul><li>bool isPercentageMarkup, bool isBuyMarkup) </li></ul><ul><li>{ </li></ul><ul><li>if (isBuyMarkup) </li></ul><ul><li>{ </li></ul><ul><li>if (isPercentageMarkup) </li></ul><ul><ul><ul><li>return rate* (1-markup); </li></ul></ul></ul><ul><li>else </li></ul><ul><ul><ul><li>return rate-markup; </li></ul></ul></ul><ul><li>} </li></ul><ul><li>else </li></ul><ul><li>{ </li></ul><ul><li>if (isPercentageMarkup) </li></ul><ul><ul><li>return rate* (1+markup); </li></ul></ul><ul><li>else </li></ul><ul><li>return rate+markup; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>decimal newRate = ApplyMarkup(1.12, 0.02, true, false); </li></ul><ul><li>} </li></ul>
  6. 6. Distilling the Domain <ul><li>Domain Driven Design </li></ul><ul><ul><li>Excessive use of primitive data types </li></ul></ul><ul><ul><li>Lack of ubiquitous language </li></ul></ul><ul><li>Distilling Domain Model (phase one) </li></ul><ul><ul><li>Discovery of domain fundamental value objects </li></ul></ul><ul><ul><li>Refactoring </li></ul></ul>
  7. 7. Value Objects - Rate <ul><li>Encapsulate domain logic </li></ul><ul><li>Class Contract </li></ul><ul><li>{ </li></ul><ul><li>decimal CalculateSettlementAmount ( </li></ul><ul><li>bool isRateDirect, </li></ul><ul><li>decimal tradeAmount, </li></ul><ul><li>decimal tradingRate) </li></ul><ul><li>{ </li></ul><ul><ul><li>if (isRateDirect) </li></ul></ul><ul><ul><li>return tradeAmount * tradingRate; </li></ul></ul><ul><ul><li>else </li></ul></ul><ul><ul><li>return tradeAmount / tradingRate; </li></ul></ul><ul><li>} </li></ul><ul><li>// ……. </li></ul><ul><li>decimal settlementAmount = </li></ul><ul><li>CalculateSettlementAmount(true, 200m, 1.12m); </li></ul>Class Rate { Currency unitCurrency; Currency settlementCurrency; decimal value; public Money Convert (Money money); } Class Contract { Money settlementMoney = tradingRate.Convert (tradeMoney); }
  8. 8. Value Objects - Markup <ul><li>Class Contract </li></ul><ul><li>public decimal ApplyMarkup( </li></ul><ul><li>decimal rate, decimal markup, </li></ul><ul><li>bool isPercentageMarkup, bool isBuyMarkup) </li></ul><ul><li>{ </li></ul><ul><li>if (isBuyMarkup) </li></ul><ul><li>{ </li></ul><ul><li>if (isPercentageMarkup) </li></ul><ul><ul><ul><li>return rate* (1-markup); </li></ul></ul></ul><ul><li>else </li></ul><ul><ul><ul><li>return rate-markup; </li></ul></ul></ul><ul><li>} </li></ul><ul><li>else </li></ul><ul><li>{ </li></ul><ul><li>if (isPercentageMarkup) </li></ul><ul><ul><li>return rate* (1+markup); </li></ul></ul><ul><li>else </li></ul><ul><li>return rate+markup; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>decimal newRate = ApplyMarkup (1.12, 0.02, true, false); </li></ul>Class Markup public Rate AppliedTo (Rate rate); Class Contract Rate newRate = markup.AppliedTo (oldRate);
  9. 9. Value Objects <ul><li>Simplifying interfaces </li></ul><ul><li>public decimal CalculateProfit ( </li></ul><ul><ul><li>string tradeCurrency, </li></ul></ul><ul><ul><li>decimal tradeAmount, </li></ul></ul><ul><ul><li>string settlementCurrency, </li></ul></ul><ul><ul><li>decimal settlementAmount </li></ul></ul><ul><ul><li>) </li></ul></ul><ul><li>public Money CalculateProfit ( </li></ul><ul><ul><li>money tradeMoney, </li></ul></ul><ul><ul><li>money settlementMoney </li></ul></ul><ul><ul><li>) </li></ul></ul><ul><li>Type safe </li></ul><ul><li>decimal GetRate ( </li></ul><ul><ul><li>string unitCurrency, </li></ul></ul><ul><ul><li>string referenceCurrency); </li></ul></ul><ul><li>Rate GetRate ( </li></ul><ul><ul><li>Currency unitCurrency, </li></ul></ul><ul><ul><li>Currency referenceCurrency); </li></ul></ul>Currency gbp = CurrencyList.Get(“GBP”);
  10. 10. Refactoring <ul><li>Shared code base (CVS) </li></ul><ul><li>Unit test suites </li></ul><ul><li>Continuous integration </li></ul><ul><li>2 developers working on refactoring, others working on upcoming release </li></ul><ul><li>2 weeks to redesign and refactor </li></ul><ul><li>Tool: Jetbrain’s Resharper </li></ul>
  11. 11. Compromises… <ul><li>Refactor important interfaces </li></ul>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); } } }
  12. 12. … And Pitfalls <ul><li>public class Rate </li></ul><ul><li>{ </li></ul><ul><ul><li>public static implicit operator decimal(Rate rate) </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>return rate.Value; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>public Money AddMoney(Money target, Money moneyToAdd) </li></ul><ul><li>{ </li></ul><ul><li>return target + Convert(moneyToAdd); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>X
  13. 13. Today and Beyond <ul><li>More domain fundamental objects are discovered. </li></ul><ul><li>More interfaces and classes have been refactored </li></ul><ul><li>Richer, evolving domain model </li></ul><ul><li>Confidence and skills to refactor </li></ul>
  14. 14. Summary <ul><li>Domain Driven Design: make hidden domain concept explicit </li></ul><ul><ul><li>http://www.domaindrivendesign.com </li></ul></ul><ul><li>A concrete example of refactoring: replacing primitive types with value objects. </li></ul><ul><li>Share our experiences as well as pitfalls. </li></ul>
  15. 15. Thank you for your attention <ul><li>IAnticorruption – A Domain Driven Approach To More Robust Integration </li></ul><ul><li>by Sam Peng and Ying Hu </li></ul>

×