CSG3H3 RPL: Teknik Berorientasi Objek Semester Genap 2014/2015
Refactoring
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.
2
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. 3
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. 4
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 5
Contoh Sangat Sederhana Menggabungkan bagian-bagian yang sama pada penggunaan skema kondisional: This:
Becomes this:
if (isSpecialDeal()) { total = price * 0.95; send(); } else { total = price * 0.98; send(); }
if (isSpecialDeal()) { total = price * 0.95; } else { total = price * 0.98; } send();
6
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. 7
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. 8
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 program. 9
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” 10
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.
11
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)
12
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)
13
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: • When you see a comment, make a method. 14
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) – Tidak masalah jika tujuannya untuk fleksibilitas. 15
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
• Banyak mengandung subpart yang berlainan
16
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 untuk menempatkan parameter di beberapa layer pemanggilan (buat whole object, gunakan objek parameter)
17
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 kelaskelas lain secara acak.
– Kohesi rendah •
Di satu kelas terdapat elemen-elemen yang tidak berelasi.
– Solusi: •
Pecah kelas (menyusun ulang kelas), dengan mempertimbangkan kembali relasi dan responsibility (Extract class) 18
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 method/field)
19
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 method/field, extract method)
20
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 void Scene::setTitle (string titleText, int titleX, int titleY, Colour titleColour){…} void Scene::getTitle (string& titleText, int& titleX, int& titleY, Colour& titleColour){…}
– Pada contoh tersebut, sebuah kelas Title perlu dibuat
21
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, extract class, introduce parameter object)
22
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); } }
23
Bad Smells (13) • Switch Statements ( lanjutan ) – Contoh dari kekurangpahaman atas polimorfisme dan enkapsulasi. – Solusi: • Redesign sebuah method polymorfisme dari PythonBird (replace conditional with polymorphism, replace type code with subclasses)
24
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 . (Extract [super]class, move method/field, rename method) 25
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)
26
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 •
Contoh: menerangkan mengapa pendekatan ini yang dipilih bukan yang lainnya 27
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); }
28
Refactoring Pattern:
BEFORE
WebService
handleGet(…)
Parameterize Method AFTER
WebService handle(serviceType,…)
handlePut(…)
29
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) double basePrice = _quantity * _itemPrice; { if (basePrice > 1000) return basePrice * 0.95; { return basePrice * 0.95; } } else else { { return basePrice * 0.98; return basePrice * 0.98; } }
30
Refactoring Pattern:
Replace Temp with Query (2)
double basePrice = _quantity * _itemPrice; if (basePrice > 1000) { return basePrice * 0.95; } else { return basePrice * 0.98; }
if (basePrice() > 1000) { return basePrice() * 0.95; } else { return basePrice() * 0.98; } … double basePrice() { return _quantity * _itemPrice; } 31
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); } }
32
Refactoring Pattern:
Replace Conditional with Polymorphism (2)
33
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 mengoverride method tersebut.
34
Refactoring Pattern:
Form Template Method (2)
35
Refactoring Pattern:
Rename Method
• Nama dari method tidak menunjukkan maksud dan tujuan method tersebut • Ganti nama method • Contoh: – customer.getinvcdtlmt(); – Customer.getInvoiceCreditLimit();
36