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.
Commonality and Variability Analysis: Avoiding Duplicate Code
1. The First 100 Hours:
Commonality and
Variability Analysis
Jason Cheong-Kee-You
@jpcky www.mightyjupiter.com
Alistair McKinnell
@amckinnell www.valuablecode.com
5. Exercise
1. 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?
12. Avoiding Duplicate Code
DRY: Don’t Repeat Yourself
Every piece of knowledge must have
a single, unambiguous, authoritative
representation within a system.
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.
36. Alistair’s Contention
Copy and Paste leads to the
creation of duplicate code.
Developers lack the thinking tools
and the development skills to avoid
the duplication.
38. Select Options
public 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. Select Options
public 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. Select Options
public 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. Select Options
public 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. Select Options
public 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. Select Options
public 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;
}
44. Select Options
SelectOptions SelectOptionsSource
create() getFirst()
getLast()
isSelected()
Commonality Variability Resolution
Data Structure Value of State Simple Java Type
52. Select Options Extra
List<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
53. Select Options Extra
public 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.
54. Select Options Extra
public 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. Select Options Extra
public 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. Select Options Extra
public 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. Select Options Extra
public 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));
}
64. Compound Result Handler
public 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;
}
65. Compound Result Handler
public 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;
}
66. Compound Result Handler
public 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;
}
75. Reading
The Pragmatic Programmer: From Journeyman to Master
Andrew Hunt and Dave Thomas
Extreme Programming Explained: Embrace Change
Kent Beck and Cynthia Andres
Test Driven Development: By Example
Kent Beck
Object-Oriented Software Construction
Bertrand Meyer
76. Reading
Clean Code: A Handbook of Agile Software
Craftsmanship Robert C. Martin
Design Patterns: Elements of Reusable Object-Oriented
Software Erich Gamma, Richard Helm, Ralph Johnson,
and John Vlissides
Multi-Paradigm Design for C++
James O. Coplien
Lean Architecture: for Agile Software Development
James O. Coplien and Gertrud Bjørnvig