Artikel ini mencantumkan beberapa kesalahan umum yang saya lihat dalam kode Java rekan-rekan di sekitar saya. Jelas sekali, analisis kode statis (tim kami menggunakan qulice) tidak akan dapat menemukan semua masalah, itulah sebabnya saya mencantumkannya di sini.
Jika menurut Anda ada yang kurang, beri tahu saya dan saya akan dengan senang hati menambahkannya.
Semua kesalahan yang tercantum di bawah ini pada dasarnya terkait dengan pemrograman berorientasi objek, khususnya OOP Java.
Nama kelas
Baca artikel singkat ini "Apa itu benda". Kelas harus berupa entitas abstrak dalam kehidupan nyata, bukan "validator", "pengontrol", dan "manajer". Jika nama kelas Anda diakhiri dengan "er" - itu desain yang buruk.
Tentu saja, kelas alat juga anti-pola, seperti StringUtils, FileUtils, dan IOUtils dari Apache. Semua hal di atas adalah contoh desain yang buruk. Bacaan lebih lanjut: Alternatif kelas alat di OOP.
Tentu saja, jangan gunakan awalan atau akhiran untuk membedakan kelas dari antarmuka. Misalnya, nama berikut ini salah: IRecord, IfaceEmployee, atau RecordInterface. Secara umum, nama antarmuka harus berupa nama entitas kehidupan nyata, dan nama kelas harus menjelaskan detail implementasinya. Jika tidak ada yang istimewa dalam implementasinya, Anda bisa menyebutnya Default, Simple atau sejenisnya. Misalnya:
Copy kode kodenya sebagai berikut:
kelas SimpleUser mengimplementasikan Pengguna {};
kelas DefaultRecord mengimplementasikan Rekam {};
class Suffixed mengimplementasikan Nama {};
kelas Divalidasi mengimplementasikan Konten {};
nama metode
Metode dapat mengembalikan nilai atau batal. Jika suatu metode mengembalikan suatu nilai, namanya harus menjelaskan apa yang dikembalikannya, misalnya (jangan pernah menggunakan awalan get):
Copy kode kodenya sebagai berikut:
boolean isValid(Nama string);
Konten string();
int ageOf(Berkas berkas);
Jika ia kembali batal, namanya harus menjelaskan fungsinya. Misalnya:
Copy kode kodenya sebagai berikut:
batal simpan(File file);
proses batal(Pekerjaan kerja);
void append(File file, baris String);
Hanya ada satu pengecualian terhadap aturan yang baru saja disebutkan - metode pengujian JUnit tidak dihitung. Ini akan dibahas di bawah.
Nama metode pengujian
Dalam kasus pengujian JUnit, nama metode harus berupa pernyataan bahasa Inggris tanpa spasi. Akan lebih jelas dengan sebuah contoh:
Copy kode kodenya sebagai berikut:
/**
* HttpRequest dapat mengembalikan kontennya dalam Unicode.
* @throws Pengecualian Jika tes gagal
*/
public void returnItsContentInUnicode() melempar Pengecualian {
}
Kalimat pertama di JavaDoc Anda harus dimulai dengan nama kelas yang ingin Anda uji, diikuti dengan can. Oleh karena itu, kalimat pertama Anda seharusnya seperti "seseorang dapat melakukan sesuatu".
Nama metodenya juga sama, hanya saja tanpa tema. Jika saya menambahkan subjek di tengah nama metode, saya mendapatkan kalimat lengkap, seperti pada contoh di atas: "HttpRequest mengembalikan kontennya dalam unicode".
Harap diperhatikan bahwa nama metode pengujian tidak dimulai dengan huruf can. Hanya komentar di JavaDoc yang akan dimulai dengan can. Selain itu, nama metode tidak boleh diawali dengan kata kerja.
Dalam praktiknya, yang terbaik adalah mendeklarasikan metode pengujian untuk menampilkan Pengecualian.
nama variabel
Hindari menggabungkan nama variabel, seperti timeOfDay, firstItem, atau httpRequest. Hal ini berlaku untuk variabel kelas dan variabel dalam metode. Nama variabel harus cukup panjang untuk menghindari ambiguitas dalam cakupan yang terlihat, namun jangan terlalu panjang jika memungkinkan. Nama harus berupa kata benda dalam bentuk tunggal atau jamak, atau singkatan yang sesuai. Misalnya:
Copy kode kodenya sebagai berikut:
Daftar<String> nama;
void sendThroughProxy(File file, Protokol proto);
konten File pribadi;
permintaan HttpRequest publik;
Terkadang, jika konstruktor menyimpan parameter masukan ke objek yang baru diinisialisasi, nama parameter dan atribut kelasnya mungkin bertentangan. Dalam hal ini, saran saya adalah menghilangkan huruf vokal dan menggunakan singkatan.
Contoh:
Copy kode kodenya sebagai berikut:
Pesan kelas publik {
penerima String pribadi;
Pesan publik(String rcpt) {
this.penerima = rcpt;
}
}
Seringkali, Anda dapat mengetahui nama variabel yang harus diberikan dengan melihat nama kelasnya. Gunakan saja bentuk huruf kecilnya, yang dapat diandalkan seperti ini:
Copy kode kodenya sebagai berikut:
berkas berkas;
pengguna pengguna;
cabang cabang;
Namun, Anda tidak boleh melakukan ini dengan tipe primitif, seperti bilangan Integer atau string String.
Jika ada beberapa variabel yang sifatnya berbeda, pertimbangkan untuk menggunakan kata sifat. Misalnya:
Copy kode kodenya sebagai berikut:
Kontak string (String kiri, String kanan);
Konstruktor
Mengabaikan pengecualian, hanya boleh ada satu konstruktor yang digunakan untuk menyimpan data ke dalam variabel objek. Konstruktor lain memanggil konstruktor ini dengan parameter berbeda. Misalnya:
Copy kode kodenya sebagai berikut:
Server kelas publik {
alamat String pribadi;
Server publik(String uri) {
alamat ini = uri;
}
Server Publik(uri URI) {
ini(uri.toString());
}
}
variabel satu kali
Variabel sekali pakai harus dihindari dengan cara apa pun. Yang saya maksud dengan “satu kali” disini adalah variabel yang hanya digunakan satu kali saja. Misalnya yang ini:
Copy kode kodenya sebagai berikut:
String nama = "data.txt";
kembalikan File baru (nama);
Variabel di atas hanya digunakan satu kali, sehingga kode ini dapat direstrukturisasi seperti ini:
Copy kode kodenya sebagai berikut:
kembalikan File baru("data.txt");
Terkadang, dalam kasus yang jarang terjadi—terutama untuk pemformatan yang terlihat lebih baik—variabel sekali pakai dapat digunakan. Namun, hal ini harus dihindari sebisa mungkin.
abnormal
Tentu saja, Anda tidak boleh menelan pengecualian itu sendiri, namun harus melewatkannya setinggi mungkin. Metode privat harus selalu menampilkan pengecualian yang dicentang.
Jangan gunakan pengecualian untuk kontrol aliran. Misalnya, kode berikut ini salah:
Copy kode kodenya sebagai berikut:
ukuran int;
mencoba {
ukuran = ini.ukuranfile();
} tangkapan (IOException ex) {
ukuran = 0;
}
Jadi apa yang harus Anda lakukan jika IOException meminta "Disk penuh"? Apakah Anda masih berpikir bahwa ukuran file adalah 0 dan melanjutkan pemrosesan?
lekukan
Mengenai lekukan, aturan utamanya adalah tanda kurung buka berakhir di akhir garis atau ditutup pada garis yang sama (berlaku sebaliknya untuk tanda kurung tutup). Misalnya, kalimat berikut ini salah karena tanda kurung buka pertama tidak ditutup pada baris yang sama dan ada karakter lain setelahnya. Tanda kurung siku kedua juga bermasalah karena diawali dengan karakter tetapi tanda kurung buka yang bersangkutan tidak berada pada baris yang sama:
Copy kode kodenya sebagai berikut:
File File terakhir = File baru (direktori,
"file.txt");
Indentasi yang benar seharusnya seperti ini:
Copy kode kodenya sebagai berikut:
StringUtils.join(
Array.asList(
"baris pertama",
"baris kedua",
StringUtils.join(
Array.asList("a", "b")
)
),
"pemisah"
);
Aturan penting kedua tentang indentasi adalah Anda harus mencoba menulis karakter sebanyak mungkin pada satu baris secara bersamaan - batas atasnya adalah 80 karakter. Contoh di atas tidak memenuhi hal ini, dapat juga diperkecil:
Copy kode kodenya sebagai berikut:
StringUtils.join(
Array.asList(
"baris pertama", "baris kedua",
StringUtils.join(Arrays.asList("a", "b"))
),
"pemisah"
);
konstanta yang berlebihan
Konstanta kelas harus digunakan ketika Anda ingin berbagi informasi dalam metode kelas. Informasi tersebut harus unik untuk kelas Anda. Jangan gunakan konstanta sebagai pengganti string atau literal numerik - ini adalah praktik yang sangat buruk dan akan mencemari kode Anda. Konstanta (seperti objek apa pun di OOP) harus memiliki arti tersendiri di dunia nyata. Mari kita lihat arti konstanta ini dalam kehidupan nyata:
Copy kode kodenya sebagai berikut:
kelas Dokumen {
private static final String D_LETTER = "D"; // praktik buruk
private static final String EXTENSION = ".doc"; // praktik yang baik
}
Kesalahan umum lainnya adalah menggunakan konstanta dalam pengujian unit untuk menghindari string atau literal numerik yang berlebihan dalam metode pengujian. Jangan lakukan ini! Setiap metode pengujian harus memiliki nilai masukan uniknya sendiri.
Gunakan teks atau nilai baru di setiap metode pengujian baru. Mereka independen satu sama lain. Jadi mengapa mereka masih berbagi konstanta masukan yang sama?
Uji kopling data
Berikut adalah contoh penggandengan data dalam metode pengujian:
Copy kode kodenya sebagai berikut:
Pengguna pengguna = Pengguna baru("Jeff");
// mungkin kode lain di sini
MatcherAssert.assertThat(pengguna.nama(), Matchers.equalTo("Jeff"));
Di baris terakhir, "Jeff" digabungkan ke string literal yang sama di baris pertama. Jika setelah beberapa bulan, seseorang ingin mengubah nilai pada baris ketiga, maka dia harus meluangkan waktu untuk mencari tahu di mana "Jeff" juga digunakan dalam metode yang sama.
Untuk menghindari hal ini, Anda sebaiknya memperkenalkan variabel.