CSG3H3 RPL: Teknik Berorientasi Objek Semester Genap 2014/2015
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
.
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
Tujuan Refactoring
•
Tujuan dari refactoring adalah membuat
program (perangkat lunak) menjadi lebih
mudah dimengerti dan dimodifikasi.
•
Berbeda dengan optimasi, walaupun juga
hanya mengubah struktur internal dengan
fungsionalitas tetap, optimasi membuat
program lebih susah dimengerti tetapi lebih
cepat.
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
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 pada penggunaan skema kondisional:
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
Martin 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.
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.
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
.
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 di-refactor
– Itulah kenapa Extreme Programming mengatakan bahwa software engineer harus memiliki “keberanian”
Katalog Refactoring
•
Katalog refactoring terdiri dari “Bad Smells”:
–
Struktur program yang tidak bagus dan perlu
diperbaiki, dan
–
Pola refactoring yang dibutuhkan untuk
menghilangkan bad smells.
Bad Smells (1)
•
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)
Bad Smells (2)
•
Duplikasi Kode
( lanjutan )–
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)
Bad Smells (3)
•
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:
Bad Smells (4)
•
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)
Bad Smells (5)
•
Long Parameter List
–
Menyulitkan memahami method.
–
Ini merupakan gejala dari:
• Method melakukan terlalu banyak hal
• Terlalu jauh dari maksud dan tujuan awal method
Bad Smells (6)
•
Long Parameter List
( lanjutan )–
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 untukmenempatkan parameter di beberapa layer
Bad Smells (7)
•
Divergent Change
– Terjadi ketika sebuah kelas sering mengalami perubahan dengan beragam cara untuk berbagai alasan.
– Kelas melakukan banyak hal dan berisi banyak sub-part yang tidak berelasi satu sama lain.
– Semakin lama beberapa kelas membentuk “God complex”.
• Mereka membutuhkan detil-detil dari sub-part yang ada di kelas-kelas lain secara acak.
– Kohesi rendah
• Di satu kelas terdapat elemen-elemen yang tidak berelasi. – Solusi:
• Pecah kelas (menyusun ulang kelas), dengan mempertimbangkan
Bad Smells (8)
•
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
Bad Smells (9)
•
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
Bad Smells (10)
•
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
void Scene::setTitle (string titleText, int titleX, int titleY,
Colour titleColour){…}
void Scene::getTitle (string& titleText, int& titleX, int& titleY,
Bad Smells (11)
•
Primitive Obsession
–
Semua atribut dari objek merupakan instans dari
tipe primitif (int, String, boolean, double, dll.)
• Contoh: dates, currency, SIN, tel.#, ISBN
–
Seringkali objek-objek mempunyai
constraint
• Contoh: fixed number dari digit/karakter, nilai khusus
–
Solusi:
• Buat beberapa “kelas kecil” yang dapat mendukung definisi constraint (replace data value with object,
Bad Smells (12)
•
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); } }
Bad Smells (13)
•
Switch Statements
( lanjutan )–
Contoh dari kekurangpahaman atas polimorfisme
dan enkapsulasi.
–
Solusi:
• Redesign sebuah method polymorfisme dari
PythonBird (replace conditional with polymorphism,
Bad Smells (14)
•
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 .
Bad Smells (15)
•
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)
Bad Smells (16)
•
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
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) { printBanner() //print details Console.Writeline(“name: ” + _name); Console.Writeline(“amount: ” + amount); }
void printOwing(double amount) {
printBanner()
printDetails(amount) }
void printDetails(double amount) {
Console.Writeline(“name: ” + _name); Console.Writeline(“amount: ” + amount); }
Refactoring Pattern:
Parameterize Method
BEFORE AFTER WebService WebService handleGet(…) handlePut(…) handle(serviceType,…)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 {
double basePrice = _quantity * _itemPrice; if (basePrice > 1000)
{ return basePrice * 0.95; }
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; }
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); }
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.
Refactoring Pattern: