Skip to the content.

Abstraction

SmellGirish Suryanarayana et al. Code SmellsAbstraction

Girish abstraction smell

Semua smell di dalam grup ini berkaitan dengan kesalahan dalam mendesain abstraksi.

Prinsip Abstraction

Girish abstraction principles

Menurut Girish Suryanarayana dkk, terdapat 5 prinsip abstraction yaitu:

Berdasarkan pada pengamatan abstraction smell, terdapat pelanggaran prinsip abstraction antara lain:

Abstraction smell Pelanggaran prinsip abstraction Penyebab Martin Fowler smells
Missing Abstraction Provide a crisp conceptual boundary and a unique identity Pemakaian komponen-komponen data/string tanpa membuatkan object class Primitive Obsession, Data Clumps
Imperative Abstraction Map domain entities Proses dijadikan class, pemikiran Procedural dalam Object-oriented programming Lazy Class (Potentially)
Incomplete Abstraction Ensure coherence and completeness Tidak ada pasang/lawan kata domain -
Multifaceted Abstraction Assign single and meaningful responsibility Satu class memegang > 1 tanggungjawab Divergent Changes + Large Class
Unnecessary Abstraction Assign single and meaningful responsibility Pembuatan class yang seharusnya tidak diperlukan (alias overengineering) Speculative Generalities
Unutilized Abstraction Assign single and meaningful responsibility Ada class yang tidak terpakai sama sekali Dead Code
Duplicate Abstraction Avoid duplication Ada method/implementasi yang sama antar class Alternative Classes with Different Interfaces

Missing Abstraction

Materi

Di sebuah industri peternakan, terdapat sekumpulan unggas yang diternakkan untuk pengolahan daging dan telur. Di suatu kejadian, supplier unggas merasakan kejanggalan setelah unggas yang mereka distribusikan tidak sesuai dengan keinginan penjualnya (penjual ingin membeli daging ayam malah diberikan daging bebek). Ya bayangkan jika di industri peternakan, ayam, bebek, angsa, dan kalkun mereka ternakkan dengan campur aduk tanpa memperhatikan perbedaan jenis-jenis unggas tersebut. :anguished:

Smell ini terjadi ketika:

Bila smell ini dibiarkan, maka bisa menyebabkan:

Penyebab Smell

Contoh

Masalah

Terdapat data-data yang berkaitan dengan ISBN (International Standard Book Number).

ISBN adalah kode unik yang dibeli oleh penerbit buku untuk diletakkan di buku terbitannya. Kode unik ini terdiri dari: registration group, registrant, publication dan check digit.

ISBN yang dipakai sekarang ini memiliki 2 bentuk. ISBN-10 (mengandung 10 digit) dan ISBN-13 (mengandung 13 digit). ISBN-10 bisa dikonversi menjadi ISBN-13, dan sebaliknya. Kedua bentuk ini juga punya algoritma tersendiri untuk mengecek apakah kode tersebut valid atau tidak. Detail algoritma konversi dan pengecekan dapat dilihat di Wikipedia.

Perhatikan Book.java pada package before. Terdapat String ISBN yang memiliki behavior pengecekan dan konversi. Behavior ini tentunya bukan merupakan tanggungjawab class Book. String ISBN seharusnya tidak disimpan secara mentah di dalam class ini.

Penyelesaian

ISBN diekstrak menjadi hirarki baru. ISBN.java sebagai parent-nya dan diturunkan menjadi ISBN10 dan ISBN13. Agar switch statement lebih rapi, dibuat ISBNFactory untuk digunakan oleh class Book.

When to Ignore

Smell ini tidak perlu di-refactor bila malah menyebabkan over-engineering.

Imperative Abstraction

Materi

Sehebat-hebatnya kerajaan tersebut dibangun, pasukan yang mereka kerahkan seharusnya siap sedia ikut perang dengan senjata andalannya. Eh di kerajaan Joger malah kebalik, ketika mereka mau mengerahkan pasukan malah pasukannya disuruh daftar ke jenderal dulu dan disuruh adu bacot-bacotan sama rajanya sendiri. Ya mau sampai kapan kalo pasukannya enggan siap-siap dari dulu :sob:.

Smell ini terjadi ketika sebuah operasi dibuat menjadi sebuah class, dan di dalam class ini, hanya punya satu method saja.

Sesuai namanya, paradigma OOP: OBJECT-oriented programming. Class di dalam OOP wajarnya berupa kata benda. Bukan kata kerja atau kata sifat. Method baru boleh kata kerja. Interface baru boleh kata sifat.

Penyebab Smell

Contoh

Masalah

Perhatikan package before. Terdapat class CreateReport, DisplayReport, dan CopyReport. Disini sudah jelas terjadi imperative abstraction karena ketiga class tersebut merupakan kata kerja, bukan kata benda.

Penyelesaian

Operasi di dalam DisplayReport dan CopyReport, dipindahkan sebagai method ke dalam class Report. CreateReport dipindahkan sebagai constructor class Report.

When to Ignore

Smell ini tidak perlu di-refactor bila class memang sengaja dibuat imperatif. Biasa terjadi ketika menerapkan design pattern state, command, atau strategy. Ketiga design pattern ini adalah Gang of Four design pattern, akan dipelajari di semester depan.

Incomplete Abstraction

Materi

Kereta aja gandengan, masa kamunya enggak punya pasangan? Di game Beautiful Twilighters (fiktif) ceritanya semua fitur makhluk dan humanoid mereka implementasikan termasuk menikahkan NPC dengan NPC lainnya :heart:. Namun di sisi player, malah tidak diberi opsi untuk berpasangan dan menikah dengan player lain. Lah si developer ini baperan atau apa :cry: ?

Smell ini terjadi ketika ada sebuah method yang secara logika harusnya punya pasangan, namun karena belum ada requirement, developer belum membuat pasangannya.

Contoh pasangan di buku Girish:

pair example

Contoh

Masalah

Terdapat method setAuthor() di dalam class Book.

Tentunya class ini terlihat aneh karena hanya ada fungsi setter tanpa getter (atau behavior lain yang memanfaatkan string author). Kita tidak pernah mendengar ada Compact Disc yang write-only, bukan?

Penyelesaian

Dilengkapi dengan menambahkan getAuthor().

Contoh lain yang menarik, Suryanarayana et al. mempermasalahkan code di dalam Java: interface javax.swing.ButtonModel.

Perhatikan methods yang disediakan pada interface ButtonModel. Semuanya berpasangan, misal setPressed() berpasangan dengan isPressed(). Namun, terdapat method setGroup() tidak memiliki pasangan.

Pasangan setGroup malah dibuat di class turunannya: javax.swing.DefaultButtonModel. Terdapat method getGroup di class tersebut.

Hal ini aneh, karena idealnya, bila memang kelupaan, getGroup langsung ditambahkan di dalam interface ButtonModel. Ini malah dipaksa diselipkan di class turunannya.

Hal ini terpaksa dilakukan Java karena bila mereka menambahkan getGroup di interface yang sudah terlanjur di-publish, maka semua programmer yang sedang menggunakan versi Java tersebut akan kalang kabut karena terjadi major changes (major version harus ditambahkan). Biasanya software atau library memiliki versioning setidaknya tiga angka dengan format major.minor.patch. Contoh: 1.0.5. Silakan pelajari perkara versioning lebih detail di semver.org.

When to Ignore

Bukan termasuk smell bila memang developer sengaja menghilangkan pasangannya.

Contohnya, class memang sengaja dibuat hanya punya getter tanpa setter karena atribut read-only.

Contoh lain, pada Java, class dibuat hanya punya constructor saja tanpa destructor karena di Java sudah ada fitur garbage collector. Berbeda bila kita menggunakan bahasa C++, destructor harus dibuat (dan dipanggil) manual.

Multifaceted Abstraction

Materi

Produk 2-in-1 itu indah, misalnya shampo + conditioner dalam 1 sachet. Tapi kalo misalnya orang yang memakai produk 2-in-1 sachet ini hanya mau pakai shamponya buat keramas, apakah conditioner dari sachetan tersebut dibuang sia-sia?

Smell ini terjadi ketika ada class yang memiliki lebih dari satu tanggungjawab (violasi SRP).

Smell ini mirip dengan smell divergent change Martin Fowler. Biasanya divergent change disertai juga dengan smell large class.

Penyebab Smell

Contoh

Masalah

Perhatikan class Rectangle di package before. Disana terdapat field width dan weight. Terdapat method area() dan perimeter(). Dan juga terdapat method print(String style).

Pada umumnya, domain logic dan presentation logic dipisah. Kita bisa berargumen bahwa class Rectangle memiliki dua tanggungjawab, yaitu mengurus kalkulasi Rectangle dan juga mengatur tampilan Rectangle ke dalam console.

Penyelesaian

Kita pindahkan method print di class Rectangle ke class yang baru. Karena di print juga terdapat smell primitive obsession, sekalian kita buatkan struktur baru menggunakan strategy design pattern. Perhatikan hasil refactor-nya di package after.

Unnecessary Abstraction

Materi

Di kerajaan Sampan, semua pasukan selalu mereka siapkan mulai dari tentara, pasukan kuda, pasukan tank, pasukan pemanah, pasukan penyetok bata, pasukan pengamen, pasukan cangcimen, pasukan kucing, dan pasukan ayam. Semuanya mereka persiapkan untuk perang melawan kerajaan Tidus.

Namun pada saat perang melawan kerajaan Tidus, ternyata pasukan-pasukan aneh tersebut malah dibantai secepat kilat oleh musuhnya. Yah sayang banget dah ngapain dibuatin yang aneh-aneh sih? :joy:

Smell ini terjadi ketika ada class yang dibuat padahal tidak dibutuhkan.

Smell ini mirip dengan speculative generality Martin Fowler.

Penyebab Smell

Contoh

Masalah

Di package before, terdapat RedButton dan BlueButton yang sebenarnya hanya menentukan background class javax.swing.JButton. Selain menentukan background, kedua class tersebut tidak memiliki behavior lain.

Penyelesaian

Terlalu berlebihan bila sampai kita melakukan inheritance hanya untuk membedakan warna. Warna background sudah cukup diwakilkan oleh atribut di dalam JButton yang bisa diatur menggunakan setBackground(). Kedua class RedButton dan BlueButton bisa dihapus. Perhatikan ButtonTest di package after.

Unutilized Abstraction

Materi

Produsen mie ternama di Ciwakanda menghentikan produksi bihun dikarenakan tidak lakunya produk bihun di pasaran. Ketika mereka ingin menjual mesin pencetak bihun, ada ide untuk memanfaatkan mesin tersebut untuk produksi mie tebal. Namun di sisi lain, produsen tersebut belum menentukan apakah mesin tersebut dijual atau dipakai kembali hingga pada akhirnya mesin tersebut tidak terpakai hingga sekarang.

Smell ini terjadi ketika ada class atau interface yang tidak pernah digunakan di dalam project. Smell ini mirip dengan dead code Martin Fowler.

Suryanarayana et al. menggolongkannya dalam dua jenis:

Penyebab Smell

Penyelesaian

Class/interface dihapus.

Untuk kasus public library/framework yang belum mau dinaikkan major version-nya (karena menghapus class = breaking changes), maka Anda bisa menandai class/interface itu sebagai deprecated. Dengan menandai deprecated, Anda memperingatkan developer lain yang menggunakan library ini, bahwa bagian code tersebut akan dihapus di versi yang akan mendatang.

Di Java, cara menandai deprecated adalah tinggal menggunakan annotation @Deprecated. Contoh:

@Deprecated
public class Foo {

}

Bila menggunakan Eclipse IDE, code yang sudah ditandai deprecated akan diberi tanda coret.

Eclipse class  deprecation

Tambahan

Flag deprecated tidak hanya berlaku untuk smell ini saja. Deprecated bisa Anda manfaatkan ketika belum mau melakukan major breaking changes untuk refactoring smell apapun.

Duplicate Abstraction

Materi

Kerajaan Kopas menciptakan strategi perang dalam menghadapi perang melawan kerajaan Fotokopi. Dengan cara gilanya, kerajaan tersebut mengerahkan 2 pasukan andalannya, pasukan pisau dan pasukan pedang. Namun di musuh, kedua pasukan dianggap sama-sama membawa senjata melee sehingga musuh mengerahkan pasukan penembak sehingga kerajaan Kopas kandas dibantai oleh musuhnya karena kesamaan dalam membawakan senjata.

Smell ini terjadi ketika ada abstraksi (class/interface) yang kembar. Mirip dengan smell alternative classes with different interfaces milik Martin Fowler.

Suryanarayana et al. membagi dua jenis:

Penyebab Smell


Catatan Referensi

Wiki dan repository ini hanyalah rangkuman dari buku Suryanarayana et al. dengan sedikit tambahan informasi lain. Diharapkan mahasiswa juga membaca sumber aslinya pada bab 3 halaman 21 - 60.