SlideShare una empresa de Scribd logo
1 de 42
Descargar para leer sin conexión
Removing Structural Duplication
Alex Bolboacă, @alexboly, alex.bolboaca@mozaicworks.com
May 2017
1
What is Structural Duplication?
Why is it a problem?
When to remove?
Example: Exception management
Example: Views
How to remove
In the End . . .
2
What is Structural Duplication?
3
Definition
Structural duplication (better said, similarity) is a similar code
structure that repeats, even though the actions performed inside
the structure are different.
4
Example: conditionals
if(condition1){
...
...
}
if(condition2){
...
...
}
if(condition3){
...
...
}
5
Example: exceptions
try{
...
...
} catch(FirstException firstExc){
...
} catch(SecondException secondExc){
...
}
try{
...
...
} catch(SecondException secondExc){
...
} catch(ThirdException thirdExc){
...
}
6
Example: views
<form id="personForm">
<div class="row">
<div class="col-md-4">
Show something here
</div>
<div class="col-md-4">
Show something different here
</div>
</div>
<div class="row">
<div class="col-md-4">
Show yet something else here
</div>
<div class="col-md-4">
And again something else here
</div>
</div>
</form>
7
Why is it a problem?
8
Issues
• Risk: when the same structure is spread throughout the code,
it’s likely that:
• it will grow
• it will keep increasing in duplication (eg. we’ll treat
ThirdException in the same way in another place)
• similar structures might change in similar ways, resulting in
duplicated work
• Intent hidden inside the structure
• Long methods
• Duplication in tests
9
When to remove?
10
Criteria for removal
• When it appears at least 3 times
• When it’s expected to grow
• When the intent is unclear
• When we expect the structure of the code to change in similar
ways in multiple places
• Judgement call
11
Careful
12
Example: Exception management
13
Example code
List<Employee> readEmployeesFromDatabase(){
try{
ResultSet rs = stmt.executeQuery(
"SELECT id, first, last, age FROM Employees");
List<Employee> employees = new List<Employee>();
while(rs.next()){
employees.add(
new Employee(rs.getInt("id"), rs.getString("first"),
rs.getString("last"), rs.getInt("age"));
}
rs.close();
return employees;
} catch(SQLException se){
return new List<Employee>();
} catch(Exception e){
log.error("Exception: " + se.toString());
return null;
}
}
14
Disclaimer
15
Step 0: Clarify responsibilities (find the right name)
List<Employee> readEmployeesFromDatabaseAndReturnEmptyListOnDbErrorAndLogOtherExceptions(){
....
}
16
Step 0: Clarify responsibilities
List<Employee> readEmployeesFromDatabaseAndReturnEmptyListO
try{
ResultSet rs = stmt.executeQuery(
"SELECT id, first, last, age FROM Employees");
List<Employee> employees = new List<Employee>();
while(rs.next()){
employees.add(
new Employee(rs.getInt("id"), rs.getString("fir
rs.getString("last"), rs.getInt("age"));
}
rs.close();
return employees;
} catch(SQLException se){
return new List<Employee>();
17
Step 0: Separate responsibilities (cont’d)
List<Employee> readEmployeesFromDatabaseAndReturnEmptyListOnDbErrorAndLogOtherExceptions(){
try{
List<Employee> employees = readEmployeesFromDatabase();
} catch(SQLException se){
return new List<Employee>();
} catch(Exception e){
log.error("Exception: " + se.toString());
return null;
}
}
18
Step 1: Remove duplication
List<Employee> readEmployeesFromDatabaseAndReturnEmptyListOnDbErrorAndLogOtherExceptions(){
try{
List<Employee> employees = readEmployees();
} catch(Exception e){
if(e is SqlException){
return new List<Employee>();
}
if(e is Exception){
log.error("Exception: " + se.toString());
return null;
}
}
}
19
Step 2: Extract action for each if statement
List<Employee> readEmployeesFromDatabase(){
try{
List<Employee> employees = readEmployees();
} catch(Exception e){
if(e is SqlException) return emptyList();
if(e is Exception) return logError();
}
}
20
Step 3: Refactor to set of rules
List<Employee> readEmployeesFromDatabaseAndReturnEmptyListO
List rules = new List(){
new Pair(
{e -> e is SqlException},
{e -> emptyList()}),
new Pair(
{e -> e is Exception},
{e -> logError(e)})
}
try{
List<Employee> employees = readEmployees();
} catch(Exception e){
return rules.find{e.first(e)}.second(e)
}
}
21
Step 4: Push errors and rules up
List<Employee> readEmployeesFromDatabaseAndManageExceptions
try{
List<Employee> employees = readEmployees();
} catch(Exception e){
return exceptionManagementRules
.find{e.first.call(e)}
.second.call(e);
}
}
22
Step 5: Extract final duplication
List<Employee> readEmployeesFromDatabase(){
return callWithExceptionManagement(
rules,
{ -> readEmployees();});
}
Object callWithExceptionManagement(List<> exceptionManagementRules, action){
try{
action.call();
} catch(Exception e){
return exceptionManagementRules
.find{e.first.call(e)}
.second.call(e);
}
}
23
Advantages
• Clear and consistent set of rules for exception management
• Separate the behaviour from exception management (SRP)
• Change the exception management rules from one place (OCP)
• Easier to write new code of the same kind
24
Disadvantages
• Can prove difficult to extend for certain exception management
treatments. Eg. retries, transactional behaviour etc.
• Requires understanding of lambdas
• Can be difficult to understand for programmers unused with
the idea
25
Example: Views
26
Example Code
<form id="personForm">
<div class="row">
<div class="col-md-4">
<label for="firstName">
</div>
<div class="col-md-4">
<input id="firstName" type="text" value="Alex"></input>
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="lastName">
</div>
<div class="col-md-4">
<input id="lastName" type="text" value="Bolboacă"></input>
</div>
</div>
</form>
27
Step 0: which structure do we want to separate?
Could be:
• A two column form, if we have many two column forms and
expect to change their layout at the same time
• A stack of rows, if we have multiple stacks of rows and
expect to change them in similar ways (e.g. switch from one
grid system to another)
• Others, depending on the rest of the code
28
Step 1: Separate structure from content
<form id="personForm">
<div class="row">
<div class="col-md-4">
<g:render template="firstNameLabel">
</div>
<div class="col-md-4">
<g:render template="firstNameInput" model="Alex">
</div>
</div>
<div class="row">
<div class="col-md-4">
<g:render template src="lastNameLabel">
</div>
<div class="col-md-4">
<g:render template="lastNameInput" model="Bolboacă">
</div>
</div>
</form>
29
Step 2: Separate data model from layout
[
[
label: [template: 'firstNameLabel'],
input: [template: 'firstNameInput', value: 'Alex']
],
[
label: [template: 'lastNameLabel'],
input: [template: 'lastNameInput', value: 'Bolboacă']
]
]
30
Step 3: Replace with loop
<form id="personForm">
<g:each var="formLine" from="${dataModel}">
<div class="row">
<div class="col-md-4">
<g:render template="${formLine.label.template}">
</div>
<div class="col-md-4">
<g:render template="${formLine.input.template}"
model="${formLine.input.value}">
</div>
</div>
</g:each>
</form>
31
Careful with accidental duplication
<div class="col-md-4">
...
</div>
<div class="col-md-4">
...
</div>
Looks like structural duplication, but label width doesn’t
necessarily change at the same time with input width
32
Step 4: More separation of layout
<form id="personForm">
<g:each var="formLine" from="${dataModel}">
<g:render template="formLine" model="${formLine}">
</g:each>
</form>
33
Advantages
• All two-column forms have the same structure, and we can
change it from one place
• Smaller, more focused code (SRP)
• Follow OCP (yes, it applies to views too!)
• Clear where to change details (label and input templates) and
where to change structure (form, formLine templates)
34
Disadvantages
• If only one of the forms changes structure (eg. to three
columns), it can be painful (aka rigidity to certain types of
change)
• Can be harder to navigate to the places where you need to
change things. The structure and conventions need to be
documented and learned
35
How to remove
36
Steps
1. Define precisely which structural duplication you want to
remove
2. Double-check if it’s accidental
3. Separate structure from actions
4. Extract data structure
5. Replace with loops or functional constructs
37
In the End . . .
38
Recap
• Structural duplication is a code construct that has similar
structure but does different actions
• If we expect the structure to change in multiple places, it’s
worth separating from the actions
• It leads to code that follows SRP & OCP
• But be very careful at accidental duplication
39
Your choice
40
Q&A
41
Join ProductLeaders
42

Más contenido relacionado

La actualidad más candente

Net Beans Codes for Student Portal
Net Beans Codes for Student PortalNet Beans Codes for Student Portal
Net Beans Codes for Student Portal
Peeyush Ranjan
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
stasimus
 

La actualidad más candente (18)

Ensure code quality with vs2012
Ensure code quality with vs2012Ensure code quality with vs2012
Ensure code quality with vs2012
 
Net Beans Codes for Student Portal
Net Beans Codes for Student PortalNet Beans Codes for Student Portal
Net Beans Codes for Student Portal
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
The Ring programming language version 1.8 book - Part 32 of 202
The Ring programming language version 1.8 book - Part 32 of 202The Ring programming language version 1.8 book - Part 32 of 202
The Ring programming language version 1.8 book - Part 32 of 202
 
Introduction to type classes
Introduction to type classesIntroduction to type classes
Introduction to type classes
 
Introduction to type classes in 30 min
Introduction to type classes in 30 minIntroduction to type classes in 30 min
Introduction to type classes in 30 min
 
The Ring programming language version 1.6 book - Part 29 of 189
The Ring programming language version 1.6 book - Part 29 of 189The Ring programming language version 1.6 book - Part 29 of 189
The Ring programming language version 1.6 book - Part 29 of 189
 
The Ring programming language version 1.3 book - Part 20 of 88
The Ring programming language version 1.3 book - Part 20 of 88The Ring programming language version 1.3 book - Part 20 of 88
The Ring programming language version 1.3 book - Part 20 of 88
 
Java
JavaJava
Java
 
Pre zen ta sion
Pre zen ta sionPre zen ta sion
Pre zen ta sion
 
How to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy CodeHow to Start Test-Driven Development in Legacy Code
How to Start Test-Driven Development in Legacy Code
 
The Ring programming language version 1.10 book - Part 17 of 212
The Ring programming language version 1.10 book - Part 17 of 212The Ring programming language version 1.10 book - Part 17 of 212
The Ring programming language version 1.10 book - Part 17 of 212
 
SQL || overview and detailed information about Sql
SQL || overview and detailed information about SqlSQL || overview and detailed information about Sql
SQL || overview and detailed information about Sql
 
Java day9n
Java day9nJava day9n
Java day9n
 
SQL querys in detail || Sql query slides
SQL querys in detail || Sql query slidesSQL querys in detail || Sql query slides
SQL querys in detail || Sql query slides
 
The Ring programming language version 1.3 book - Part 24 of 88
The Ring programming language version 1.3 book - Part 24 of 88The Ring programming language version 1.3 book - Part 24 of 88
The Ring programming language version 1.3 book - Part 24 of 88
 
The Ring programming language version 1.6 book - Part 34 of 189
The Ring programming language version 1.6 book - Part 34 of 189The Ring programming language version 1.6 book - Part 34 of 189
The Ring programming language version 1.6 book - Part 34 of 189
 

Similar a Removing structural duplication

Knockout.js presentation
Knockout.js presentationKnockout.js presentation
Knockout.js presentation
Scott Messinger
 
Vejovis: Suggesting Fixes for JavaScript Faults
Vejovis: Suggesting Fixes for JavaScript FaultsVejovis: Suggesting Fixes for JavaScript Faults
Vejovis: Suggesting Fixes for JavaScript Faults
SALT Lab @ UBC
 
Converting Db Schema Into Uml Classes
Converting Db Schema Into Uml ClassesConverting Db Schema Into Uml Classes
Converting Db Schema Into Uml Classes
Kaniska Mandal
 
VisualStudio2012-WhatsNew-TechEd_v3-9
VisualStudio2012-WhatsNew-TechEd_v3-9VisualStudio2012-WhatsNew-TechEd_v3-9
VisualStudio2012-WhatsNew-TechEd_v3-9
SSW
 

Similar a Removing structural duplication (20)

Django quickstart
Django quickstartDjango quickstart
Django quickstart
 
Knockout.js presentation
Knockout.js presentationKnockout.js presentation
Knockout.js presentation
 
Presentacion clean code
Presentacion clean codePresentacion clean code
Presentacion clean code
 
The Ring programming language version 1.3 book - Part 83 of 88
The Ring programming language version 1.3 book - Part 83 of 88The Ring programming language version 1.3 book - Part 83 of 88
The Ring programming language version 1.3 book - Part 83 of 88
 
Chapter Seven- JDBC.pptx
Chapter Seven- JDBC.pptxChapter Seven- JDBC.pptx
Chapter Seven- JDBC.pptx
 
The Ring programming language version 1.4.1 book - Part 8 of 31
The Ring programming language version 1.4.1 book - Part 8 of 31The Ring programming language version 1.4.1 book - Part 8 of 31
The Ring programming language version 1.4.1 book - Part 8 of 31
 
Presentation on template and exception
Presentation  on template and exceptionPresentation  on template and exception
Presentation on template and exception
 
The Ring programming language version 1.6 book - Part 31 of 189
The Ring programming language version 1.6 book - Part 31 of 189The Ring programming language version 1.6 book - Part 31 of 189
The Ring programming language version 1.6 book - Part 31 of 189
 
JavaScript lesson 1.pptx
JavaScript lesson 1.pptxJavaScript lesson 1.pptx
JavaScript lesson 1.pptx
 
New Component Patterns in Ember.js
New Component Patterns in Ember.jsNew Component Patterns in Ember.js
New Component Patterns in Ember.js
 
The Ring programming language version 1.7 book - Part 32 of 196
The Ring programming language version 1.7 book - Part 32 of 196The Ring programming language version 1.7 book - Part 32 of 196
The Ring programming language version 1.7 book - Part 32 of 196
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
 
Jquery tutorial
Jquery tutorialJquery tutorial
Jquery tutorial
 
Vejovis: Suggesting Fixes for JavaScript Faults
Vejovis: Suggesting Fixes for JavaScript FaultsVejovis: Suggesting Fixes for JavaScript Faults
Vejovis: Suggesting Fixes for JavaScript Faults
 
Performance is a feature! - Developer South Coast - part 2
Performance is a feature!  - Developer South Coast - part 2Performance is a feature!  - Developer South Coast - part 2
Performance is a feature! - Developer South Coast - part 2
 
Converting Db Schema Into Uml Classes
Converting Db Schema Into Uml ClassesConverting Db Schema Into Uml Classes
Converting Db Schema Into Uml Classes
 
VisualStudio2012-WhatsNew-TechEd_v3-9
VisualStudio2012-WhatsNew-TechEd_v3-9VisualStudio2012-WhatsNew-TechEd_v3-9
VisualStudio2012-WhatsNew-TechEd_v3-9
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 
Alfredo-PUMEX
Alfredo-PUMEXAlfredo-PUMEX
Alfredo-PUMEX
 

Más de Alexandru Bolboaca

Más de Alexandru Bolboaca (20)

Refactor legacy code through pure functions
Refactor legacy code through pure functionsRefactor legacy code through pure functions
Refactor legacy code through pure functions
 
Design Without Types
Design Without TypesDesign Without Types
Design Without Types
 
Thinking in Functions
Thinking in FunctionsThinking in Functions
Thinking in Functions
 
Raising the Bar
Raising the BarRaising the Bar
Raising the Bar
 
The Journey to Master Code Design
The Journey to Master Code DesignThe Journey to Master Code Design
The Journey to Master Code Design
 
What is good software design? And why it matters?
What is good software design? And why it matters?What is good software design? And why it matters?
What is good software design? And why it matters?
 
Functional programming in C++
Functional programming in C++Functional programming in C++
Functional programming in C++
 
Agile Technical Leadership
Agile Technical LeadershipAgile Technical Leadership
Agile Technical Leadership
 
TDD As If You Meant It
TDD As If You Meant ItTDD As If You Meant It
TDD As If You Meant It
 
Usable Software Design
Usable Software DesignUsable Software Design
Usable Software Design
 
Hidden loops
Hidden loopsHidden loops
Hidden loops
 
Continuous delivery
Continuous deliveryContinuous delivery
Continuous delivery
 
Why You Should Start Using Docker
Why You Should Start Using DockerWhy You Should Start Using Docker
Why You Should Start Using Docker
 
Pyramid of-developer-skills
Pyramid of-developer-skillsPyramid of-developer-skills
Pyramid of-developer-skills
 
Applied craftsmanship
Applied craftsmanshipApplied craftsmanship
Applied craftsmanship
 
Pyramid of-developer-skills
Pyramid of-developer-skillsPyramid of-developer-skills
Pyramid of-developer-skills
 
Stay focused
Stay focusedStay focused
Stay focused
 
Kanban intro
Kanban introKanban intro
Kanban intro
 
Unit testing-patterns
Unit testing-patternsUnit testing-patterns
Unit testing-patterns
 
Incremental design, simply explained
Incremental design, simply explainedIncremental design, simply explained
Incremental design, simply explained
 

Último

The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
shinachiaurasa2
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 

Último (20)

%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 

Removing structural duplication

  • 1. Removing Structural Duplication Alex Bolboacă, @alexboly, alex.bolboaca@mozaicworks.com May 2017 1
  • 2. What is Structural Duplication? Why is it a problem? When to remove? Example: Exception management Example: Views How to remove In the End . . . 2
  • 3. What is Structural Duplication? 3
  • 4. Definition Structural duplication (better said, similarity) is a similar code structure that repeats, even though the actions performed inside the structure are different. 4
  • 6. Example: exceptions try{ ... ... } catch(FirstException firstExc){ ... } catch(SecondException secondExc){ ... } try{ ... ... } catch(SecondException secondExc){ ... } catch(ThirdException thirdExc){ ... } 6
  • 7. Example: views <form id="personForm"> <div class="row"> <div class="col-md-4"> Show something here </div> <div class="col-md-4"> Show something different here </div> </div> <div class="row"> <div class="col-md-4"> Show yet something else here </div> <div class="col-md-4"> And again something else here </div> </div> </form> 7
  • 8. Why is it a problem? 8
  • 9. Issues • Risk: when the same structure is spread throughout the code, it’s likely that: • it will grow • it will keep increasing in duplication (eg. we’ll treat ThirdException in the same way in another place) • similar structures might change in similar ways, resulting in duplicated work • Intent hidden inside the structure • Long methods • Duplication in tests 9
  • 11. Criteria for removal • When it appears at least 3 times • When it’s expected to grow • When the intent is unclear • When we expect the structure of the code to change in similar ways in multiple places • Judgement call 11
  • 14. Example code List<Employee> readEmployeesFromDatabase(){ try{ ResultSet rs = stmt.executeQuery( "SELECT id, first, last, age FROM Employees"); List<Employee> employees = new List<Employee>(); while(rs.next()){ employees.add( new Employee(rs.getInt("id"), rs.getString("first"), rs.getString("last"), rs.getInt("age")); } rs.close(); return employees; } catch(SQLException se){ return new List<Employee>(); } catch(Exception e){ log.error("Exception: " + se.toString()); return null; } } 14
  • 16. Step 0: Clarify responsibilities (find the right name) List<Employee> readEmployeesFromDatabaseAndReturnEmptyListOnDbErrorAndLogOtherExceptions(){ .... } 16
  • 17. Step 0: Clarify responsibilities List<Employee> readEmployeesFromDatabaseAndReturnEmptyListO try{ ResultSet rs = stmt.executeQuery( "SELECT id, first, last, age FROM Employees"); List<Employee> employees = new List<Employee>(); while(rs.next()){ employees.add( new Employee(rs.getInt("id"), rs.getString("fir rs.getString("last"), rs.getInt("age")); } rs.close(); return employees; } catch(SQLException se){ return new List<Employee>(); 17
  • 18. Step 0: Separate responsibilities (cont’d) List<Employee> readEmployeesFromDatabaseAndReturnEmptyListOnDbErrorAndLogOtherExceptions(){ try{ List<Employee> employees = readEmployeesFromDatabase(); } catch(SQLException se){ return new List<Employee>(); } catch(Exception e){ log.error("Exception: " + se.toString()); return null; } } 18
  • 19. Step 1: Remove duplication List<Employee> readEmployeesFromDatabaseAndReturnEmptyListOnDbErrorAndLogOtherExceptions(){ try{ List<Employee> employees = readEmployees(); } catch(Exception e){ if(e is SqlException){ return new List<Employee>(); } if(e is Exception){ log.error("Exception: " + se.toString()); return null; } } } 19
  • 20. Step 2: Extract action for each if statement List<Employee> readEmployeesFromDatabase(){ try{ List<Employee> employees = readEmployees(); } catch(Exception e){ if(e is SqlException) return emptyList(); if(e is Exception) return logError(); } } 20
  • 21. Step 3: Refactor to set of rules List<Employee> readEmployeesFromDatabaseAndReturnEmptyListO List rules = new List(){ new Pair( {e -> e is SqlException}, {e -> emptyList()}), new Pair( {e -> e is Exception}, {e -> logError(e)}) } try{ List<Employee> employees = readEmployees(); } catch(Exception e){ return rules.find{e.first(e)}.second(e) } } 21
  • 22. Step 4: Push errors and rules up List<Employee> readEmployeesFromDatabaseAndManageExceptions try{ List<Employee> employees = readEmployees(); } catch(Exception e){ return exceptionManagementRules .find{e.first.call(e)} .second.call(e); } } 22
  • 23. Step 5: Extract final duplication List<Employee> readEmployeesFromDatabase(){ return callWithExceptionManagement( rules, { -> readEmployees();}); } Object callWithExceptionManagement(List<> exceptionManagementRules, action){ try{ action.call(); } catch(Exception e){ return exceptionManagementRules .find{e.first.call(e)} .second.call(e); } } 23
  • 24. Advantages • Clear and consistent set of rules for exception management • Separate the behaviour from exception management (SRP) • Change the exception management rules from one place (OCP) • Easier to write new code of the same kind 24
  • 25. Disadvantages • Can prove difficult to extend for certain exception management treatments. Eg. retries, transactional behaviour etc. • Requires understanding of lambdas • Can be difficult to understand for programmers unused with the idea 25
  • 27. Example Code <form id="personForm"> <div class="row"> <div class="col-md-4"> <label for="firstName"> </div> <div class="col-md-4"> <input id="firstName" type="text" value="Alex"></input> </div> </div> <div class="row"> <div class="col-md-4"> <label for="lastName"> </div> <div class="col-md-4"> <input id="lastName" type="text" value="Bolboacă"></input> </div> </div> </form> 27
  • 28. Step 0: which structure do we want to separate? Could be: • A two column form, if we have many two column forms and expect to change their layout at the same time • A stack of rows, if we have multiple stacks of rows and expect to change them in similar ways (e.g. switch from one grid system to another) • Others, depending on the rest of the code 28
  • 29. Step 1: Separate structure from content <form id="personForm"> <div class="row"> <div class="col-md-4"> <g:render template="firstNameLabel"> </div> <div class="col-md-4"> <g:render template="firstNameInput" model="Alex"> </div> </div> <div class="row"> <div class="col-md-4"> <g:render template src="lastNameLabel"> </div> <div class="col-md-4"> <g:render template="lastNameInput" model="Bolboacă"> </div> </div> </form> 29
  • 30. Step 2: Separate data model from layout [ [ label: [template: 'firstNameLabel'], input: [template: 'firstNameInput', value: 'Alex'] ], [ label: [template: 'lastNameLabel'], input: [template: 'lastNameInput', value: 'Bolboacă'] ] ] 30
  • 31. Step 3: Replace with loop <form id="personForm"> <g:each var="formLine" from="${dataModel}"> <div class="row"> <div class="col-md-4"> <g:render template="${formLine.label.template}"> </div> <div class="col-md-4"> <g:render template="${formLine.input.template}" model="${formLine.input.value}"> </div> </div> </g:each> </form> 31
  • 32. Careful with accidental duplication <div class="col-md-4"> ... </div> <div class="col-md-4"> ... </div> Looks like structural duplication, but label width doesn’t necessarily change at the same time with input width 32
  • 33. Step 4: More separation of layout <form id="personForm"> <g:each var="formLine" from="${dataModel}"> <g:render template="formLine" model="${formLine}"> </g:each> </form> 33
  • 34. Advantages • All two-column forms have the same structure, and we can change it from one place • Smaller, more focused code (SRP) • Follow OCP (yes, it applies to views too!) • Clear where to change details (label and input templates) and where to change structure (form, formLine templates) 34
  • 35. Disadvantages • If only one of the forms changes structure (eg. to three columns), it can be painful (aka rigidity to certain types of change) • Can be harder to navigate to the places where you need to change things. The structure and conventions need to be documented and learned 35
  • 37. Steps 1. Define precisely which structural duplication you want to remove 2. Double-check if it’s accidental 3. Separate structure from actions 4. Extract data structure 5. Replace with loops or functional constructs 37
  • 38. In the End . . . 38
  • 39. Recap • Structural duplication is a code construct that has similar structure but does different actions • If we expect the structure to change in multiple places, it’s worth separating from the actions • It leads to code that follows SRP & OCP • But be very careful at accidental duplication 39