Refactoring Overview • Apakah Refactoring itu? • Katalog “bad smells”
Refactoring
Overview• Apakah Refactoring itu?
• Katalog “bad smells”
2
Apakah Refactoring ?
• Refactoring adalah proses memperbaiki struktur internal sebuah sistem perangkat lunak dengan tetap mempertahankan fungsionalitas (external behavior) dari sistem.
• Refactoring merupakan proses memperbaiki desain setelah coding
3
Latar Belakang
• Dasar kemunculan refactoring: sangat sulit mendapatkan sebuah rancangan yang benar pada iterasi pertama pengembangan sistem, dan ketika ada perubahan pada sistem maka desain juga perlu diubah– INCREMENTAL DESIGN
– refactoring menyediakan teknik-teknik untuk mengembangkan desain dalam bentuk tahap-tahap kecil pengembangan sistem
• Keuntungan– Ukuran program bisa lebih kecil– Struktur yang membingungkan ditransformasikan ke struktur yang
lebih sederhana yang lebih mudah dipelihara dan dimengerti
4
Tujuan Refactoring
• Tujuan dari refactoring adalah membuat program perangkat lunak menjadi lebih mudah dimengerti dan dimodifikasi
• Berbeda dengan optimisasi, walaupun juga hanya mengubah struktur internal dengan fungsionalitas tetap, optimisasi membuat program lebih susah dimengerti tetapi lebih cepat.
5
Mengapa perlu Refactoring?
• Refactoring memperbaiki desain perangkat lunak– Tanpa refactoring, rancangan bisa rusak ketika ada perubahan
terhadap sistem perangkat lunak
• Refactoring membuat perangkat lunak lebih mudah untuk dimengerti– Karena struktur diperbaiki, duplikasi kode bisa diperbaiki, dan
lain-lain
• Refactoring membantu menemukan bugs– Refactoring meningkatkan pemahaman terhadap kode dan
pemahaman ini sangat membantu dalam menemukan dan mengantisipasi bugs
• Refactoring membuat pemrograman (pada iterasi berikutnya) menjadi lebih cepat
6
Contoh sangat sederhana
This
if (isSpecialDeal()) {
total = price * 0.95;send()
} else {
total = price * 0.98;send()
}
becomes this
if (isSpecialDeal())
{
total = price * 0.95;
}
else
{
total = price * 0.98;
}
send();
Menggabungkan bagian-bagian yang sama Menggabungkan bagian-bagian yang sama pada penggunaan skema kondisional pada penggunaan skema kondisional
7
Prinsip Refactoring (1)
• Ada anggapan bahwa refactoring menghabiskan waktu implementasi dan menyebabkan penyelesaian proyek terlambat.
- karenanya Refactoring perlu sistematik, bertahap, dan aman
• Bagaimana membuat refactoring aman?
=> Pertama, gunakan “pola-pola” refactoring - Fowler memberikan nama pada “pola-pola” refactoring
=> Kedua, lakukan test - Setelah refactoring, test harus dilakukan. Jika test memberikan hasil gagal maka berarti Refactoring telah merusak program dan harus diperbaiki dulu sebelum ke tahap selanjutnya.
8
Prinsip Refactoring (2)
• Refactoring berbeda dengan penambahan fungsi, keduanya tidak bisa dilakukan secara bersamaan
• Penambahan fungsi– Fungsionalitas diimplementasikan pada sistem tanpa
pembersihan kode
• Refactoring– Tidak ada fungsionalitas yang ditambahkan pada
sistem, tetapi kode dibersihkan, sehingga mudah dimengerti dan dimodifikasi, dan kadang-kadang bisa mereduksi ukuran program
9
Kapan perlu refactoring?
• The Rule of Three – Terdapat bagian kode berulang 3 kali, refactoring
dilakukan terhadap bagian tersebut
• Refactoring ketika menambah fungsionalitas– Refactoring sebelum menambah fungsi untuk
mempermudah penambahan fungsi tersebut– Atau lakukan setelah fungsi ditambahkan
• Refactoring untuk memperbaiki bugs• Refactoring jika perlu review progran
10
Masalah dengan Refactoring
• Basis data – Aplikasi bisnis biasanya terhubung erat basis data – Kode mudah untuk diubah basis data tidak
• Mengubah antarmuka– Beberapa refactoring membutuhkan perubahan antarmuka. Akan
jadi masalah jika source code antarmuka tidak ada.
• Perubahan desain yang sulit untuk direfaktor– Itulah kenapa extreme programming mengatakan bahwa software
engineer harus memiliki “keberanian”
11
Katalog Refactoring
• Katalog refactoring terdiri dari “Bad Smells”, yaitu struktur program yang tidak bagus dan perlu diperbaiki, dan pola refactoring yang dibutuhkan untuk menghilangkan bad smells
• Studi kasus :
12
Bad smells
• Duplikasi Kode– Bad smell yang paling banyak muncul
– Apakah terdapat dua method yang sama pada sebuah kelas?• Buat sebuah rutin tambahan berparameter
(Extract method)
– Kode yang sama pada kelas yang berelasi?• Pindahkan bagian yang sama tersebut ke ancestor terdekat dan
parametrisasi
• Gunakan template method untuk mengakomodasi variasi pada subtasks
(template method)
13
Bad smells
• Duplikasi Kode– Kode yang sama pada kelas yang tidak berelasi?
• Haruskah mereka berelasi?– Buat kelas induk abstrak (Extract class, Pull up method)
• Apakah kode sebaiknya dimiliki hanya oleh sebuah kelas?– Buat kelas lainnya sebagai client (Extract method)
• Dapatkah bagian kode yang sama tadi dipisahkan ke dalam subpart atau functor atau other function object?
– Pindahkan method ke subobject dari kedua kelas tersebut
– Strategi DP membolehkan pendefinisian methods-as-objects/ method object untuk variasi polimorfisme
(Replace method with method object)
14
Bad smells
• Long method– Seringkali menunjukkan:
• Method melakukan terlalu banyak hal• Menunjukkan abstraksi dan pembatasan yang buruk• Micromanagement anti-pattern
– Harus diidentifikasi dengan cermat tentang tugas-tugas utama dan bagaimana mereka berinterelasi.
• Pecah ke dalam method yang lebih kecil dalam kelas yang sama dan dengan visibility Private (Extract method)
• Delegasikan subtask ke beberapa subobjek (contoh: template method DP)(Extract class/method, Replace data value with object)
– Heuristic Fowler:• When you see a comment, make a method.
15
Bad smells
• Large class– Terlalu banyak komponen
– Solusi:1. Kelompokkan dan pisahkan masing-masing ke sebuah kelas
(Extract class, replace data value with object)
2. Delegasikan method ke kelas / subparts.(Extract method)
– Contoh:• Kelas-kelas library seringkali ‘gemuk’ (banyak method, banyak
parameter, banyak overloading)– Tidak masalah jika tujuannya untuk fleksibilitas.
16
Bad smells
• Long parameter list– Menyulitkan memahami method– Ini merupakan gejala dari:
• Method melakukan terlalu banyak hal• Terlalu jauh dari maksud dan tujuan awal method • Banyak mengandung subpart yang berlainan
– Pada pemrograman terstruktur parameter digunakan sebagai solusi atas penggunaan variabel global yang banyak.
• Pada OOP, objek sangat mungkin memiliki variabel-variabel yang bersifat global terhadap method tetapi tetap tersembunyi dari semua bagian program lainnya.
Jadi, tidak perlu menjadikan subpart (atribut) pada method dari objek yang sama.
17
Bad smells
• Long parameter list– Solusi:
• Method melakukan terlalu banyak hal?– Pecah ke dalam beberapa method
(Extract method)
• Terlalu jauh dari maksud dan tujuan awal method?– Lokalisasi parameter, jangan mudah untuk menempatkan parameter di
beberapa layer pemanggilan
(Buat whole object, gunakan objek parameter)
• Banyak mengandung subpart yang berlainan?– Kelompokkan parameter ke dalam aggregate subpart
– Antarmuka method akan menjadi lebih mudah untuk dipahami
(Preserve whole object, introduce parameter object)
18
Bad smells
• Divergent change– Terjadi ketika sebuah kelas sering mengalami perubahan dengan
beragam cara untuk berbagai alasan– Kelas melakukan banyak hal dan berisi banyak subpart yang tidak
berelasi satu sama lain – Semakin lama, beberapa kelas membentuk “God complex”
• Mereka membutuhkan detil-detil dari subpart yang ada di kelas-kelas lain secara acak
– Kohesi rendah• Di satu kelas terdapat elemen-elemen yang tidak berelasi
– Solusi:• Pecah kelasmenyusun ulang kelas, mempertimbangkan kembali relasi dan
responsibiliti (Extract class)
19
Bad smells
• Shotgun surgery– Kebalikan dari divergent change
• Setiap kali terjadi perubahan yang koheren, maka banyak kelas yang berubah
• Kohesi rendah
• Elemen-elemen yang berelasi ada di kelas-kelas yang berbeda
– Solution:• Tempatkan atribut dan method yang berelasi pada sebuah kelas,
bisa kelas baru atau yang sudah ada.(Move method/field)
20
Bad smells
• Feature envy– Sebuah method lebih cocok berada di kelas lain
Contoh: method A::m() sering memanggil method get/set dari kelas B
– Solusi:• Pindahkan m() (atau bagian dari m()) ke kelas B
(Move method/field, extract method)
– Pengecualian:• Visitor/iterator/strategy DP yang bertujuan menempatkan data
terpisah dari algoritma
21
Bad smells
• Data clumps– Terjadi jika sekumpulan data selalu bersama-sama, sebagai parameter
atau diubah/diakses pada saat yang sama
– Seharusnya terdapat sebuah subobjek koheren yang perlu dibuat
– Pada contoh tersebut, sebuah kelas Title perlu dibuat
– Pemindahan data dapat menimbulkan feature envy• Perancangan dilakukan secara iterasi sampai benar.(Preserve whole object, extract class, introduce parameter
object)
void Scene::setTitle (string titleText, int titleX, int titleY, Colour titleColour){…}
void Scene::getTitle (string& titleText, int& titleX, int& titleY, Colour& titleColour){…}
22
Bad smells
• Primitive obsession– Semua atribut dari objek merupakan instans dari tipe primitif
(int, string, bool, double, dll.)Contoh: dates, currency, SIN, tel.#, ISBN
– Seringkali objek-objek mempunyai konstraincontoh., fixed number dari digit/karakter, nilai khusus
– Solusi:• Buat beberapa “kelas kecil” yang dapat mendukung definisi
konstrain.(Replace data value with object, extract class, introduce
parameter object)
23
Bad smells
• Switch statements– Contoh penggunaan switch:
Double getSpeed () { switch (_type) {
case EUROPEAN: return getBaseSpeed();case AFRICAN: return getBaseSpeed() –
getLoadFactor() * _numCoconuts;case NORWEGIAN_BLUE: return (_isNailed) ? 0
: getBaseSpeed(_voltage); }}
24
Bad smells
• Switch statements– Contoh dari kekurangpahaman atas polimorfisme dan
enkapsulasi.
– Solusi:• Redesign sebuah method polymorfisme dari PythonBird
(Replace conditional with polymorphism, replace type code with subclasses)
25
Bad smells
• Lazy class– Kelas-kelas yang tidak banyak melakukan hal-hal yang berbeda
dengan kelas-kelas lainnya.
– Jika ada beberapa kelas turunan yang tidak menampilkan perbedaan/variasi perilaku dari kelas induknya maka hilangkan kelas tersebut dan buat parameterisasi pada method kelas induk.
– Seringkali lazy classes merupakan akibat dari rancangan yang terlalu ambisius atau refactoring
(Collapse hierarchy, inline class)
26
Bad smells
• Speculative generality– Adanya kelas-kelas yang tidak berguna sebagai akibat dari
prinsip “We might need this one day …”• Tidak masalah, tetapi harus diperiksa ulang apakah kelas-kelas
tersebut memang diperlukan atau tidak?
• Adanya kelas-kelas yang tidak terpakai menambah kompleksitas model dan sistem.
– Filosofi Extrem Programming:• “Sesederhana mungkin tetapi tidak lebih sederhana”
• “Rule of three”.
– Harus diingat bahwa Refactoring adalah proses yang berlangsung terus menerus.
• Jika benar-benar diperlukan, kelas bisa ditambahkan kembali
(Collapse hierarchy, inline class, remove parameter)
27
Bad smells
• Message chains– Objek klien (A) meminta servis dari sebuah objek (B), B
meminta servis dari subobjek lain (C), C meminta servis dari subobjek lainnya (D), …
• Multi-layer “drill down” dapat menghasilkan sub-sub-sub-objects ke objek klien.
– Perlu berpikir ulang tentang abstraksi • Mengapa ada message passing bersarang?
• Mengapa objek-objek subpart yang berguna bagi objek klien “berjarak jauh” dari objek klien tersebut?
(Hide delegate)
28
Bad smells
• Inappropriate intimacy– Sharing properti privat antar kelas. Hal ini membawa sistem kepada
coupling yang tinggi, struktur internal kelas dan teknik implementasi menjadi terbuka. Akibatnya struktur menjadi rapuh dan sulit berkembang.
– Solusi:• Gunakan method get/set • Pikir ulang dari abstraksi.• Gabungkan kelas(Move/extract method/field, change bidirectional association to
unidirectional, hide delegate)
• Middle man– Objek-objek yang hanya mendelegasikan message dari objek klien ke
objek server(Remove middle man, replace delegation with inheritance)
29
Bad smells
• Alternative classes with different interfaces– Kelas-kelas/method-method mengimplementasikan abstraksi
yang sama/sejenis padahal mereka tidak berelasi
– Bukan merupakan overloading tetapi keteledoran perancangan.
– Solusi:• Gabungkan kelas-kelas yang terlihat “dekat”.
– Definisikan antarmukanya
– Cari subpart-subpart yang sama dan hampir semuanya dihapus agar tidak ada redundansi .
(Extract [super]class, move method/field, rename method)
30
Bad smells
• Data class– Kelas hanya terdiri dari field-field data sederhana
dan method-method pengaksesan sederhana.– Solusi:
• Perhatikan pola penggunaan ini oleh objek klien
• Abstraksikan cara-cara pengaksesan yang sama terhadap komponen, ke dalam method-method dari kelas data, dan pindahkan beberapa fungsionalitas ke kelas data tersebut
(Extract/move method)
31
Bad smells
• Refused bequest– Subkelas mewarisi semua method/variabel dari kelas parent tetapi
tidak menggunakan sebagian dari mereka.• Gunakan delegasi
(Replace inheritance with delegation)
– Kelas parent punya fitur yang digunakan hanya oleh beberapa kelas turunannya. :
• Membuat kelas-kelas intermediate pada hierarki. Pindahkan method-method khusus ke level yang lebih bawah.(Push down field/method)
32
Bad smells
• Comments– Filosofi memandang penting penggunaan komentar, karena:
• Membuat method lebih mudah dipahami
– Pada Refactoring, Fowler mengklaim bahwa komentar merupakan tanda-tanda ketidakjelasan, kerumitan, dan ketidakpahaman.
• Daripada memelihara ketidakjelasan, lebih baik kode direstrukturisasi
(Extract method/class, [many others applicable] …)– Komen diperlukan untuk mendokumentasi alasan
contoh, menerangkan mengapa pendekatan ini yang dipilih bukan yang lainnya
33
Refactoring Pattern: Extract Method
• Terdapat sebuah penggalan kode yang bisa dipisahkan, maka jadikan sebuah method dengan nama yang menggambarkan tujuan dari fragmen
void printOwing(double amount)void printOwing(double amount) {{ printBanner()printBanner()
//print details//print details Console.Writeline(“name: ” + Console.Writeline(“name: ” + _name);_name); Console.Writeline(“amount: ” + Console.Writeline(“amount: ” + amount);amount);}}
void printOwing(double amount) void printOwing(double amount) {{ printBanner()printBanner() printDetails(amount)printDetails(amount)}}
void printDetails(double amount) void printDetails(double amount) {{ Console.Writeline(“name: ” + _name);Console.Writeline(“name: ” + _name); Console.Writeline(“amount: ” + amount);Console.Writeline(“amount: ” + amount);}}
34
Refactoring Pattern: Parameterize Method
BEFORE
AFTER
WebService WebService
handleGet(…)
handlePut(…)
handle(serviceType,…)
35
Refactoring Pattern: Replace Temp with Query(1)
• Menggunakan variabel sementara untuk menyimpan hasil dari suatu expresi
• Jadikan expresi tersebut sebuah method• Ganti semua referens ke variabel sementara tersebut
dengan expresi, dan hilangkan variabel
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
{
return basePrice * 0.95;
}
else
{
return basePrice * 0.98;
}
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
{ return basePrice * 0.95;
}
else
{ return basePrice * 0.98;
}
36
Refactoring Pattern: Replace Temp with Query (2)
if (basePrice() > 1000)
{ return basePrice() * 0.95;
}
else
{ return basePrice() * 0.98;
}
…
double basePrice()
{ return _quantity * _itemPrice;
}
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
{
return basePrice * 0.95;
}
else
{
return basePrice * 0.98;
}
37
Refactoring Pattern: Replace Conditional with Polymorphism (1)
• Terdapat kondisional untuk berdasarkan tipe dari objek
• Hilangkan kondisional dengan sebuah overriding method yang ada pada sub kelas
• Buat abstrak untuk method asal
double getSpeed() { switch (_type) { case EUROPEAN: return getBaseSpeed();
case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
case NORWEGIAN_BLUE:return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}}
38
Refactoring Pattern: Replace Conditional with Polymorphism (2)
39
Refactoring Pattern: Form Template Method
• Terdapat 2 method dengan tujuan yang sama pada beberapa subclass yang berbeda tetapi ada perbedaan pada bagian algoritma.
• Buat sebuah method yang sama dan tempatkan pada superclass/parent sehingga method asal sama, dan definisikan sebuah method pada subclass yang meng-override method tersebut.
40
Refactoring Pattern: Form Template Method (2)
41
Refactoring Pattern: Rename Method
• Nama dari method tidak menunjukkan maksud dan tujuan method tersebut
• Ganti nama method
• Contoh:– customer.getinvcdtlmt();– Customer.getInvoiceCreditLimit();