Sitemap
Radinal Dwiki Novendra, S.T., M.T.

Radinal Dwiki Novendra, S.T., M.T.

Everything you can imagine is real.

Code Smell and Refactoring — Bloaters

5 min readMar 28, 2023

--

Bloaters merupakan class dan method yang semakin gemuk (besar) sehingga sulit untuk dipahami. Biasanya smell ini tidak langsung muncul, melainkan berangsur-angsur bertambah seiring pengembangan program.

A. Long Function / Long Method

Press enter or click to view image in full size
image source : https://refactoring.guru/

Definisi

Merupakan method yang terlalu panjang atau berisi terlalu banyak baris kode. Menurut Fowler (2018), program yang memiliki fungsi yang pendek adalah program yang hidupnya paling baik dan bertahan lama.

Sedangkan menurut Shvets (2019), umumnya method yang sudah lebih dari 10 baris harus mulai dipertanyakan. Layaknya metafora pada lagu Hotel California — Eagles, dalam lirik lagu tersebut menggambarkan sebuah hotel yang tampak indah dan mengundang, namun begitu sudah masuk, tamu tidak dapat keluar.

Lalu apa hubungannya dengan method?

Seperti halnya hotel dalam lagu, beberapa method atau proses dirancang sedemikan rupa sehingga sulit atau tidak mungkin untuk disederhanakan atau dirampingkan. Pengembang terus menambah proses atau isi dari method, tetapi tidak ada yang dihapus, sehingga mengarah ke situasi di mana proses menjadi semakin kompleks dan sulit dikelola.

Karena menulis kode lebih mudah daripada membacanya, “smell” (bau) ini tetap tidak diperhatikan hingga method berubah menjadi monster yang jelek dan besar.

Secara rasional, seringkali lebih sulit membuat method baru dari pada menambahkan ke method yang sudah ada: “Tapi hanya 2 baris, tidak ada gunanya membuat method hanya untuk itu…” yang artinya baris lain akan ditambahkan dan kemudian baris lainnya, akhirnya melahirkan spaghetti code yang kusut.

Contoh dan Cara Memperbaiki (Refactoring)

1. Extract Method

Untuk mengurangi panjang isi dari sebuah method, gunakan Extract Method. Misalnya kita punya bagian kode yang mungkin bisa dikelompokkan bersama.

/* 
Problem code😟
*/
void printOwing(){
printBanner();

// Print details.
System.out.println("name : " +name);
System.out.println("amount : " +getOutstanding());
}

Solusinya adalah pindahkan kode ini ke method baru yang terpisah, ganti kode lama dengan memanggil nama method baru tersebut.

/* 
Solution code🙂
*/
void printOwing(){
printBanner();
printDetails(getOutstanding());
}

void printDetails(double outStanding){
System.out.println("name : " +name);
System.out.println("amount : " +getOutstanding());
}

2. Reduce Local Variables and Parameters Before Extracting a Method.

Jika variabel dan parameter lokal menghalangi extract method, gunakan Replace Temp with Query, Introduce Parameter Object, atau Preserve Whole Object.

2.a. Replace Tempt with Query.

Misalnya kita menempatkan hasil ekspresi dalam variabel lokal untuk digunakan nanti.

/* 
Problem code😟
*/
double calculateTotal() {
double basePrice = quantity * itemPrice;
if (basePrice > 1000) {
return basePrice * 0.95;
}
else {
return basePrice * 0.98;
}
}

Solusinya adalah pindahkan seluruh ekspresi ke method terpisah dan return hasilnya. Ini dinamakan melakukan Query pada sebuah method alih-alih menggunakan variabel. Jika perlu, gabungkan method baru dalam method lain.

/* 
Solution code🙂
*/
double calculateTotal() {
if (basePrice() > 1000) {
return basePrice() * 0.95;
}
else {
return basePrice() * 0.98;
}
}
double basePrice() {
return quantity * itemPrice;
}

2.b. Introduce Parameter Object

Misalkan method yang kita buat berisi sekumpulan parameter berulang.

Press enter or click to view image in full size
Problem code 😟

Solusinya adalah mengganti parameter dengan objek.

Press enter or click to view image in full size
Solution code🙂

2.c. Preserve Whole Object

Misalkan kita mendapatkan nilai dari beberapa objek dan di-passing sebagai parameter sebuah pemanggilan method

/* 
Problem code😟
*/
int low = daysTempRange.getLow();
int high = daysTempRange.getHigh();
boolean withinPlan = plan.withinRange(low, high);

Solusinya adalah passing objek secara keseluruhan

/* 
Solution code🙂
*/
boolean withinPlan = plan.withinRange(daysTempRange);

3. Replace Method with Object Method

Jika teknik-teknik sebelumnya tidak membantu, coba pindahkan seluruh method ke objek terpisah melalui Replace Method with Method Object.

Get Radinal Dwiki Novendra, S.T., M.T.’s stories in your inbox

Join Medium for free to get updates from this writer.

Misalkan kita punya method panjang dimana variabel lokal saling terkait sehingga tidak bisa dilakukan extract method.

/* 
Problem code😟
*/
class Order {
// ...
public double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// Perform long computation.
}
}

Solusinya adalah ubah method menjadi class terpisah sehingga variabel lokal menjadi field dari class. Kemudian kita pecah method menjadi beberapa method dalam class yang sama.

/* 
Solution code🙂
*/
class Order {
// ...
public double price() {
return new PriceCalculator(this).compute();
}
}

class PriceCalculator {
private double primaryBasePrice;
private double secondaryBasePrice;
private double tertiaryBasePrice;

public PriceCalculator(Order order) {
// Copy relevant information from the
// order object.
}

public double compute() {
// Perform long computation.
}
}

4. Conditionals and Loops

Conditional operators dan loops adalah petunjuk bagus bahwa kode dapat dipindahkan ke method terpisah. Untuk conditionals, gunakan Decompose Conditional. Jika loops menghalangi, coba Extract Method.

4.a. Decompose Conditional

Misalkan kita punya statement percabangan yang kompleks, contohnyaif-then/ else atau switch.

/* 
Problem code😟
*/
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
}
else {
charge = quantity * summerRate;
}

Solusinya decompose bagian kondisional yang rumit menjadi method terpisah : bagian condition, then dan else.

/* 
Solution code🙂
*/
if (isSummer(date)) {
charge = summerCharge(quantity);
}
else {
charge = winterCharge(quantity);
}

4.b. Extract Method

Misalkan kita punya potongan kode yang tidak bisa dikelompokkan bersama.

 /* 
Problem code😟
*/
void printProperties(List users) {
for (int i = 0; i < users.size(); i++) {
String result = "";
result += users.get(i).getName();
result += " ";
result += users.get(i).getAge();
System.out.println(result);

// ...
}
}

Solusinya adalah pindahkan kode ini ke method baru yang terpisah, ganti kode lama dengan memanggil nama method baru tersebut.

/* 
Solution code🙂
*/
void printProperties(List users) {
for (User user : users) {
System.out.println(getProperties(user));

// ...
}
}

String getProperties(User user) {
return user.getName() + " " + user.getAge();
}

Hasilnya

  • Menurut Fowler (2018), program yang memiliki fungsi yang pendek adalah program yang hidupnya paling baik dan bertahan lama. Semakin panjang method atau function, semakin sulit dipahami dan dipelihara
  • Selain itu, long method menjadi tempat persembunyian strategis bagi duplicate code yang tidak diinginkan

Terkait Performance

Apakah semakin banyak method akan merusak kinerja? Di hampir semua kasus, nyatanya berdampak sangat kecil bahkan tidak perlu dikhawatirkan. Selain itu, setelah kita punya kode yang jelas dan mudah dipahami, kita dapat menemukan cara efektif untuk menstruktur ulang kode agar mendapatkan peningkatan kinerja, jika dibutuhkan.

Referensi

  • Fowler, M. (2018): Refactoring — Improving the Design of Existing Code, Addison-Wesley Signature Series, diperoleh 18 Februari 2023

--

--