Bagian ini berisi rangkuman dan referensi dasar dasar pemrograman yang wajib dipahami oleh seluruh tim teknis Flipbox.
Konsep Clean Code mempunyai beberapa penafsiran dan karakteristik, di antaranya :
-
Kode tersebut harus mudah dipahami
- Memiliki alur kerja/pertukaran data yang jelas dan konsisten
- Kolaborasi antar class atau berkas harus mudah dipahami
- Tanggung jawab dan fungsi dari setiap berkas harus mudah untuk dipahami. Jangan membuat fungsi yang terlalu kompleks apabila tidak dibutuhkan.
- Fungsi atau method yang ada di dalam sebuah berkas harus mudah dipahami
- Tujuan, penamaan dan fungsi dari setiap variabel ataupun baris mudah dipahami dan mudah dibaca
- Kode harus mudah dibaca, tambahkan komentar di bagian yang cukup kompleks atau kurang stabil (lihat bagian readable code)
-
Kode tersebut harus mudah diubah
- Kelas dan fungsinya harus dijaga agar tetap kecil dan bertanggung jawab pada sebuah pekerjaan tertentu (single responsibility principle)
- Kelas harus memiliki API yang jelas dan mudah dipahami / mudah dibaca
- Kelas dan fungsinya harus berjalan dengan sebagai mana mustinya dan proses yang ada di dalamnya mudah untuk ditebak
- Mempunyai unit test atau diatur sedemikian rupa agar memudahkan pembuatan tes.
- Tes yang tersedia mudah dipahami dan mudah untuk diubah
- Redundansi kode harus dijaga seminimal mungkin (DRY principle) agar kode dapat tetap berjalan dengan konsisten ketika terjadi perubahan di suatu tempat
- Dependensi yang ada di dalam kode harus dijaga seminimal mungkin untuk mengurangi resiko kesalahan akibat perubahan dependensi
"Clean Code is a code that is written by someone who cares" - Michael Feathers
Bacaan tambahan :
Clean Code : A Handbook of Agile Software Craftmanship
High Quality Code for Better Programmer
Hal yang cukup sering dilupakan pengembang adalah bahwa kode yang mereka kembangkan akan digunakan kembali suatu hari nanti, mungkin oleh orang lain. Banyak kasus muncul ketika kode lama dibuka kembali, dibutuhkan waktu untuk memahami ataupun mengingat ulang bagaimana kode tersebut dibuat. Waktu tersebut dapat diminimalisir apabila kode yang dibuat mudah untuk dibaca dan dipahami.
Prinsip prinsip untuk membuat kode yang mudah dibaca adalah :
- Konsistensi dalam tata cara pembuatan kode, di antaranya :
- Spasi vs tab
- Peletakan { }
- Ikuti kesepakatan yang berlaku di dalam tim
- Penamaan files & folders yang konsisten :
- Peletakan berkas di dalam folder yang relevan dan mudah dipahami
- Konvensi penamaan (CamelCase, snake-case, etc)
- Ikuti kesepakatan yang berlaku di dalam tim
- Masukkan komentar dan dokumentasi di tempat yang membutuhkan penjelasan tambahan
- Hindari pembuatan fungsi / baris yang kompleks dan membutuhkan waktu tambahan untuk dipahami.
- Hindari spasi / tab yang terlalu menjorok (deep nesting) karena akan menyulitkan pemahaman fungsi dan tujuan kode
"Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. Code for readability" - John F Woods
Bacaan lebih lanjut :
KISS : Keep It Simple and Straightforward!
Konsep KISS menyatakan bahwa kode yang dibuat harus sederhana dan mudah dipahami tanpa mengorbankan kualitas hasil akhir pengerjaan kode.
Beberapa hal yang harus diperhatikan dalam penerapan konsep KISS adalah :
- methods & classes harus dibuat sesederhana mungkin.
- Hindari kompleksitas dalam kondisi perulangan dan percabangan (nested/complex loop & conditional)
- Hindari solusi yang terlalu kompleks atau kode yang terlalu singkat namun sulit untuk dibaca. Jangan pula mengorbankan performa demi mendapatkan baris kode yang mudah dibaca. Cari keseimbangan antara keduanya.
DRY : Don’t Repeat Yourself!
Apabila sebuah blok kode sudah digunakan beberapa kali ( +- 3 kali ) dalam sebuah proyek, buatlah reusable/helper method dan hapus duplikasi yang terjadi.
SOLID
- Single responsibility : Sebuah class hanya boleh memiliki 1 tanggung jawab. Jangan membuat sebuah class yang terlalu kompleks dan melakukan banyak hal sekaligus.
Contoh : sebuah layanan ojek online mungkin bisa membuat kelas
AntarJemput
untuk memodelkan proses bisnisnya. Namun akan lebih baik apabila kelas tersebut dipecah menjadiAntar
yang bertanggung jawab dengan pengantaran pengguna menuju tujuan danJemput
yang bertanggung jawab untuk fungsi penjemputan pengguna dari tempat asal sehingga apabila ada optimalisasi dalam prosesJemput
, fungsi yang mengimplementasi kelasAntar
menjadi relatif lebih aman
- Open for extension but closed for modification : Fungsi atau kegunaan dalam sebuah entitas seharusnya bisa ditambahkan tanpa harus mengubah isi dari entitas tersebut ( Open Closed )
Contoh : sebuah
Truk
memiliki fungsijumlahVolumeBarang
yang memiliki parameter List barang barang yang ada di dalamTruk
tersebut. FungsijumlahVolumeBarang
bertugas untuk menghitung volume masing masing barang kemudian menjumlahkan keseluruhan volume. Apabila terdapat jenis barang baru dengan rumus volume baru, makajumlahVolumeBarang
harus diperbarui. Seharusnya ada implementasihitungVolume
di dalam barang sehingga untuk barang tertipe apapun,jumlahVolumeBarang
tidak harus diperbarui karena hanya akan menjumlahkan hasil daribarang.hitungVolume()
- Liskov substitution principles : Sebuah object seharusnya dapat diganti oleh object subtype tanpa mengubah keluaran dari sebuah program ( Design by Contract )
Contoh : sebuah fungsi
antarPenumpang
memiliki parameter Kendaraan yang memiliki fungsirem
. Liskov subtitution menyatakan bahwa semua jenis Kendaraan (Odong Odong
,Bemo
)harus mengimplementasikanrem
dengan tujuan yang sama ( menurunkan kecepatan ).
-
Interface segregation principles : Interface yang spesifik dan kecil lebih baik daripada Interface besar yang menyebabkan class harus menerapkan fungsi yang tidak dibutuhkan.
-
Dependency inversion principle : Detail harusnya bergantung pada abstraksi. Seharusnya tidak ada class yang bergantung / depend dari class yang konkrit ( non abstract )
Contoh : Fungsi
antarPenumpang
dalam kelasAntar
mungkin bisa memiliki parameter/dependensiSepeda Motor
. Namun apabila layanan ojek online ingin menambahkanBemo
di armadanya tentu harus mengubah isi dariAntar
. Akan lebih baik apabila parameter dariantarPenumpang
diubah menjadiKendaraan
(abstract) sehingga memungkin adanya penambahan tipe armada tanpa harus mengubah fungsi / kelas terkait.
Bacaan lebih lanjut :
SOLID : Object Oriented Design
SOLID, GRASP and other principles of OOP
Beberapa konsep utama yang harus dipahami dari sebuah paradigma OOP ( Object Oriented Programming ) adalah :
Everything is an object
Banyak pihak yang menyebutkan bahwa dalam OOP, semua hal bisa direpresentasikan sebagai Object
. Hal ini bisa mungkin tidak bisa diimplementasikan dalam beberapa situasi/konsep tertentu ( primitive variables, methods, etc ). Namun perlu dipahami bahwa dalam pemodelan solusi, hampir sebagian besar masalah dan solusinya dapat direpresentasikan sebagai kumpulan objek yang saling berinteraksi satu sama lain. Oleh karena itu, kemampuan memodelkan masalah menjadi objek dan representasinya menjadi sangat penting dalam pemahaman OOP.
Encapsulation
Enkapsulasi menyatakan bahwa implementasi/representasi internal dari sebuah objek seharusnya tidak bisa terlihat dari objek lain.
Enkapsulasi bisa dilakukan dengan cara melakukan pembatasan akses terhadap accessor dan mutator. Accessor merupakan sebuah fungsi yang dapat memberikan nilai yang terkandung di sebuah objek. Mutator adalah sebuah fungsi yang dapat mengubah representasi/nilai internal yang terkandung di dalam sebuah objek.
Contoh : objek
Person
bisa mempunyai AccessorgetClothes()
dan MutatorsetClothes(...)
untuk mencari tahu dan mengubah pakain yang sedang dikenakannya
Abstraction
Abstraksi berhubungan erat dengan enkapsulasi, karena pada dasarnya abstraksi adalah proses pembuatan sebuah objek yang tidak memiliki implementasi nyata dalam Accessor ataupun Mutator yang dimilikinya. Implementasi tersebut akan diterapkan pada objek yang merepresentasikannya
Contoh : objek
Manusia
memiliki AccessorbisaMembaca
, namun implementasibisaMembaca
akan berbeda tergantung objek lain yang merepresentasikanManusia
. Budi mungkinbisaMembaca
( mengembalikantrue
) namun Joko bisa saja tidakbisaMembaca
( mengembalikanfalse
)
Inheritance
Secara umum, objek dapat berinteraksi satu dengan yang lainnya dalam hubungan mempunyai (has a), menggunakan (use a), atau merepresentasikan (is a). Is a atau representasi adalah sebuah bentuk dari Interitance atau pewarisan. Dalam konsep Inheritance terdapat istilah parent/super class dan child class. Child class akan mewarisi properti dan fungsi non-privat yang dimiliki oleh parent/super class.
Contoh : Kelas
Kendaraan
memiliki propertiroda
dan fungsiaturKecepatan
. Semua kelas yang menjadi child class dariKendaraan
akan memilikiroda
dan fungsiaturKecepatan
secara otomatis.
Polymorphism
Polymorphism bisa dijabarkan atau diartikan sebagai sebuah operasi yang memiliki beberapa jenis implementasi
Beberapa jenis Polymorphism adalah :
- Ad Hoc Polymorphism atau Function Overloading adalah sebuah fungsi yang memiliki nama sama, namun parameter berbeda sehingga bisa memiliki implementasi yang berbeda
Contoh : fungsi dengan
jumlah
bisa memiliki parameterangka arab (1-0)
ataupunangka romawi (I-X)
sehingga implementasijumlah(10, 20)
tentunya akan menjadi beda denganjumlah (XV, IV)
- Parametric Polymorphism atau Generic Type adalah sebuah fungsi atau jenis data yang ditulis secara umum sehingga bisa mengakomodir semua jenis tipe data tanpa terkecuali
Contoh : kelas
Minuman<T>
dan fungsiracikMinuman(T)
mempunyai Generic Type yang direpresentasikan dalamT
. Dalam proses representasiMinuman
,T
dapat didefinisikan sebagai data berjenis apapun (misalKopi
atauTeh
) danracikMinuman
harus menggunakan tipe data yang sama sebagai parameter ( menjadiracikMinuman(Kopi)
atauracikMinuman(Teh)
.
- Subtyping atau Function Overriding adalah sebuah fungsi yang diwariskan dari parent class namun dapat didefinisikan berbeda oleh child class
Contoh : kelas
Binatang
mempunyai fungsibicara
, namun kelas yang merepresentasikanBinatang
mungkin mempunyai cara yang berbeda untukbicara
( misalkanKucing
bicara
akan mengembalikan Meow! danAnjing
bicara
akan mengembalikan Woof! )
Bacaan tambahan ( gunakan akun Flipbox untuk akses Udemy course ) :
Beberapa konsep utama yang harus dipahami dari sebuah paradigma Reactive Programming adalah :
Everything is a stream
Sedikit berbeda dengan konsep OOP yang menggambarkan masalah dan solusinya sebagai objek dan interaksinya, Reactive Programming menitikberatkan kepada kejadian dan alur kejadiannya (stream & events). Hampir sebagian besar proses dapat digambarkan dalam kumpulan kejadian (events) dan alur kejadian dari mulai sampai selesai (stream)
Karena perbedaan paradigma ini, Reactive Programming sangat cocok apabila diterapkan ke dalam sebuah sistem yang membutuhkan respon secara instan / real time karena paradigma ini sangat menitikberatkan kepada kejadian (event) dan reaksinya (response).
Subject / Observable
Stream dapat diimplementasikan dengan menginisialisasi sebuah Subject (bisa juga disebut Observable). Observable adalah sebuah objek/data yang dapat dipantau (observe/subscribed) oleh sebuah Observer. Setiap perubahan dari status data akan langsung diinformasikan kepada seluruh Observer yang memantau data Observable tersebut.
Observer
Observer adalah sebuah objek/data yang memantau semua perubahan nilai dari Subject/Observable. Setelah Observer menyatakan diri siap memantau (subscribe) Observable, maka Observer tersebut sudah memasuki stream data yang ada di dalam proses. Setiap ada perubahan status internal di dalam Subject/Observable maka Observer akan mendapatkan notifikasi sehingga dapat melakukan reaksi yang bersesuaian dengan aksi.
Bacaan lebih lanjut :
Reactive Programming Introduction