Commonality and Variability Analysis: Avoiding Duplicate Code

3,284 views

Published on

Duplicate code is something to be avoided. And yet, everyday developers make copies of working code, make edits to the copy, and create duplicate code.

Some developers have the discipline and the skill to refactor to eliminate this duplicate code. Many do not.

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,284
On SlideShare
0
From Embeds
0
Number of Embeds
283
Actions
Shares
0
Downloads
41
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Commonality and Variability Analysis: Avoiding Duplicate Code

    1. 1. The First 100 Hours: Commonality and Variability AnalysisJason Cheong-Kee-You @jpcky www.mightyjupiter.com Alistair McKinnell@amckinnell www.valuablecode.com
    2. 2. Commonality andVariability Analysis
    3. 3. Commonality and Variability AnalysisAvoiding Duplicate Code
    4. 4. Exercise
    5. 5. Exercise1. Did you write any code last year? If so, how many lines of code?2. How many lines of code in your code base?3. Percentage of duplicate code?
    6. 6. Code Visibility
    7. 7. Code Visibility
    8. 8. Code Visibility
    9. 9. Avoiding Duplicate Code
    10. 10. Avoiding Duplicate Code
    11. 11. Avoiding Duplicate Code DRY: Don’t Repeat Yourself
    12. 12. Avoiding Duplicate Code DRY: Don’t Repeat Yourself Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
    13. 13. Avoiding Duplicate Code
    14. 14. Avoiding Duplicate Code Once and Only Once
    15. 15. Avoiding Duplicate Code Once and Only Once Data, structure, or logic should exist in only one place in the system.
    16. 16. Avoiding Duplicate Code
    17. 17. Avoiding Duplicate Code Test-Driven Development
    18. 18. Avoiding Duplicate Code Test-Driven Development 1. Write new code only if an automated test has failed.
    19. 19. Avoiding Duplicate Code Test-Driven Development 1. Write new code only if an automated test has failed. 2. Eliminate duplication.
    20. 20. Avoiding Duplicate Code
    21. 21. Avoiding Duplicate Code Single Choice Principle
    22. 22. Avoiding Duplicate Code Single Choice Principle Whenever a software system must support a set of alternatives, one and only one module in the system should know their exhaustive list.
    23. 23. Avoiding Duplicate Code
    24. 24. Avoiding Duplicate Code Duplication may be the root of all evil in software.
    25. 25. Exercise
    26. 26. Exercise
    27. 27. ExerciseWhat are the consequences ofduplicate code?
    28. 28. ExerciseWhat are the consequences ofduplicate code?Consider both good and evil.
    29. 29. Exercise
    30. 30. Exercise
    31. 31. ExerciseHow does duplicate codecome about?
    32. 32. ExerciseHow does duplicate codecome about?Make a Top 3 list.
    33. 33. Alistair’s Contention
    34. 34. Alistair’s ContentionCopy and Paste leads to thecreation of duplicate code.
    35. 35. Alistair’s ContentionCopy and Paste leads to thecreation of duplicate code.Developers lack the thinking toolsand the development skills to avoidthe duplication.
    36. 36. Duplicate Code:Select Options
    37. 37. Select Optionspublic static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}
    38. 38. Select Optionspublic static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}
    39. 39. Select Optionspublic static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}
    40. 40. Select Optionspublic static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}
    41. 41. Select Optionspublic static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}
    42. 42. Select Optionspublic static List<SelectOption> createEndMonthList(Date expiryDate) { List<SelectOption> monthList = new ArrayList<SelectOption>(); int month = getDateMonth(expiryDate); for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(true); } else { option.setLabel(String.valueOf(intLooper)); option.setValue(String.valueOf(intLooper)); option.setSelected(false); } monthList.add(option); } return monthList;}
    43. 43. Select Options SelectOptions SelectOptionsSourcecreate() getFirst() getLast() isSelected() Commonality Variability Resolution Data Structure Value of State Simple Java Type
    44. 44. Select Options SelectOptions SelectOptionsSourcecreate() getFirst() getLast() isSelected() Parameter Object
    45. 45. Select Options SelectOptions SelectOptionsSourcecreate() getFirst() getLast() isSelected() Commonality Variability Resolution Encapsulate Behaviour Collaborator Collection
    46. 46. Select Options SelectOptions SelectOptionsSourcecreate() getFirst() getLast() isSelected() Encapsulate Collection
    47. 47. Duplicate Code:Select Options Extra
    48. 48. Select Options Extrapublic static List<SelectOption> createProvinceList(String selectedProvince){ List<SelectOption> provinceList = new ArrayList<SelectOption>(); List<String> provinces = asList("AB", "BC", "MB", "NB", "NL", "NT", "NS", "NU", "ON", "PE", "QC", "SK", "YT"); for (int intLooper = 0; intLooper < provinces.size(); intLooper++) { SelectOption option = new SelectOption(); if (selectedProvince.equals(provinces.get(intLooper))) { option.setLabel(provinces.get(intLooper)); option.setValue(provinces.get(intLooper)); option.setSelected(true); } else { option.setLabel(provinces.get(intLooper)); option.setValue(provinces.get(intLooper)); option.setSelected(false); } provinceList.add(option); } return provinceList;}
    49. 49. Select Options Extrapublic static List<SelectOption> createProvinceList(String selectedProvince){ List<SelectOption> provinceList = new ArrayList<SelectOption>(); List<String> provinces = asList("AB", "BC", "MB", "NB", "NL", "NT", "NS", "NU", "ON", "PE", "QC", "SK", "YT"); for (int intLooper = 0; intLooper < provinces.size(); intLooper++) { SelectOption option = new SelectOption(); if (selectedProvince.equals(provinces.get(intLooper))) { option.setLabel(provinces.get(intLooper)); option.setValue(provinces.get(intLooper)); option.setSelected(true); } else { option.setLabel(provinces.get(intLooper)); option.setValue(provinces.get(intLooper)); option.setSelected(false); } provinceList.add(option); } return provinceList;}
    50. 50. Select Options ExtraList<String> provinces = asList("AB", "BC", "MB", "NB", "NL", "NT", "NS", "NU", "ON", "PE", "QC", "SK", "YT");
    51. 51. Select Options ExtraList<String> provinces = asList("AB", "BC", "MB", "NB", "NL", "NT", "NS", "NU", "ON", "PE", "QC", "SK", "YT");public enum Province { AB, BC, MB, NB, NL, NT, NS, NU, ON, PE, QC, SK, YT;} Commonality Variability Resolution A small set of Data Structure enum values
    52. 52. Select Options Extrapublic enum Province { AB, BC, MB, NB, NL, NT, NS, NU, ON, PE, QC, SK, YT;} Single Choice Principle Whenever a software system must support a set of alternatives, one and only one module in the system should know their exhaustive list.
    53. 53. Select Options Extrapublic static List<SelectOption> createEndMonthList(Date expiryDate) { for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper));}public static List<SelectOption> createProvinceList(String selectedProvince){ for (int intLooper = 0; intLooper < provinces.size(); intLooper++) { SelectOption option = new SelectOption(); if (selectedProvince.equals(provinces.get(intLooper))) { option.setLabel(provinces.get(intLooper));}
    54. 54. Select Options Extrapublic static List<SelectOption> createEndMonthList(Date expiryDate) { for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper));}public static List<SelectOption> createProvinceList(String selectedProvince){ for (int intLooper = 0; intLooper < provinces.size(); intLooper++) { SelectOption option = new SelectOption(); if (selectedProvince.equals(provinces.get(intLooper))) { option.setLabel(provinces.get(intLooper));}
    55. 55. Select Options Extrapublic static List<SelectOption> createEndMonthList(Date expiryDate) { for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper));}public static List<SelectOption> createProvinceList(String selectedProvince){ for (int intLooper = 0; intLooper < provinces.size(); intLooper++) { SelectOption option = new SelectOption(); if (selectedProvince.equals(provinces.get(intLooper))) { option.setLabel(provinces.get(intLooper));}
    56. 56. Select Options Extrapublic static List<SelectOption> createEndMonthList(Date expiryDate) { for (int intLooper = 1; intLooper <= 12; intLooper++) { SelectOption option = new SelectOption(); if (month == intLooper) { option.setLabel(String.valueOf(intLooper));}public static List<SelectOption> createProvinceList(String selectedProvince){ for (int intLooper = 0; intLooper < provinces.size(); intLooper++) { SelectOption option = new SelectOption(); if (selectedProvince.equals(provinces.get(intLooper))) { option.setLabel(provinces.get(intLooper));}
    57. 57. Select Options Extra String Iterable iterator() SelectOptions SelectOptionsSource create() isSelected() IntegerRangeSource ProvinceSource iterator() iterator() isSelected() isSelected()
    58. 58. Select Options Extra String Iterable iterator() SelectOptions SelectOptionsSource create() isSelected() IntegerRangeSource ProvinceSource iterator() iterator() isSelected() isSelected()
    59. 59. Select Options Extra String Iterable iterator() SelectOptions SelectOptionsSource create() isSelected() IntegerRangeSource ProvinceSource iterator() iterator() isSelected() isSelected()Commonality Variability Resolution Collection Values Iterator
    60. 60. Select Options Extra String Iterable iterator() SelectOptions SelectOptionsSource create() isSelected() IntegerRangeSource ProvinceSource iterator() iterator() isSelected() isSelected()Commonality Variability Resolution Collection Type Generics
    61. 61. Select Options Extra String Iterable iterator() SelectOptions SelectOptionsSource create() isSelected() IntegerRangeSource ProvinceSource iterator() iterator() isSelected() isSelected()Commonality Variability Resolution Inheritance Behaviour Implementation (Object-Oriented)
    62. 62. Duplicate Code:Compound Result Handler
    63. 63. Compound Result Handlerpublic Collection<IRegCommand> processCompondResults(Patient sourcePatient, Collection<Result> results) { Collection<IRegCommand> retVal = new ArrayList<IRegCommand>(); Set<Result> resultsMarkedForRemoval = new HashSet<Result>(); Set<Result> resultsProcessed = new HashSet<Result>(); for (Result primaryResult : results) { if (isResultProcessed(resultsProcessed, primaryResult)) { continue; } resultsProcessed.add(primaryResult); Result correspondingResult = getCorrespondingResult(primaryResult, results); if (correspondingResult != null) { resultsProcessed.add(correspondingResult); resultsMarkedForRemoval.add(correspondingResult); } if (!sourcePatient.getDataWarehouse().equals(DataWarehouseTag.QHN)) { // If the response to either question is yes then display positive as the measure value. if (primaryResult.getDwValue().equalsIgnoreCase("1")) { primaryResult.setDwValue("POSITIVE"); } else { // If the response to both questions is no then display negative as the measure value. if (correspondingResult != null) { if (correspondingResult.getDwValue().equalsIgnoreCase("2")) { primaryResult.setDwValue("NEGATIVE"); } else if (correspondingResult.getDwValue().equalsIgnoreCase("1")) { // It must be yes - thus value is POSITIVE primaryResult.setDwValue("POSITIVE"); } else { badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "Issue with multiple PHQ results"); continue; } } else { // No corresponding result - where is the 2nd result? - badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "No corresponding value found for a 2 item screener with value of no"); continue; } } } else { // If the response to either question is yes then display positive as the measure value. if (primaryResult.getDwValue().equalsIgnoreCase("3") || primaryResult.getDwValue().equalsIgnoreCase("4")) { primaryResult.setDwValue("POSITIVE"); } else { // If the response to both questions is no then display negative as the measure value. if (correspondingResult != null) { if (primaryResult.getDwValue().equalsIgnoreCase("0") || primaryResult.getDwValue().equalsIgnoreCase("1") || primaryResult.getDwValue().equalsIgnoreCase("2")) { primaryResult.setDwValue("NEGATIVE"); } else if (primaryResult.getDwValue().equalsIgnoreCase("3") || primaryResult.getDwValue().equalsIgnoreCase("4")) { // It must be yes - thus value is POSITIVE primaryResult.setDwValue("POSITIVE"); } else { badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "Issue with multiple PHQ results"); continue; } } else { // No corresponding result - where is the 2nd result? - badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "No corresponding value found for a 2 item screener with value of no"); continue; } } } Map<String, Object> transformedResult = resultTransformer.transformResult(sourcePatient, primaryResult); if (null != transformedResult) { retVal.add(new PatientDataUpdateCommand(CommandType.RESULT, sourcePatient, transformedResult)); } } return retVal;}
    64. 64. Compound Result Handlerpublic Collection<IRegCommand> processCompondResults(Patient sourcePatient, Collection<Result> results) { Collection<IRegCommand> retVal = new ArrayList<IRegCommand>(); Set<Result> resultsMarkedForRemoval = new HashSet<Result>(); Set<Result> resultsProcessed = new HashSet<Result>(); for (Result primaryResult : results) { if (isResultProcessed(resultsProcessed, primaryResult)) { continue; } resultsProcessed.add(primaryResult); Result correspondingResult = getCorrespondingResult(primaryResult, results); if (correspondingResult != null) { resultsProcessed.add(correspondingResult); } resultsMarkedForRemoval.add(correspondingResult); if (!sourcePatient.getDataWarehouse() if (!sourcePatient.getDataWarehouse().equals(DataWarehouseTag.QHN)) { // If the response to either question is yes then display positive as the measure value. if (primaryResult.getDwValue().equalsIgnoreCase("1")) { primaryResult.setDwValue("POSITIVE"); .equals(DataWarehouseTag.QHN)) { } else { // If the response to both questions is no then display negative as the measure value. if (correspondingResult != null) { if (correspondingResult.getDwValue().equalsIgnoreCase("2")) { primaryResult.setDwValue("NEGATIVE"); } else if (correspondingResult.getDwValue().equalsIgnoreCase("1")) { // It must be yes - thus value is POSITIVE primaryResult.setDwValue("POSITIVE"); } else { badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "Issue with multiple PHQ results"); continue; } } else { // No corresponding result - where is the 2nd result? - badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "No corresponding value found for a 2 item screener with value of no"); continue; } } } else { // If the response to either question is yes then display positive as the measure value. if (primaryResult.getDwValue().equalsIgnoreCase("3") || primaryResult.getDwValue().equalsIgnoreCase("4")) { primaryResult.setDwValue("POSITIVE"); } else { // If the response to both questions is no then display negative as the measure value. if (correspondingResult != null) { if (primaryResult.getDwValue().equalsIgnoreCase("0") || primaryResult.getDwValue().equalsIgnoreCase("1") || primaryResult.getDwValue().equalsIgnoreCase("2")) { primaryResult.setDwValue("NEGATIVE"); } else if (primaryResult.getDwValue().equalsIgnoreCase("3") || primaryResult.getDwValue().equalsIgnoreCase("4")) { // It must be yes - thus value is POSITIVE primaryResult.setDwValue("POSITIVE"); } else { badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "Issue with multiple PHQ results"); continue; } } else { // No corresponding result - where is the 2nd result? - badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "No corresponding value found for a 2 item screener with value of no"); continue; } } } Map<String, Object> transformedResult = resultTransformer.transformResult(sourcePatient, primaryResult); if (null != transformedResult) { retVal.add(new PatientDataUpdateCommand(CommandType.RESULT, sourcePatient, transformedResult)); } } return retVal;}
    65. 65. Compound Result Handlerpublic Collection<IRegCommand> processCompondResults(Patient sourcePatient, Collection<Result> results) { Collection<IRegCommand> retVal = new ArrayList<IRegCommand>(); Set<Result> resultsMarkedForRemoval = new HashSet<Result>(); Set<Result> resultsProcessed = new HashSet<Result>(); for (Result primaryResult : results) { if (isResultProcessed(resultsProcessed, primaryResult)) { continue; } resultsProcessed.add(primaryResult); Result correspondingResult = getCorrespondingResult(primaryResult, results); if (correspondingResult != null) { resultsProcessed.add(correspondingResult); } resultsMarkedForRemoval.add(correspondingResult); if (!sourcePatient.getDataWarehouse().equals(DataWarehouseTag.QHN)) { if (primaryResult.getDwValue().equalsIgnoreCase("1")) // If the response to either question is yes then display positive as the measure value. if (primaryResult.getDwValue().equalsIgnoreCase("1")) { primaryResult.setDwValue("POSITIVE"); } else { // If the response to both questions is no then display negative as the measure value. if (correspondingResult != null) { if (correspondingResult.getDwValue().equalsIgnoreCase("2")) { primaryResult.setDwValue("NEGATIVE"); } else if (correspondingResult.getDwValue().equalsIgnoreCase("1")) { // It must be yes - thus value is POSITIVE primaryResult.setDwValue("POSITIVE"); } else { badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "Issue with multiple PHQ results"); continue; } } else { // No corresponding result - where is the 2nd result? - badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "No corresponding value found for a 2 item screener with value of no"); continue; } } else { } if (primaryResult.getDwValue().equalsIgnoreCase("3") || // If the response to either question is yes then display positive as the measure value. if (primaryResult.getDwValue().equalsIgnoreCase("3") || primaryResult.getDwValue().equalsIgnoreCase("4")) { primaryResult.setDwValue("POSITIVE"); primaryResult.getDwValue().equalsIgnoreCase("4")) } else { // If the response to both questions is no then display negative as the measure value. if (correspondingResult != null) { if (primaryResult.getDwValue().equalsIgnoreCase("0") || primaryResult.getDwValue().equalsIgnoreCase("1") || primaryResult.getDwValue().equalsIgnoreCase("2")) { primaryResult.setDwValue("NEGATIVE"); } else if (primaryResult.getDwValue().equalsIgnoreCase("3") || primaryResult.getDwValue().equalsIgnoreCase("4")) { // It must be yes - thus value is POSITIVE primaryResult.setDwValue("POSITIVE"); } else { badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "Issue with multiple PHQ results"); continue; } } else { // No corresponding result - where is the 2nd result? - badDataLogger.logBadData(sourcePatient.getExternalId(), Measure.NAME_2ITEMSCREENER, primaryResult.getDwValue() + " (" + primaryResult.getEventDateTime() + ") ", "No corresponding value found for a 2 item screener with value of no"); continue; } } } Map<String, Object> transformedResult = resultTransformer.transformResult(sourcePatient, primaryResult); if (null != transformedResult) { retVal.add(new PatientDataUpdateCommand(CommandType.RESULT, sourcePatient, transformedResult)); } } return retVal;}
    66. 66. Compound Result Handler CompoundResultHandler CompoundResultClassifier isNegative() isPositive() AbstractCompoundResultClassifier toNumber() QueensCompoundResultClassifier StandardCompoundResultClassifier isNegative() isNegative() isPositive() isPositive()
    67. 67. Compound Result Handler CompoundResultHandler CompoundResultClassifier isNegative() isPositive() AbstractCompoundResultClassifier toNumber() QueensCompoundResultClassifier StandardCompoundResultClassifier isNegative() isNegative() isPositive() isPositive() Commonality Variability Resolution Inheritance Behaviour Implementation (Object-Oriented)
    68. 68. Compound Result Handler CompoundResultHandler CompoundResultClassifier isNegative() isPositive() AbstractCompoundResultClassifier toNumber() QueensCompoundResultClassifier StandardCompoundResultClassifier isNegative() isNegative() isPositive() isPositive() Commonality Variability ResolutionImplementation None Base Class
    69. 69. Code Visibility
    70. 70. Reading
    71. 71. Reading
    72. 72. ReadingThe Pragmatic Programmer: From Journeyman to MasterAndrew Hunt and Dave ThomasExtreme Programming Explained: Embrace ChangeKent Beck and Cynthia AndresTest Driven Development: By ExampleKent BeckObject-Oriented Software ConstructionBertrand Meyer
    73. 73. ReadingClean Code: A Handbook of Agile SoftwareCraftsmanship Robert C. MartinDesign Patterns: Elements of Reusable Object-OrientedSoftware Erich Gamma, Richard Helm, Ralph Johnson,and John VlissidesMulti-Paradigm Design for C++James O. CoplienLean Architecture: for Agile Software DevelopmentJames O. Coplien and Gertrud Bjørnvig
    74. 74. Photo Creditshttp://www.flickr.com/photos/27558040@N00/4151899795/http://www.flickr.com/photos/popilop/331357312/http://www.flickr.com/photos/arlette/3260468/http://www.flickr.com/photos/36829973@N04/3546657245/

    ×