SlideShare a Scribd company logo
1 of 53
Download to read offline
GET BETTER AT REFACTORING
stanly@odd-e.com

@stanlylau
INTRODUCTION
ABOUT ME
▸ Lives in Singapore
▸ Software development coach /
mentor
▸ Goal: Reduce the cost of change
▸ Agile Singapore community
1. PROBLEM
2. REFACTORING
3. DEMO
4. TIPS
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String post(@ModelAttribute MailSendForm form, Model model) {
model.addAttribute("form", form);
return "send";
}
loc: 4
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String post(@ModelAttribute MailSendForm form, Model model) {
// TODO Validate Request
String address = form.getAddress();
boolean isMailAddress = Validator.isMailAddress(address);
if (!isMailAddress) {
model.addAttribute("form", form);
model.addAttribute("error", "error");
return "send";
}
String subject = form.getSubject();
boolean isSubject = Validator.isSubject(subject);
String body = form.getBody();
boolean isBody = Validator.isBody(body);
// TODO Mail Send
// TODO Show the page
model.addAttribute("form", form);
return "send";
}
loc: 14
@RequestMapping(value = "/sendEmail", method = RequestMethod.POST)
public String sendEmail(@ModelAttribute MailSendForm form, Model model) {
if (!Validator.isMailAddress(form.getAddress())) {
model.addAttribute("error", "error");
return "send";
}
if (!Validator.isSubject(form.getSubject())) {
model.addAttribute("error", "error");
return "send";
}
if (!Validator.isBody(form.getBody())) {
model.addAttribute("error", "error");
return "send";
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com",
form.getAddress(), form.getSubject(), form.getBody());
try {
mailService.send(mail);
} catch (Exception e) {
e.printStackTrace();
}
return "send";
}
loc: 17
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model)
{
if (result.hasErrors()) {
model.addAttribute("errorMessage", "error");
return "send";
}
String[] addresses = form.getAddress().split("s*;s*");
boolean isValid = Stream.of(addresses).anyMatch(address -> !Validator.isMailAddress(address));
if (isValid) {
model.addAttribute("errorMessage", "error");
return "send";
}
for (String address : addresses) {
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, form.getSubject(),
form.getBody());
try {
mailService.send(mail);
} catch (Exception e) {
model.addAttribute("errorMessage", "error");
return "send";
}
}
return "send";
}
loc: 18
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String sendEmail(@ModelAttribute MailSendForm form, Model model) {
if (!Validator.isSubject(form.getSubject())) {
model.addAttribute("errorMessage", "error");
return "send";
}
if (!Validator.isBody(form.getBody())) {
model.addAttribute("errorMessage", "error");
return "send";
}
String addressFromForm = form.getAddress();
if (StringUtils.isEmpty(addressFromForm)) {
model.addAttribute("errorMessage", "error");
return "send";
}
String[] addresses = addressFromForm.split(";");
for(String address : addresses) {
if (!Validator.isMailAddress(address)) {
model.addAttribute("errorMessage", "error");
return "send";
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, form.getSubject(),
form.getBody());
try {
mailService.send(mail);
} catch (Exception e) {
model.addAttribute("errorMessage", "error");
}
}
return "send";
}
loc: 23
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("errorMessage", "error");
return "send";
}
String[] addresses = form.getAddress().split(“s*;s*");
boolean isValid = Stream.of(addresses).anyMatch(address -> !Validator.isMailAddress(address));
if (isValid) {
model.addAttribute("errorMessage", "error");
return "send";
}
try {
List<MailInfo> mailInfoList = new ArrayList<>();
String subject = form.getSubject();
for (String address : addresses) {
AddressItem addressItem = addressBookService.findByAddress(address);
if (addressItem != null) {
if (StringUtils.isEmpty(addressItem.getName()) && StringUtils.contains(subject, "$name")) {
throw new Exception("name attribute is empty!!");
}
subject = StringUtils.replace(subject, "$name", addressItem.getName());
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, subject, form.getBody());
mailInfoList.add(mail);
}
mailService.sendMultiple(mailInfoList);
} catch (Exception e) {
model.addAttribute("errorMessage", "error");
return "send";
}
return "send";
loc: 26
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("errorMessage", "error");
return "send";
}
String[] addresses = form.getAddress().split("s*;s*");
boolean isValid = Stream.of(addresses).anyMatch(address -> !Validator.isMailAddress(address));
if (isValid) {
model.addAttribute("errorMessage", "error");
return "send";
}
try {
List<MailInfo> mailInfoList = new ArrayList<>();
String subject = form.getSubject();
for (String address : addresses) {
AddressItem addressItem = addressBookService.findByAddress(address);
String replacedSubject = subject;
if (addressItem != null) {
if (StringUtils.isEmpty(addressItem.getName()) && StringUtils.contains(subject, "$name")) {
throw new Exception("name attribute is empty!!");
}
replacedSubject = StringUtils.replace(subject, "$name", addressItem.getName());
}else {
if (StringUtils.contains(subject, "$name")){
throw new Exception("email address is not registered");
}
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, form.getBody());
mailInfoList.add(mail);
}
mailService.sendMultiple(mailInfoList);
} catch (Exception e) {
model.addAttribute("errorMessage", "error");
return "send";
}
return "send";
loc: 30
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
FieldError fieldError = result.getFieldErrors().get(0);
model.addAttribute("errorMessage", fieldError.getField() + " " + fieldError.getDefaultMessage());
return "send";
}
String[] addresses = form.getAddress().split("s*;s*");
boolean isValid = Stream.of(addresses)
.anyMatch(address -> !Validator.isMailAddress(address));
if (isValid) {
model.addAttribute("errorMessage", "Email address is invalid");
return "send";
}
try {
List<MailInfo> mailInfoList = new ArrayList<>();
String subject = form.getSubject();
String body = form.getBody();
for (String address : addresses) {
Contact addressItem = addressBookService.findByAddress(address);
String replacedSubject = subject;
String replacedBody = body;
if (addressItem != null) {
if ("".equals(addressItem.getName()) && (subject.contains("$name") || body.contains("$name"))) {
throw new Exception("Can't render template with an empty name in contact");
}
replacedSubject = subject.replace("$name", addressItem.getName());
replacedBody = body.replace("$name", addressItem.getName());
}else {
if (subject.contains("$name") || body.contains("$name")){
throw new Exception("No matching contact found to render template");
}
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, replacedBody);
mailInfoList.add(mail);
}
mailService.sendMultiple(mailInfoList);
} catch (Exception e) {
model.addAttribute("errorMessage", e.getMessage());
return "send";
}
return "send";
}
loc: 33
http://www.marketingfirepower.info
A NATURE OF SOFTWARE DEVELOPMENT
AMOUNT OF
"BAD” CODE
# BUGS
TIME SPENT
ON FIXING
BUGS
PANIC
QUICK HACKS
MOTIVATION OF
DEVELOPERS
CASUAL LOOP
DIAGRAM
A NATURE OF SOFTWARE DEVELOPMENT
REQUIREMENTS
TIME
(you)
(competitor)
COMPETING BY CHANGE
The Management of Computer Programming Projects
Charles Lecht - 1967
Equally responsible for the initiation of project with
predefined failure is management that insists upon having
fixed commitments from programming personnel prior to
the latter’s understanding what the commitment are for.
Too frequently, management does not realize that in
asking the staff for “the impossible”, the staff will feel the
obligation to respond out of respect, fear or misguided
loyalty. Saying “no” to the boss frequently requires
courage, political and psychological wisdom, and
business maturity that comes with much experience.
A NATURE OF SOFTWARE DEVELOPMENT
AMOUNT OF
"BAD” CODE
# BUGS
TIME SPENT
ON FIXING
BUGS
PANIC
QUICK HACKS
MOTIVATION OF
DEVELOPERS
AMOUNT OF
CODE SMELLS
REFACTORING
OPPORTUNITY FOR
INDICATES
REFACTORING 101
SOFTWARE MAINTAINABILITY
REFACTORING
“…IS A DISCIPLINED TECHNIQUE FOR
RESTRUCTURING AN EXISTING BODY OF
CODE, ALTERING ITS INTERNAL
STRUCTURE WITHOUT CHANGING ITS
EXTERNAL BEHAVIOR.”
MARTIN FOWLER
INTRODUCE
PARAMETER OBJECT
EXTRACT CLASS
INTRODUCE
LOCAL VARIABLE
RENAME
MOVE METHODEXTRACT METHOD
INLINE VARIABLE
Q: WHEN DO WE REFACTOR?
A: WHEN THE CODE SMELLS!
CODE SMELLS
“A CODE SMELL IS A SURFACE
INDICATION THAT USUALLY
CORRESPONDS TO A DEEPER PROBLEM
IN THE SYSTEM”
MARTIN FOWLER
DUPLICATED CODE
MAGIC NUMBER
FEATURE ENVY
PRIMITIVE OBSESSION
LONG METHOD
COMMENTS
ABOUT DEMO
PERSONALISED EMAILER
WEB APP
JAVA
SPRING MVC
RECEIVED (NORMAL)
TO: NON-CONTACT@GMAIL.COM
SUBJECT: SEASONS GREETING
TO: NON-CONTACT2@GMAIL.COM
SUBJECT: SEASONS GREETING
RECEIVED (TEMPLATE)
TO: STANLY@ODD-E.COM
SUBJECT: SEASONS GREETING STANLY
TO: AKI@ODD-E.COM
SUBJECT: SEASONS GREETING AKI
Subject with
attribute
Body with
attribute
Send to
multiple
recipients …
✓ ✓
@RequestMapping(value = "/send", method = RequestMethod.POST)
public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) {
if (result.hasErrors()) {
FieldError fieldError = result.getFieldErrors().get(0);
model.addAttribute("errorMessage", fieldError.getField() + " " + fieldError.getDefaultMessage());
return "send";
}
String[] addresses = form.getAddress().split("s*;s*");
boolean isValid = Stream.of(addresses)
.anyMatch(address -> !Validator.isMailAddress(address));
if (isValid) {
model.addAttribute("errorMessage", "Email address is invalid");
return "send";
}
try {
List<MailInfo> mailInfoList = new ArrayList<>();
String subject = form.getSubject();
String body = form.getBody();
for (String address : addresses) {
Contact addressItem = addressBookService.findByAddress(address);
String replacedSubject = subject;
String replacedBody = body;
if (addressItem != null) {
if ("".equals(addressItem.getName()) && (subject.contains("$name") || body.contains("$name"))) {
throw new Exception("Can't render template with an empty name in contact");
}
replacedSubject = subject.replace("$name", addressItem.getName());
replacedBody = body.replace("$name", addressItem.getName());
}else {
if (subject.contains("$name") || body.contains("$name")){
throw new Exception("No matching contact found to render template");
}
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, replacedBody);
mailInfoList.add(mail);
}
mailService.sendMultiple(mailInfoList);
} catch (Exception e) {
model.addAttribute("errorMessage", e.getMessage());
return "send";
}
return "send";
}
WHAT DID YOU
SMELL?
WHAT DID YOU
SMELL?
L O N G M E T H O D
MailController

——————

sendEmail()
MailInfo
AddressBookService

(interface)

———————

findAddress()
MailService

(interface)

——————

sendMultiple()
MailSendForm
LET’S REFACTOR
sendEmail()
CODE COVERAGE
✓
MailController

——————

sendEmail()
Mail
ContactDao

(interface)

———————

findAddress()
MailService

(interface)

——————

sendMultiple()
EmailTemplate

————-————

populate()

hasPopulateError()

getPopulateErrorMessage()
CODE SMELLS
LONG METHOD
TEMPORARY VARIABLE
FEATURE ENVY
DUPLICATE CODE
MAGIC NUMBER
UNCOMMUNICATIVE NAME
PRIMITIVE OBSESSION
sendEmail()
BREAKS SINGLE RESPONSIBILITY
MAIL CREATION
ERROR HANDLING
TEMPLATE RENDERING
VALIDITY OF RECIPIENT ADDRESS
REFACTORING
EXTRACT METHOD
INLINE VAR. / METHOD
INTRODUCE PARAMETER
RENAME
MOVE METHOD
TIPS
LEARN TO SMELL
THE CODE
CODE SMELLS
DESIGN PRINCIPLES
SINGLE RESPONSIBILITY
HI COHESION, LOW COUPLING
while(change_for_new_functionality()){
DO_NOT_REFACTOR()
}
PROGRAMMING IS THE ART OF
DOING ONE THING AT A TIME
Michael Feathers
TIPS
REFACTORING
WHY? WHAT? HOW?
GET READY
FOR
CHANGE
DESIGN CODE
SMELLS
HOW TO START
ESSENTIAL SKILLS
▸ Explain the code with design principles
▸ Identify code smells
▸ Refactor either manually or through IDE
▸ Familiar working with unit/integration tests
▸ Familiar with the functionality you’re changing
PRACTICE
REFACTORING KATA
https://github.com/stanlylau/tictactoe_csharp
https://github.com/stanlylau/refactoring-kata
https://github.com/emilybache/Tennis-Refactoring-Kata
https://github.com/emilybache/GildedRose-Refactoring-Kata
https://github.com/stanlylau/trivia-csharp
TEACH TO LEARN
1. CREATE CODE SMELLS EXERCISES
2. PRACTICE REMOVING THE SMELLS
3. INVITE PEOPLE TO REMOVE THE SMELLS
4. CODE REVIEW
5. DEMO
Unconscious

Competence
Conscious

Competence
Conscious

Incompetence
Unconscious

Incompetence
FOUR STAGES OF COMPETENCE
TO LEVEL UP
REVIEW THE CODE WITH A MENTOR,
BE REFLECTIVE
EXPERIENCED PROGRAMMERS DO NOT
WRITE INFINITELY COMPLEX CODE;
THEY WRITE CODE THAT’S BLINDINGLY
SIMPLE
99 Bottles of OOP
TIPS
REFACTORING IS
AN EXERCISE IN
KINDNESS
Kent Beck
THANK YOU
STANLY@ODD-E.COM

More Related Content

What's hot

Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Jo Cranford
 
Enterprise workflow with Apps Script
Enterprise workflow with Apps ScriptEnterprise workflow with Apps Script
Enterprise workflow with Apps Scriptccherubino
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysqlKnoldus Inc.
 
Why (I think) CoffeeScript Is Awesome
Why (I think) CoffeeScript Is AwesomeWhy (I think) CoffeeScript Is Awesome
Why (I think) CoffeeScript Is AwesomeJo Cranford
 
Wann soll ich mocken?
Wann soll ich mocken?Wann soll ich mocken?
Wann soll ich mocken?David Völkel
 
How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF Luc Bors
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
jQuery Rescue Adventure
jQuery Rescue AdventurejQuery Rescue Adventure
jQuery Rescue AdventureAllegient
 
MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...
MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...
MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...jaxconf
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Scala Quick Introduction
Scala Quick IntroductionScala Quick Introduction
Scala Quick IntroductionDamian Jureczko
 

What's hot (16)

Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012
 
Enterprise workflow with Apps Script
Enterprise workflow with Apps ScriptEnterprise workflow with Apps Script
Enterprise workflow with Apps Script
 
SOLID in Practice
SOLID in PracticeSOLID in Practice
SOLID in Practice
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysql
 
Why (I think) CoffeeScript Is Awesome
Why (I think) CoffeeScript Is AwesomeWhy (I think) CoffeeScript Is Awesome
Why (I think) CoffeeScript Is Awesome
 
Web 5 | JavaScript Events
Web 5 | JavaScript EventsWeb 5 | JavaScript Events
Web 5 | JavaScript Events
 
Wann soll ich mocken?
Wann soll ich mocken?Wann soll ich mocken?
Wann soll ich mocken?
 
How te bring common UI patterns to ADF
How te bring common UI patterns to ADFHow te bring common UI patterns to ADF
How te bring common UI patterns to ADF
 
How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Web 6 | JavaScript DOM
Web 6 | JavaScript DOMWeb 6 | JavaScript DOM
Web 6 | JavaScript DOM
 
jQuery Rescue Adventure
jQuery Rescue AdventurejQuery Rescue Adventure
jQuery Rescue Adventure
 
MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...
MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...
MVC on the Server and on the Client: How to Integrate Spring MVC and Backbone...
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Scala Quick Introduction
Scala Quick IntroductionScala Quick Introduction
Scala Quick Introduction
 
Python training for beginners
Python training for beginnersPython training for beginners
Python training for beginners
 

Similar to Get better at Refactoring (Voxxed Days)

Get better at Refactoring | Stanly Lau
Get better at Refactoring | Stanly LauGet better at Refactoring | Stanly Lau
Get better at Refactoring | Stanly LauAgileTour@TW
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your CodeAbbas Ali
 
SPFx working with SharePoint data
SPFx working with SharePoint dataSPFx working with SharePoint data
SPFx working with SharePoint dataVladimir Medina
 
SPFx: Working with SharePoint Content
SPFx: Working with SharePoint ContentSPFx: Working with SharePoint Content
SPFx: Working with SharePoint ContentVladimir Medina
 
WTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaWTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaiMasters
 
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכיריםמ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכיריםMiriam Schwab
 
WordPress: From Antispambot to Zeroize
WordPress: From Antispambot to ZeroizeWordPress: From Antispambot to Zeroize
WordPress: From Antispambot to ZeroizeYoav Farhi
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Seri Moth
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrowPete McFarlane
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB jhchabran
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Codestasimus
 
Basic Object Oriented Concepts
Basic Object Oriented ConceptsBasic Object Oriented Concepts
Basic Object Oriented ConceptsScott Lee
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web developmentJohannes Brodwall
 
Webmontag Berlin "coffee script"
Webmontag Berlin "coffee script"Webmontag Berlin "coffee script"
Webmontag Berlin "coffee script"Webmontag Berlin
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 

Similar to Get better at Refactoring (Voxxed Days) (20)

Get better at Refactoring | Stanly Lau
Get better at Refactoring | Stanly LauGet better at Refactoring | Stanly Lau
Get better at Refactoring | Stanly Lau
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
SPFx working with SharePoint data
SPFx working with SharePoint dataSPFx working with SharePoint data
SPFx working with SharePoint data
 
SPFx: Working with SharePoint Content
SPFx: Working with SharePoint ContentSPFx: Working with SharePoint Content
SPFx: Working with SharePoint Content
 
WTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaWTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio Akita
 
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכיריםמ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
 
WordPress: From Antispambot to Zeroize
WordPress: From Antispambot to ZeroizeWordPress: From Antispambot to Zeroize
WordPress: From Antispambot to Zeroize
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
 
Week 12 code
Week 12 codeWeek 12 code
Week 12 code
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB
 
Leveraging Symfony2 Forms
Leveraging Symfony2 FormsLeveraging Symfony2 Forms
Leveraging Symfony2 Forms
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Basic Object Oriented Concepts
Basic Object Oriented ConceptsBasic Object Oriented Concepts
Basic Object Oriented Concepts
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Webmontag Berlin "coffee script"
Webmontag Berlin "coffee script"Webmontag Berlin "coffee script"
Webmontag Berlin "coffee script"
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
PHP POWERPOINT SLIDES
PHP POWERPOINT SLIDESPHP POWERPOINT SLIDES
PHP POWERPOINT SLIDES
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 

Recently uploaded

SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
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.docxComplianceQuest1
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
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.pdfkalichargn70th171
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 

Recently uploaded (20)

SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
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
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
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
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 

Get better at Refactoring (Voxxed Days)

  • 1. GET BETTER AT REFACTORING stanly@odd-e.com
 @stanlylau
  • 2. INTRODUCTION ABOUT ME ▸ Lives in Singapore ▸ Software development coach / mentor ▸ Goal: Reduce the cost of change ▸ Agile Singapore community
  • 4. @RequestMapping(value = "/send", method = RequestMethod.POST) public String post(@ModelAttribute MailSendForm form, Model model) { model.addAttribute("form", form); return "send"; } loc: 4
  • 5. @RequestMapping(value = "/send", method = RequestMethod.POST) public String post(@ModelAttribute MailSendForm form, Model model) { // TODO Validate Request String address = form.getAddress(); boolean isMailAddress = Validator.isMailAddress(address); if (!isMailAddress) { model.addAttribute("form", form); model.addAttribute("error", "error"); return "send"; } String subject = form.getSubject(); boolean isSubject = Validator.isSubject(subject); String body = form.getBody(); boolean isBody = Validator.isBody(body); // TODO Mail Send // TODO Show the page model.addAttribute("form", form); return "send"; } loc: 14
  • 6. @RequestMapping(value = "/sendEmail", method = RequestMethod.POST) public String sendEmail(@ModelAttribute MailSendForm form, Model model) { if (!Validator.isMailAddress(form.getAddress())) { model.addAttribute("error", "error"); return "send"; } if (!Validator.isSubject(form.getSubject())) { model.addAttribute("error", "error"); return "send"; } if (!Validator.isBody(form.getBody())) { model.addAttribute("error", "error"); return "send"; } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", form.getAddress(), form.getSubject(), form.getBody()); try { mailService.send(mail); } catch (Exception e) { e.printStackTrace(); } return "send"; } loc: 17
  • 7. @RequestMapping(value = "/send", method = RequestMethod.POST) public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) { if (result.hasErrors()) { model.addAttribute("errorMessage", "error"); return "send"; } String[] addresses = form.getAddress().split("s*;s*"); boolean isValid = Stream.of(addresses).anyMatch(address -> !Validator.isMailAddress(address)); if (isValid) { model.addAttribute("errorMessage", "error"); return "send"; } for (String address : addresses) { MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, form.getSubject(), form.getBody()); try { mailService.send(mail); } catch (Exception e) { model.addAttribute("errorMessage", "error"); return "send"; } } return "send"; } loc: 18
  • 8. @RequestMapping(value = "/send", method = RequestMethod.POST) public String sendEmail(@ModelAttribute MailSendForm form, Model model) { if (!Validator.isSubject(form.getSubject())) { model.addAttribute("errorMessage", "error"); return "send"; } if (!Validator.isBody(form.getBody())) { model.addAttribute("errorMessage", "error"); return "send"; } String addressFromForm = form.getAddress(); if (StringUtils.isEmpty(addressFromForm)) { model.addAttribute("errorMessage", "error"); return "send"; } String[] addresses = addressFromForm.split(";"); for(String address : addresses) { if (!Validator.isMailAddress(address)) { model.addAttribute("errorMessage", "error"); return "send"; } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, form.getSubject(), form.getBody()); try { mailService.send(mail); } catch (Exception e) { model.addAttribute("errorMessage", "error"); } } return "send"; } loc: 23
  • 9. @RequestMapping(value = "/send", method = RequestMethod.POST) public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) { if (result.hasErrors()) { model.addAttribute("errorMessage", "error"); return "send"; } String[] addresses = form.getAddress().split(“s*;s*"); boolean isValid = Stream.of(addresses).anyMatch(address -> !Validator.isMailAddress(address)); if (isValid) { model.addAttribute("errorMessage", "error"); return "send"; } try { List<MailInfo> mailInfoList = new ArrayList<>(); String subject = form.getSubject(); for (String address : addresses) { AddressItem addressItem = addressBookService.findByAddress(address); if (addressItem != null) { if (StringUtils.isEmpty(addressItem.getName()) && StringUtils.contains(subject, "$name")) { throw new Exception("name attribute is empty!!"); } subject = StringUtils.replace(subject, "$name", addressItem.getName()); } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, subject, form.getBody()); mailInfoList.add(mail); } mailService.sendMultiple(mailInfoList); } catch (Exception e) { model.addAttribute("errorMessage", "error"); return "send"; } return "send"; loc: 26
  • 10. @RequestMapping(value = "/send", method = RequestMethod.POST) public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) { if (result.hasErrors()) { model.addAttribute("errorMessage", "error"); return "send"; } String[] addresses = form.getAddress().split("s*;s*"); boolean isValid = Stream.of(addresses).anyMatch(address -> !Validator.isMailAddress(address)); if (isValid) { model.addAttribute("errorMessage", "error"); return "send"; } try { List<MailInfo> mailInfoList = new ArrayList<>(); String subject = form.getSubject(); for (String address : addresses) { AddressItem addressItem = addressBookService.findByAddress(address); String replacedSubject = subject; if (addressItem != null) { if (StringUtils.isEmpty(addressItem.getName()) && StringUtils.contains(subject, "$name")) { throw new Exception("name attribute is empty!!"); } replacedSubject = StringUtils.replace(subject, "$name", addressItem.getName()); }else { if (StringUtils.contains(subject, "$name")){ throw new Exception("email address is not registered"); } } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, form.getBody()); mailInfoList.add(mail); } mailService.sendMultiple(mailInfoList); } catch (Exception e) { model.addAttribute("errorMessage", "error"); return "send"; } return "send"; loc: 30
  • 11. @RequestMapping(value = "/send", method = RequestMethod.POST) public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) { if (result.hasErrors()) { FieldError fieldError = result.getFieldErrors().get(0); model.addAttribute("errorMessage", fieldError.getField() + " " + fieldError.getDefaultMessage()); return "send"; } String[] addresses = form.getAddress().split("s*;s*"); boolean isValid = Stream.of(addresses) .anyMatch(address -> !Validator.isMailAddress(address)); if (isValid) { model.addAttribute("errorMessage", "Email address is invalid"); return "send"; } try { List<MailInfo> mailInfoList = new ArrayList<>(); String subject = form.getSubject(); String body = form.getBody(); for (String address : addresses) { Contact addressItem = addressBookService.findByAddress(address); String replacedSubject = subject; String replacedBody = body; if (addressItem != null) { if ("".equals(addressItem.getName()) && (subject.contains("$name") || body.contains("$name"))) { throw new Exception("Can't render template with an empty name in contact"); } replacedSubject = subject.replace("$name", addressItem.getName()); replacedBody = body.replace("$name", addressItem.getName()); }else { if (subject.contains("$name") || body.contains("$name")){ throw new Exception("No matching contact found to render template"); } } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, replacedBody); mailInfoList.add(mail); } mailService.sendMultiple(mailInfoList); } catch (Exception e) { model.addAttribute("errorMessage", e.getMessage()); return "send"; } return "send"; } loc: 33
  • 13. A NATURE OF SOFTWARE DEVELOPMENT AMOUNT OF "BAD” CODE # BUGS TIME SPENT ON FIXING BUGS PANIC QUICK HACKS MOTIVATION OF DEVELOPERS CASUAL LOOP DIAGRAM
  • 14. A NATURE OF SOFTWARE DEVELOPMENT REQUIREMENTS TIME (you) (competitor) COMPETING BY CHANGE
  • 15. The Management of Computer Programming Projects Charles Lecht - 1967 Equally responsible for the initiation of project with predefined failure is management that insists upon having fixed commitments from programming personnel prior to the latter’s understanding what the commitment are for. Too frequently, management does not realize that in asking the staff for “the impossible”, the staff will feel the obligation to respond out of respect, fear or misguided loyalty. Saying “no” to the boss frequently requires courage, political and psychological wisdom, and business maturity that comes with much experience.
  • 16. A NATURE OF SOFTWARE DEVELOPMENT AMOUNT OF "BAD” CODE # BUGS TIME SPENT ON FIXING BUGS PANIC QUICK HACKS MOTIVATION OF DEVELOPERS AMOUNT OF CODE SMELLS REFACTORING OPPORTUNITY FOR INDICATES
  • 18. REFACTORING “…IS A DISCIPLINED TECHNIQUE FOR RESTRUCTURING AN EXISTING BODY OF CODE, ALTERING ITS INTERNAL STRUCTURE WITHOUT CHANGING ITS EXTERNAL BEHAVIOR.” MARTIN FOWLER INTRODUCE PARAMETER OBJECT EXTRACT CLASS INTRODUCE LOCAL VARIABLE RENAME MOVE METHODEXTRACT METHOD INLINE VARIABLE
  • 19. Q: WHEN DO WE REFACTOR? A: WHEN THE CODE SMELLS!
  • 20. CODE SMELLS “A CODE SMELL IS A SURFACE INDICATION THAT USUALLY CORRESPONDS TO A DEEPER PROBLEM IN THE SYSTEM” MARTIN FOWLER DUPLICATED CODE MAGIC NUMBER FEATURE ENVY PRIMITIVE OBSESSION LONG METHOD COMMENTS
  • 23.
  • 24. RECEIVED (NORMAL) TO: NON-CONTACT@GMAIL.COM SUBJECT: SEASONS GREETING TO: NON-CONTACT2@GMAIL.COM SUBJECT: SEASONS GREETING
  • 25.
  • 26.
  • 27. RECEIVED (TEMPLATE) TO: STANLY@ODD-E.COM SUBJECT: SEASONS GREETING STANLY TO: AKI@ODD-E.COM SUBJECT: SEASONS GREETING AKI
  • 28. Subject with attribute Body with attribute Send to multiple recipients … ✓ ✓
  • 29. @RequestMapping(value = "/send", method = RequestMethod.POST) public String sendEmail(@Valid @ModelAttribute MailSendForm form, BindingResult result, Model model) { if (result.hasErrors()) { FieldError fieldError = result.getFieldErrors().get(0); model.addAttribute("errorMessage", fieldError.getField() + " " + fieldError.getDefaultMessage()); return "send"; } String[] addresses = form.getAddress().split("s*;s*"); boolean isValid = Stream.of(addresses) .anyMatch(address -> !Validator.isMailAddress(address)); if (isValid) { model.addAttribute("errorMessage", "Email address is invalid"); return "send"; } try { List<MailInfo> mailInfoList = new ArrayList<>(); String subject = form.getSubject(); String body = form.getBody(); for (String address : addresses) { Contact addressItem = addressBookService.findByAddress(address); String replacedSubject = subject; String replacedBody = body; if (addressItem != null) { if ("".equals(addressItem.getName()) && (subject.contains("$name") || body.contains("$name"))) { throw new Exception("Can't render template with an empty name in contact"); } replacedSubject = subject.replace("$name", addressItem.getName()); replacedBody = body.replace("$name", addressItem.getName()); }else { if (subject.contains("$name") || body.contains("$name")){ throw new Exception("No matching contact found to render template"); } } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, replacedBody); mailInfoList.add(mail); } mailService.sendMultiple(mailInfoList); } catch (Exception e) { model.addAttribute("errorMessage", e.getMessage()); return "send"; } return "send"; }
  • 31. WHAT DID YOU SMELL? L O N G M E T H O D
  • 35. CODE SMELLS LONG METHOD TEMPORARY VARIABLE FEATURE ENVY DUPLICATE CODE MAGIC NUMBER UNCOMMUNICATIVE NAME PRIMITIVE OBSESSION
  • 36. sendEmail() BREAKS SINGLE RESPONSIBILITY MAIL CREATION ERROR HANDLING TEMPLATE RENDERING VALIDITY OF RECIPIENT ADDRESS
  • 37. REFACTORING EXTRACT METHOD INLINE VAR. / METHOD INTRODUCE PARAMETER RENAME MOVE METHOD
  • 38. TIPS
  • 39. LEARN TO SMELL THE CODE CODE SMELLS
  • 41.
  • 43. PROGRAMMING IS THE ART OF DOING ONE THING AT A TIME Michael Feathers TIPS
  • 44. REFACTORING WHY? WHAT? HOW? GET READY FOR CHANGE DESIGN CODE SMELLS
  • 45. HOW TO START ESSENTIAL SKILLS ▸ Explain the code with design principles ▸ Identify code smells ▸ Refactor either manually or through IDE ▸ Familiar working with unit/integration tests ▸ Familiar with the functionality you’re changing
  • 47. TEACH TO LEARN 1. CREATE CODE SMELLS EXERCISES 2. PRACTICE REMOVING THE SMELLS 3. INVITE PEOPLE TO REMOVE THE SMELLS 4. CODE REVIEW 5. DEMO
  • 49. TO LEVEL UP REVIEW THE CODE WITH A MENTOR, BE REFLECTIVE
  • 50. EXPERIENCED PROGRAMMERS DO NOT WRITE INFINITELY COMPLEX CODE; THEY WRITE CODE THAT’S BLINDINGLY SIMPLE 99 Bottles of OOP TIPS
  • 51.
  • 52. REFACTORING IS AN EXERCISE IN KINDNESS Kent Beck