Study with me for Code Refactoring ( Story3 — Long Method of Bloaters)

Thaw Zin Toe
3 min readJan 26, 2023

--

Bloaters are already explained in the previous article Story 2. I want to explain the details of the symptoms and treatments of the Long Method.

Long Method

Symptoms

In clean code, Robert martin was already told that a method line of codes must not be greater than 10. In reality, splitting the use case of the function is a more effective and nice way to readability

# Long Method
fun longMethod() {
# Do first thing
# Do second thing
# Do third thing
# Do fourth thing
}

Treatment

  1. Too complex and too difficult to read in one method — use Extract Method.

Problem

# Extract Method
fun printOwing() {
var outstanding: Double = 0.0
// print banner
println("********************************")
println("******** Customer Owes *********")
println("********************************")

// calculate outstanding
for (orderLine in orderLines) {
outstanding += orderLine.amount
}
// print details
println("Name: $name")
println("Amount: $outstanding")
}

Solution

fun printOwing() {
var amount: Double = 0.0
printBanner()
outstanding = getOutstanding(amount)
printDetails(outstanding)
}

private fun getOutstanding(amount: Double): Double {
var outstanding = previousAmount
for (orderLine in orderLines) {
outstanding += orderLine.amount
}
return outstanding
}

Benefits

  • Less code coupling
  • More readable code
  • More Maintainability
  • More independent parts of the code

2. If local variables and parameters interfere with extracting a method, use Replace Temp with Query, Introduce Parameter Object and Preserve Whole Object

*Replace Temp with Query

Problem

class Order {
var quantity: Int = 0
var itemPrice: Double = 0.0
}

fun proceedOrder(order: Order): Double {
var basePrice = order.quantity * order.itemPrice
var discount = 0.0
if (basePrice > 1000) {
discount = basePrice * 0.05
}
return basePrice - discount
}

Treatment

fun proceedOrder(order: Order): Double {
return order.basePrice() - order.discount()
}

fun Order.basePrice(): Double {
return this.quantity * this.itemPrice
}

fun Order.discount(): Double {
return if (basePrice() > 1000) basePrice() * 0.05 else 0.0
}

Benefits

  • Code readability & maintainability
  • Less Line

*Introduce Paramter method

Problem

fun doStuff(count: Int,items: List<Item>,name: String,isGood: Boolean)
fun doItemUpdate(count: Int,items: List<Item>,name: String,moreItems: Collection)

Treatment

data class DotaGame(
var count: Int,
var items: List<Item>,
var name: String
)

fun doStuff(game: DotaGame,isGood: Boolean)
fun doItemUpdate(game: DotaGame,moreItems: Collection)

Benefit

  • More readable code
  • Identical groups of parameter

*Preserve the Whole Object

Problem

val low = daysTempRange.getLow()
val high = daysTempRange.getHigh()
val withinTemp = plan.withinRange(low, high)

Treatment

val withinTemp = plan.withinRange(daysTempRange)

Benefit

  • no more rewriting when data is more needed in withinRange
  • single object and more readable

3. So many variables in this method — Replace method With Method Object

Problem

fun proceedBlurImage(): BlurImage {
val blurAlpha = 0.5
val greyColor = Color.Grey
val compress = true
val greyImage = Image()
# long calculation
}

Treatment

Class BlurImage {
val blurAlpha = 0.5
val greyColor = Color.Grey
val compress = true
val greyImage = Image()
fun execute(): BlurImage
}

fun proceedBlurImage = BlurImage.execute()

Benefit

  • Independent Code
  • Can Apply Dependency Injection

4. Too many Conditional operators and loops — Decompose Conditional

Problem

if (date.before(WINTER_START) || date.after(WINTER_END)) {
charge = quantity * summerRate
}
else if (date.before(RAINNY_START) || date.after(RAINNY_END)) {
charge = quantity * rainnyRate
}
else {
charge = quantity * winterRate
}

Treatment

enum class Seanson {
SUMMER,
RAINNY,
WINTER
}

fun priceForSummer() = quantity * summerRate
fun priceForRainny() = quantity * rainnyRate
fun priceForWinter() = quantity * winterRate

when(season) {
is Season.SUMMER -> priceForSummer()
is Season.RAINNY -> priceForRainny()
is Season.WINTER -> priceForWinter()
}

Benefit

  • More readable and maintainability

Note: Sometimes so many code extracts or queries the method tends to be more complex and hard to read. So, please keep it simple as much as you can.

This is the end of Story 3.

See you next time, bye-bye 👋

--

--