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

@stanlylau
INTRODUCTION
ABOUT ME
▸ Lives in Singapore
▸ Software development
coach / mentor
▸ Lead Agile Singapore
community
@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()) {
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();
String body = form.getBody();
for (String address : addresses) {
String replacedSubject = subject;
String replacedBody = body;
if (StringUtils.contains(subject, "$name") || StringUtils.contains(body, "$name")) {
AddressItem addressItem = addressBookService.findByAddress(address);
if (addressItem == null) {
throw new Exception("email address is not registered");
}
if (StringUtils.isEmpty(addressItem.getName())) {
throw new Exception("name attribute is empty!!");
}
replacedSubject = StringUtils.replace(subject, "$name", addressItem.getName());
replacedBody = StringUtils.replace(body, "$name", addressItem.getName());
}
MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, replacedBody);
mailInfoList.add(mail);
}
mailService.sendMultiple(mailInfoList);
} catch (Exception e) {
model.addAttribute("errorMessage", "error");
return "send";
}
return "send";
}
loc: 32
DEVELOPERS GET BETTER AT
COMPLEXITY AND SOMETIMES
THEY BELIEVE IT IS INEVITABLE.
EXPERIENCED PROGRAMMERS DO NOT
WRITE INFINITELY COMPLEX CODE;
THEY WRITE CODE THAT’S BLINDINGLY
SIMPLE
99 Bottles of OOP
GROWTH OF A DEVELOPER
THE NATURE OF SOFTWARE DEVELOPMENT
LEARNING THIS NATURE
AND DEALING WITH IT
HELPS TO INCREASE
FLEXIBILITY.
AMOUNT OF
BAD CODE
# BUGS
TIME SPENT
ON FIXING
BUGS
PANIC
QUICK HACKS
MOTIVATION OF
DEVELOPERS
REFACTORING
AMOUNT OF
CODE SMELLS
INDICATES
OPPORTUNITY FOR
IRONICALLY, DEVELOPERS
ARE TOLD TO DO MORE
WHAT CAN HELP?
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
REFACTORING
WHY? WHAT? HOW?
GET READY
FOR
CHANGE
DESIGN 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
DEMO
PERSONALISED EMAILER
WEB APP
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
DESIGN DIRECTION
BRING OUT TEMPLATE
CONCEPT
HOW TO START
HOW TO START
ESSENTIAL SKILLS
▸ Explain the code with design principles
▸ Identify code smells
▸ Refactor either manually or through IDE
▸ Familiar with unit/integration tests
▸ Familiar with functionality behaviour you’re changing
▸ Understand abstractions
TRY CODING DOJO SESSIONS

ON PRODUCTION CODE
PICK CODE SMELLS TO REMOVE
LEARN TO SMELL
THE CODE
CODE SMELLS
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
DESIGN PRINCIPLES
SINGLE RESPONSIBILITY
HI COHESION, LOW COUPLING
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
CRAFTSMANSHIP
REFACTORING IS
AN EXERCISE IN
KINDNESS
Kent Beck
THANK YOU
STANLY@ODD-E.COM

More Related Content

What's hot

ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2RORLAB
 
Wann soll ich mocken?
Wann soll ich mocken?Wann soll ich mocken?
Wann soll ich mocken?David Völkel
 
Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateKiev ALT.NET
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairMark
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Vagif Abilov
 
Enterprise workflow with Apps Script
Enterprise workflow with Apps ScriptEnterprise workflow with Apps Script
Enterprise workflow with Apps Scriptccherubino
 
Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Jo Cranford
 
Functional GUIs with F#
Functional GUIs with F#Functional GUIs with F#
Functional GUIs with F#Frank Krueger
 
Art of Javascript
Art of JavascriptArt of Javascript
Art of JavascriptTarek Yehia
 
Christopher Latham Portfolio
Christopher Latham PortfolioChristopher Latham Portfolio
Christopher Latham Portfoliolathamcl
 

What's hot (15)

ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2
 
JavaScript
JavaScriptJavaScript
JavaScript
 
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?
 
Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicate
 
Form
FormForm
Form
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love Affair
 
Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#Typed? Dynamic? Both! Cross-platform DSLs in C#
Typed? Dynamic? Both! Cross-platform DSLs in C#
 
Web 6 | JavaScript DOM
Web 6 | JavaScript DOMWeb 6 | JavaScript DOM
Web 6 | JavaScript DOM
 
Enterprise workflow with Apps Script
Enterprise workflow with Apps ScriptEnterprise workflow with Apps Script
Enterprise workflow with Apps Script
 
Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012
 
Functional GUIs with F#
Functional GUIs with F#Functional GUIs with F#
Functional GUIs with F#
 
Art of Javascript
Art of JavascriptArt of Javascript
Art of Javascript
 
Python training for beginners
Python training for beginnersPython training for beginners
Python training for beginners
 
Christopher Latham Portfolio
Christopher Latham PortfolioChristopher Latham Portfolio
Christopher Latham Portfolio
 

Similar to Get better at Refactoring | Stanly Lau

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
 
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
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your CodeAbbas Ali
 
Scala in practice
Scala in practiceScala in practice
Scala in practicepatforna
 
WTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaWTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaiMasters
 
Basic Object Oriented Concepts
Basic Object Oriented ConceptsBasic Object Oriented Concepts
Basic Object Oriented ConceptsScott Lee
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Seri Moth
 
מ-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
 
Ext GWT 3.0 Data Widgets
Ext GWT 3.0 Data WidgetsExt GWT 3.0 Data Widgets
Ext GWT 3.0 Data WidgetsSencha
 
Custom Signals for Uncoupled Design
Custom Signals for Uncoupled DesignCustom Signals for Uncoupled Design
Custom Signals for Uncoupled Designecomsmith
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object CalisthenicsPHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object CalisthenicsGuilherme Blanco
 
ABV_fastcontact
ABV_fastcontactABV_fastcontact
ABV_fastcontactarjun rao
 
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBTDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBtdc-globalcode
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB jhchabran
 

Similar to Get better at Refactoring | Stanly Lau (20)

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
 
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
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
WTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio AkitaWTF Oriented Programming, com Fabio Akita
WTF Oriented Programming, com Fabio Akita
 
Basic Object Oriented Concepts
Basic Object Oriented ConceptsBasic Object Oriented Concepts
Basic Object Oriented Concepts
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
 
מ-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
 
typeorm.pdf
typeorm.pdftypeorm.pdf
typeorm.pdf
 
Ext GWT 3.0 Data Widgets
Ext GWT 3.0 Data WidgetsExt GWT 3.0 Data Widgets
Ext GWT 3.0 Data Widgets
 
Custom Signals for Uncoupled Design
Custom Signals for Uncoupled DesignCustom Signals for Uncoupled Design
Custom Signals for Uncoupled Design
 
dfhdf
dfhdfdfhdf
dfhdf
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object CalisthenicsPHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
 
ABV_fastcontact
ABV_fastcontactABV_fastcontact
ABV_fastcontact
 
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBTDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
 
Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB Introduction à CoffeeScript pour ParisRB
Introduction à CoffeeScript pour ParisRB
 
3
33
3
 

More from AgileTour@TW

Let’s build an User-Centered Team | 張朝智
Let’s build an User-Centered Team | 張朝智Let’s build an User-Centered Team | 張朝智
Let’s build an User-Centered Team | 張朝智AgileTour@TW
 
Effective DevOps:一場文化與技術的轉型運動 (陳正瑋)
Effective DevOps:一場文化與技術的轉型運動  (陳正瑋)Effective DevOps:一場文化與技術的轉型運動  (陳正瑋)
Effective DevOps:一場文化與技術的轉型運動 (陳正瑋)AgileTour@TW
 
經濟學角度思考敏捷 (Eviler Chuang)
經濟學角度思考敏捷  (Eviler Chuang)經濟學角度思考敏捷  (Eviler Chuang)
經濟學角度思考敏捷 (Eviler Chuang)AgileTour@TW
 
Scrum Drawing Game 2.0 - Draw Your Dream House (Chao-Kung Liu)
Scrum Drawing Game 2.0 - Draw Your Dream House  (Chao-Kung Liu)Scrum Drawing Game 2.0 - Draw Your Dream House  (Chao-Kung Liu)
Scrum Drawing Game 2.0 - Draw Your Dream House (Chao-Kung Liu)AgileTour@TW
 
Agile In Transition and In Business World | Mick Chung
Agile In Transition and In Business World | Mick ChungAgile In Transition and In Business World | Mick Chung
Agile In Transition and In Business World | Mick ChungAgileTour@TW
 
The Power of Agile Coaching | PK.Chen
The Power of Agile Coaching | PK.ChenThe Power of Agile Coaching | PK.Chen
The Power of Agile Coaching | PK.ChenAgileTour@TW
 
高效溝通 - 揭開促進團隊效能的密碼 | Percy
高效溝通 - 揭開促進團隊效能的密碼 | Percy高效溝通 - 揭開促進團隊效能的密碼 | Percy
高效溝通 - 揭開促進團隊效能的密碼 | PercyAgileTour@TW
 
UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲
UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲
UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲AgileTour@TW
 
敏捷商業分析 | Lisa Chu
敏捷商業分析 | Lisa Chu敏捷商業分析 | Lisa Chu
敏捷商業分析 | Lisa ChuAgileTour@TW
 

More from AgileTour@TW (9)

Let’s build an User-Centered Team | 張朝智
Let’s build an User-Centered Team | 張朝智Let’s build an User-Centered Team | 張朝智
Let’s build an User-Centered Team | 張朝智
 
Effective DevOps:一場文化與技術的轉型運動 (陳正瑋)
Effective DevOps:一場文化與技術的轉型運動  (陳正瑋)Effective DevOps:一場文化與技術的轉型運動  (陳正瑋)
Effective DevOps:一場文化與技術的轉型運動 (陳正瑋)
 
經濟學角度思考敏捷 (Eviler Chuang)
經濟學角度思考敏捷  (Eviler Chuang)經濟學角度思考敏捷  (Eviler Chuang)
經濟學角度思考敏捷 (Eviler Chuang)
 
Scrum Drawing Game 2.0 - Draw Your Dream House (Chao-Kung Liu)
Scrum Drawing Game 2.0 - Draw Your Dream House  (Chao-Kung Liu)Scrum Drawing Game 2.0 - Draw Your Dream House  (Chao-Kung Liu)
Scrum Drawing Game 2.0 - Draw Your Dream House (Chao-Kung Liu)
 
Agile In Transition and In Business World | Mick Chung
Agile In Transition and In Business World | Mick ChungAgile In Transition and In Business World | Mick Chung
Agile In Transition and In Business World | Mick Chung
 
The Power of Agile Coaching | PK.Chen
The Power of Agile Coaching | PK.ChenThe Power of Agile Coaching | PK.Chen
The Power of Agile Coaching | PK.Chen
 
高效溝通 - 揭開促進團隊效能的密碼 | Percy
高效溝通 - 揭開促進團隊效能的密碼 | Percy高效溝通 - 揭開促進團隊效能的密碼 | Percy
高效溝通 - 揭開促進團隊效能的密碼 | Percy
 
UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲
UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲
UX in the Jungle - 如何應用敏捷實務設計出好玩的桌上遊戲
 
敏捷商業分析 | Lisa Chu
敏捷商業分析 | Lisa Chu敏捷商業分析 | Lisa Chu
敏捷商業分析 | Lisa Chu
 

Recently uploaded

Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactPECB
 
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...PsychoTech Services
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Krashi Coaching
 
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...Sapna Thakur
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdfQucHHunhnh
 
fourth grading exam for kindergarten in writing
fourth grading exam for kindergarten in writingfourth grading exam for kindergarten in writing
fourth grading exam for kindergarten in writingTeacherCyreneCayanan
 
Paris 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityParis 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityGeoBlogs
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDThiyagu K
 
Grant Readiness 101 TechSoup and Remy Consulting
Grant Readiness 101 TechSoup and Remy ConsultingGrant Readiness 101 TechSoup and Remy Consulting
Grant Readiness 101 TechSoup and Remy ConsultingTechSoup
 
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in DelhiRussian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhikauryashika82
 
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...EduSkills OECD
 
Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3JemimahLaneBuaron
 
General AI for Medical Educators April 2024
General AI for Medical Educators April 2024General AI for Medical Educators April 2024
General AI for Medical Educators April 2024Janet Corral
 
A Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformA Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformChameera Dedduwage
 
BASLIQ CURRENT LOOKBOOK LOOKBOOK(1) (1).pdf
BASLIQ CURRENT LOOKBOOK  LOOKBOOK(1) (1).pdfBASLIQ CURRENT LOOKBOOK  LOOKBOOK(1) (1).pdf
BASLIQ CURRENT LOOKBOOK LOOKBOOK(1) (1).pdfSoniaTolstoy
 
Interactive Powerpoint_How to Master effective communication
Interactive Powerpoint_How to Master effective communicationInteractive Powerpoint_How to Master effective communication
Interactive Powerpoint_How to Master effective communicationnomboosow
 

Recently uploaded (20)

Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global Impact
 
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
Mattingly "AI & Prompt Design: Structured Data, Assistants, & RAG"
 
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
 
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
 
1029-Danh muc Sach Giao Khoa khoi 6.pdf
1029-Danh muc Sach Giao Khoa khoi  6.pdf1029-Danh muc Sach Giao Khoa khoi  6.pdf
1029-Danh muc Sach Giao Khoa khoi 6.pdf
 
fourth grading exam for kindergarten in writing
fourth grading exam for kindergarten in writingfourth grading exam for kindergarten in writing
fourth grading exam for kindergarten in writing
 
Paris 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityParis 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activity
 
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptxINDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SD
 
Mattingly "AI & Prompt Design: The Basics of Prompt Design"
Mattingly "AI & Prompt Design: The Basics of Prompt Design"Mattingly "AI & Prompt Design: The Basics of Prompt Design"
Mattingly "AI & Prompt Design: The Basics of Prompt Design"
 
Grant Readiness 101 TechSoup and Remy Consulting
Grant Readiness 101 TechSoup and Remy ConsultingGrant Readiness 101 TechSoup and Remy Consulting
Grant Readiness 101 TechSoup and Remy Consulting
 
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in DelhiRussian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
Russian Escort Service in Delhi 11k Hotel Foreigner Russian Call Girls in Delhi
 
Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1
 
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
 
Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3
 
General AI for Medical Educators April 2024
General AI for Medical Educators April 2024General AI for Medical Educators April 2024
General AI for Medical Educators April 2024
 
A Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformA Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy Reform
 
BASLIQ CURRENT LOOKBOOK LOOKBOOK(1) (1).pdf
BASLIQ CURRENT LOOKBOOK  LOOKBOOK(1) (1).pdfBASLIQ CURRENT LOOKBOOK  LOOKBOOK(1) (1).pdf
BASLIQ CURRENT LOOKBOOK LOOKBOOK(1) (1).pdf
 
Interactive Powerpoint_How to Master effective communication
Interactive Powerpoint_How to Master effective communicationInteractive Powerpoint_How to Master effective communication
Interactive Powerpoint_How to Master effective communication
 

Get better at Refactoring | Stanly Lau

  • 1. GET BETTER AT REFACTORING stanly@odd-e.com
 @stanlylau
  • 2. INTRODUCTION ABOUT ME ▸ Lives in Singapore ▸ Software development coach / mentor ▸ Lead Agile Singapore community
  • 3. @RequestMapping(value = "/send", method = RequestMethod.POST) public String post(@ModelAttribute MailSendForm form, Model model) { model.addAttribute("form", form); return "send"; } loc: 4
  • 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
  • 5. @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
  • 6. @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
  • 7. @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
  • 8. @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
  • 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); 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
  • 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(); String body = form.getBody(); for (String address : addresses) { String replacedSubject = subject; String replacedBody = body; if (StringUtils.contains(subject, "$name") || StringUtils.contains(body, "$name")) { AddressItem addressItem = addressBookService.findByAddress(address); if (addressItem == null) { throw new Exception("email address is not registered"); } if (StringUtils.isEmpty(addressItem.getName())) { throw new Exception("name attribute is empty!!"); } replacedSubject = StringUtils.replace(subject, "$name", addressItem.getName()); replacedBody = StringUtils.replace(body, "$name", addressItem.getName()); } MailInfo mail = new MailInfo("gadget.mailsender@gmail.com", address, replacedSubject, replacedBody); mailInfoList.add(mail); } mailService.sendMultiple(mailInfoList); } catch (Exception e) { model.addAttribute("errorMessage", "error"); return "send"; } return "send"; } loc: 32
  • 11. DEVELOPERS GET BETTER AT COMPLEXITY AND SOMETIMES THEY BELIEVE IT IS INEVITABLE.
  • 12. EXPERIENCED PROGRAMMERS DO NOT WRITE INFINITELY COMPLEX CODE; THEY WRITE CODE THAT’S BLINDINGLY SIMPLE 99 Bottles of OOP GROWTH OF A DEVELOPER
  • 13. THE NATURE OF SOFTWARE DEVELOPMENT LEARNING THIS NATURE AND DEALING WITH IT HELPS TO INCREASE FLEXIBILITY. AMOUNT OF BAD CODE # BUGS TIME SPENT ON FIXING BUGS PANIC QUICK HACKS MOTIVATION OF DEVELOPERS REFACTORING AMOUNT OF CODE SMELLS INDICATES OPPORTUNITY FOR
  • 15. WHAT CAN HELP? SOFTWARE MAINTAINABILITY
  • 16. 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
  • 17. REFACTORING WHY? WHAT? HOW? GET READY FOR CHANGE DESIGN CODE SMELLS
  • 18. 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
  • 20.
  • 21. RECEIVED (NORMAL) TO: NON-CONTACT@GMAIL.COM SUBJECT: SEASONS GREETING TO: NON-CONTACT2@GMAIL.COM SUBJECT: SEASONS GREETING
  • 22.
  • 23.
  • 24. RECEIVED (TEMPLATE) TO: STANLY@ODD-E.COM SUBJECT: SEASONS GREETING STANLY TO: AKI@ODD-E.COM SUBJECT: SEASONS GREETING AKI
  • 25. DESIGN DIRECTION BRING OUT TEMPLATE CONCEPT
  • 27. HOW TO START ESSENTIAL SKILLS ▸ Explain the code with design principles ▸ Identify code smells ▸ Refactor either manually or through IDE ▸ Familiar with unit/integration tests ▸ Familiar with functionality behaviour you’re changing ▸ Understand abstractions
  • 28. TRY CODING DOJO SESSIONS
 ON PRODUCTION CODE PICK CODE SMELLS TO REMOVE
  • 29. LEARN TO SMELL THE CODE CODE SMELLS
  • 32.
  • 33. 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
  • 35. REFACTORING IS AN EXERCISE IN KINDNESS Kent Beck