refactoring toward deeper insight java forum

Download Refactoring toward deeper insight   java forum

Post on 01-Nov-2014

950 views

Category:

Technology

2 download

Embed Size (px)

DESCRIPTION

Refactoring Toward Deeper Insight DDD Findings in Batch Processing, a Case Study When I was introduced to the Domain-Driven Design (DDD) approach close to ten years ago, it provided me with some of the missing pieces I needed to implement Object-Orientation in an effective way. And over the years I've been coming back to Eric Evans' very rich and deep book many times to discover something new to help me design better software - thinking tools and practical design advice, in the small and in the large. Over the years Object-Orientation has become less important to me, but DDD is still my default starting point when I am helping teams to refactor their architectures and take control over their code bases. Many teams have already made attempts to implement DDD, but very often they don't get the effects they were hoping for. It turns out that DDD is hard to get right. In a current project I have been involved in yet another effort to implement DDD on a legacy code base. And I have made some interesting findings. Batch processing scenarios opened up my eyes to some intrinsic problems with the DDD approach. Issues that have been have been nagging me over the years became very clear. And yet again I managed to gain deeper insight in the DDD approach and come up with some quite interesting ways to implement it. Andreas Brink, factor10

TRANSCRIPT

  • 1. Disclaimer!!! .NET not Java Work In ProgressRefactoring Toward Deeper InsightDDD Findings In Batch Processing A Case Study Andreas Brink, factor10
  • 2. Danica Pension Core financial business system. ASP.NET / RDBMS / Integrations Generations of technologies / architectures. Lots of financial business rules. Lots of Batch Processing. Mission: Taking Control of the Code Base DRY, Understandability, Testability, Automation DDD/DM + ORM fits well!
  • 3. My View of the DDD Toolbox Model Design & Impl.Philosophy & Principles Entity Ubiquitous Language Aggregate Model Driven Value Object Declarativity Respository Distilling The Model Service Specifiction Breaktrhough Side-Effect Free Functions Strategic Design Bounded Contexts Responsibilty Layers
  • 4. Domain Model Pattern (DM)Basic Building Blocks Supple Design Entity, Assertions Aggregate Side-effect free Value Object Functions Specification Standalone Classes Factory Closure of Operations Design Sweet-Spot Understanding & Communication Testability, Executable Specifications But, not like the Office Object Model Must scale Not one single file on disk
  • 5. Implementability SomeLayer Repository ORM Service Object Navigation does not scale Repositories DM does not scale well with composition & coupling Services Problem Solved !?!?
  • 6. Implementation Mess Repository Some ORMScenario Service Less focus on Domain Model Services The Ultimate Loophole Touches big parts of the system horizontally, vertically Side Effects Understandability & Testing Problems Decentralized Flow Control & Data Access Global Optimization & Generic Processing hard or impossible Performance Problems
  • 7. Why DDD is Hard Repository Some ORMScenario Service Model Design is hard to begin with OO Expertise is still quite rare Have to be a Design Patterns / ORM / Architecture Expert Fail to get an Easily Consumable & Testable Model Same old Procedural Service Soup (+ some entities)
  • 8. My DDD Challenge Reclaiming the Domain Model Easy Reasoning, Consumption & Testing REAL Separation of Concerns Not just a complex web of objects and method calls behind superficially simple interfaces And with Batch Processing in the mix IS THIS POSSIBLE??
  • 9. Batch in the mix ORM is not for Batch, use the right tool DDD/ORM vs Stored Procedures Service Chattiness Performance Problem Batch becomes a domain service in itself Business Workflow as a mini program Hard to decompose/compose without Service I want the business rules in the Domain Model
  • 10. Billing Batch Pseudo Codeforeach (PlanAgreement planAgreement in GetPlanAgreements()){ Agreement agreement = GetAgreement(planAgreement.Id); foreach (PlanCategory planCategory in GetPlanCategories(planAgreement.Id)) { PremiumTable premiumTable = GetPremiumTable(planCategory.Id); foreach (PlanInsurance planInsurance in GetPlanInsurances(planCategory.Id)) { Insurance insurance = GetInsurance(planInsurance.InsuranceNumber); InsuranceAccount account = GetAccount(planInsurance.InsuranceNumber); AdviceHistory adviceHistory = GetAdviceHistory(planInsurance.InsuranceNumber); double premium = CalculatePremium(planAgreement, agreement, planCategory, premiumTable, planInsurance, insurance); List advices = CalculateBillingAdvice(adviceHistory, premium, account); ... ... ... } }}
  • 11. Billing Batch Levels Agreement Agreement PlanAgreement Category PlanCategory PremiumTable Insurance PlanInsuranceHistory Misc LatestPlanInsurance InsuranceHistory LatestInsurance InsuranceAccount AdviceHistory
  • 12. Batch Observations High input/output entity ratio 11 Entity Types as Input Often Complex 2 as Output (1 Create, 1 Update) Simple Simple State Semantics Opportunities for Caching (Responsibility Layers Analysis) Data is centered around a few central business keys.Potential for generalizing / streamlining the batch processing pipeline??
  • 13. Billing Batch Loops FlattenedPlanAgreement planAgreement = null;Agreement agreement = null;PlanCategory planCategory = null;PremiumTable premiumTable = null;foreach (PlanInsurance planInsurance in GetPlanInsurances()) { if (planInsurance.PlanAgreement != planAgreement) { planAgreement = planInsurance.PlanAgreement; agreement = GetAgreement(planAgreement.Id); } if (planInsurance.PlanCategory != planCategory) { planCategory = planInsurance.PlanCategory; premiumTable = GetPremiumTable(planCategory.Id); } Insurance insurance = GetInsurance(planInsurance.InsuranceNumber); InsuranceAccount account = GetAccount(planInsurance.InsuranceNumber); AdviceHistory adviceHistory = GetAdviceHistory(planInsurance.InsuranceNumber); double premium = CalculatePremium(planAgreement, agreement, planCategory, premiumTable, planInsurance, insurance); List advices = CalculateBillingAdvice(adviceHistory, premium, account); ...}
  • 14. Billing Batch Levels Flattened Agreement Category Insurance Misc Agreement Category Insurance Misc Agreement Category Insurance Misc Agreement PlanCategory PlanInsuranceHistory PlanAgreement PremiumTable LatestPlanInsurance InsuranceHistory LatestInsurance InsuranceAccount AdviceHistory
  • 15. Billing Batch Entity Level Keys Agreement Category Insurance Level Level Level Key Key Key Agreement Category Insurance Misc Agreement Category Insurance Misc Agreement Category Insurance Misc Agreement PlanCategory PlanInsuranceHistory PlanAgreement PremiumTable LatestPlanInsurance InsuranceHistory LatestInsurance InsuranceAccount AdviceHistory
  • 16. Billing Batch Generic Cursor Style Master Keys EntitiesAgreement Level Plan Agreement Agreement Insurance HistoryCategory Level Advice History Premium Table Plan CategoryInsurance Level Plan Insurance History Cursor Semantics A Set of Master Keys Drives the Cursor Entities Associated with Keys in Master Each Row Contains Entities for a Unit-Of-Work
  • 17. Entity Level Keys Level Keys Plan Insurance Agreement Level = 4501 Agreement ID = 4501 Category Level = 78 Category ID =

View more