1 of 49

Refactoring II

@windygallery

December 13, 2019 4:30 PM @AddTech Hub Office Meeting room 1, 12 floor.

2 of 49

Outline

  1. Problems & Pains
  2. What: Idea of code refactoring
  3. Why: Benefits
  4. Design concepts
  5. How: Refactoring methods
  6. When: Bad smells
  7. Conclusion

3 of 49

  1. Code growth & Problems

time

Day 0

Day 1

Day 10

Day 100

More code, more problems..

4 of 49

Add new features

5 of 49

Code Refactoring

REUSE

6 of 49

7 of 49

3. Benefits of Code refactoring

  • Easy to understand
  • Easy to add new feature
  • Easy to identify problems/bugs
  • Easy to optimize performance

8 of 49

Cost of Code Refactoring

9 of 49

4. Design concepts

  • Dependency (coupling)
  • Chain of responsibilities
  • Object Oriented Programming
  • Model view controller (MVC)
  • Facade design pattern

10 of 49

Dependency (coupling)

“One of the earliest indicators of design quality was coupling.”�Martin Fowler.

methodB()

methodA()

methodA()

methodB()

11 of 49

Class Leader

main() {

Follower f = new Follower()

f.doTask(this)

f.update(this)

}

Class Follower

# Leader x

  • init()
  • doTask(Leader x)
  • update(x)

Class Follower

  • init()
  • doTask(parameters)

Class Leader

main() {

Follower f = new Follower()

String output = f.doTask(x, y, z, ...)

// use output...

}

Low coupling

Only one side hold knowledge

High coupling

(2 sides of knowledge)

12 of 49

3

5

3

5

6

3

5

Strong coupling

Weak coupling

13 of 49

Chain of responsibility

User input

Query DB

Calcute

Render report

14 of 49

Object oriented programming (1/3): Class & instances

Class

instances

  • Attributes : size, color, height
  • Methods : open(), close(), party()

15 of 49

Object oriented programming (2/3): Inheritance

run()

run()

run()

16 of 49

Object oriented programming (3/3): Encapsulation

  • drive()
  • sleep()
  • eat()
  • wakeup()

  • start()
  • run()
  • stop()
  • charge()

17 of 49

Model view controller (MVC)

Model

Controller

View

18 of 49

Facade design pattern

without facade

Use facade for interfacing

19 of 49

5. Refactoring methods

  • Extract method
  • Move method
  • Extract class
  • Rename
  • Replace temp variable with query
  • Replace Data values with Object

20 of 49

function longTasks() {

doTaskA..

doTaskB..

doTaskC..

doTaskD..

}

21 of 49

Refactoring methods: Extract method

function longTasks() {

doTaskA..

doTaskB..

doTaskC..

doTaskD..

}

function process() {

taskA()

taskB()

taskC()

taskD()

}�

function taskA() { .. }�function taskB() { .. }

function taskC() { .. }

function taskD() { .. }

22 of 49

class Customer

  • registerNewCust()
  • updateProfile()
  • redeemPoint()
  • summaryReport()

23 of 49

Refactoring methods: Move method

class Report

  • summaryReport()

class Customer

  • registerNewCust()
  • updateProfile()
  • redeemPoint()
  • summaryReport()

class Business Logic

  • redeemPoint()

24 of 49

class SuperMan

  • insertDB()
  • updateDB()
  • doSomething()
  • cleanSomething()
  • generateReport()
  • calculateBonus()

25 of 49

Refactoring methods: Extract class

class SuperMan

  • insertDB()
  • updateDB()
  • doSomething()
  • cleanSomething()
  • generateReport()
  • calculateBonus()

class DatabaseManager

  • insertDB()
  • updateDB()

class Business Logic

  • generateReport()
  • calculateBonus()

26 of 49

  • register(name, email, number, code)
  • checkCustomerData()
  • loadCustomerData()

27 of 49

Refactoring methods: Rename

  • register(name, email, number, code)
  • checkCustomerData()
  • loadCustomerData()��
  • registerCustomer(fullname, email, phonenumber, activateCode)
  • isCustomerActive()
  • getCustomerAddress()

28 of 49

let summary = 0�customer.getBasket.foreach(product, quantity) {� let price = product.getPrice()� summary = summary + price * quantity�}

29 of 49

Refactoring methods: Replace temp with Query

let summary = 0�customer.getBasket.foreach(product, quantity) {� let price = product.getPrice()� summary = summary + price * quantity�}�----------------------------------------------------------------------------------------------------------�let summary = 0�customer.getBasket.foreach(product, quantity) {� summary = summary + product.getPrice() * quantity�}

30 of 49

  • processData(fullname, address, phonenumber, email, … )

31 of 49

Refactoring methods: Replace values with Object

  • processData(fullname, address, phonenumber, email, … )��
  • processData(customerObj)

32 of 49

6. Bad smells

  • Duplicated code
  • Long method
  • Big class, Lazy class
  • Long parameter list
  • Divergent Change
  • Shotgun Surgery
  • Feature envy
  • Comment

33 of 49

Duplicate code

Registration

  • register
  • forgotPass
  • sendMail()

Update profile

  • updateProfile
  • sendMail()

34 of 49

Duplicate code

Registration

  • register
  • forgotPass
  • sendMail()

Update profile

  • updateProfile
  • sendMail()

CustomerNotify

  • sendMail()

Move method

35 of 49

Long method

Function A(...) {

queryDatabase..� preprocess#1..� removeNoise..� preprocess#2.. summaryData... process.. calculateReport.. cleanData� update...

}

Function B(...) {

saveData(...)

}

36 of 49

Long method

  • Long method may contains many dependencies
  • Hard to understand all possible flows
  • Hard to find bugs
  • Hard to analyze performance
  • Solutions:
    • Extract method
    • Move method
  • Side benefit: Easy to create unit tests

Function A(...) {

queryDatabase..� preprocess#1..� removeNoise..� preprocess#2.. summaryData... process.. calculateReport.. cleanData� update...

}

Function B(...) {

saveData(...)

}

37 of 49

Big class, lazy class

SuperDad class

  • createDB()
  • registerService()
  • makeReport()
  • notifyCustomer()
  • testConenction()
  • drinkTea()
  • backupService()
  • analyzeThread()

Lazy class

  • sleep()

38 of 49

Big class, lazy class

  • Solutions for Big class:
    • Extract class
    • Rename
    • Move method�
  • Solutions for lazy class:
    • Move method

SuperDad class

  • createDB()
  • registerService()
  • makeReport()
  • notifyCustomer()
  • testConenction()
  • drinkTea()
  • backupService()
  • analyzeThread()

Lazy class

  • sleep()

39 of 49

Long parameter list

  • function login(� username, password, os, appVersion, deviceToken, rootFlag, useragent, hardwareModel, sessonToken, customerSeqment)

40 of 49

Long parameter list

  • Replace values with Object
  • function login(� username, password, os, appVersion, deviceToken, rootFlag, useragent, hardwareModel, sessonToken, customerSeqment)

  • function login(customerObject)

Customer class

41 of 49

Divergent Change class

DatabaseManager

  • initDatabase
  • prepareData
  • QueryMySQL
  • UpdateMySQL
  • InsertMySQL
  • DeleteMySQL
  • QueryMongoDB
  • UpdateMongoDB
  • InsertMongoDB
  • DeleteMongoDB
  • cleanDatabase

42 of 49

Divergent Change class

DatabaseManager

  • initDatabase
  • prepareData
  • QueryMySQL
  • UpdateMySQL
  • InsertMySQL
  • DeleteMySQL
  • QueryMongoDB
  • UpdateMongoDB
  • InsertMongoDB
  • DeleteMongoDB
  • cleanDatabase

MySQLmanager

  • init
  • prepareData
  • Query
  • Update
  • Insert
  • Delete
  • clean

MongoDBmanager

  • init
  • prepareData
  • Query
  • Update
  • Insert
  • Delete
  • clean

Extract class

  • Rename (optional)

43 of 49

Shotgun surgery

Class A

  • Query

Class B

  • Insert
  • Update

Class C

  • initDatabase
  • prepareData

Class D

  • Delete

Class E

  • cleanDatabase

44 of 49

Shotgun surgery

Class A

  • Query

MongoDBmanager

  • initDatabase
  • prepareData
  • Query
  • Update
  • Insert
  • Delete
  • cleanDatabase

Class B

  • Insert
  • Update

Class C

  • initDatabase
  • prepareData

Class D

  • Delete

Class E

  • cleanDatabase

Move method

  • Rename (optional)

45 of 49

Feature envy

Customer

  • addProduct
  • buy
  • calculatePromotion
  • report

Product

  • getPrice
  • getPromotion

46 of 49

Feature envy

Customer

  • addProduct
  • buy
  • calculatePromotion
  • report

Product

  • getPrice
  • getPromotion

Calculate

  • calculate(product[])
  • report()

Move method

47 of 49

Comment

If your code is too complex, you will need to explain

If your function name is confused, you will need comment

Make is Short, Simple and Stupid

48 of 49

Use refactoring techniques to make your code better.

49 of 49

Conclusion

  • Code Refactoring is used for improving understanding, better internal process without changing behaviors
  • We should de code refactoring when codes has some bad smells
  • Less dependency, easier to change, add new features
  • Small change, more reliability