JavaRush /Java Blog /Random-ID /Cara kerja refactoring di Java

Cara kerja refactoring di Java

Dipublikasikan di grup Random-ID
Saat belajar pemrograman, banyak waktu yang dihabiskan untuk menulis kode. Kebanyakan pengembang pemula percaya bahwa ini adalah aktivitas mereka di masa depan. Hal ini sebagian benar, tetapi tugas programmer juga mencakup pemeliharaan dan pemfaktoran ulang kode. Hari ini kita akan berbicara tentang refactoring. Cara kerja refactoring di Java - 1

Memfaktorkan ulang dalam kursus JavaRush

Kursus JavaRush mencakup topik refactoring dua kali: Berkat tugas besarnya, ada kesempatan untuk mengenal praktik refactoring yang sebenarnya, dan kuliah tentang refactoring di IDEA akan membantu Anda memahami alat otomatis yang membuat hidup menjadi lebih mudah.

Apa itu pemfaktoran ulang?

Ini adalah perubahan struktur kode tanpa mengubah fungsinya. Misalnya, ada metode yang membandingkan 2 angka dan mengembalikan nilai benar jika angka pertama lebih besar, dan salah jika sebaliknya:
public boolean max(int a, int b) {
    if(a > b) {
        return true;
    } else if(a == b) {
        return false;
    } else {
        return false;
    }
}
Hasilnya adalah kode yang sangat rumit. Bahkan pemula pun jarang menulis hal seperti ini, tetapi ada risiko seperti itu. Tampaknya mengapa ada blok di sini if-elsejika Anda dapat menulis metode 6 baris lebih pendek:
public boolean max(int a, int b) {
     return a>b;
}
Nah cara ini terlihat sederhana dan elegan, meskipun fungsinya sama seperti contoh di atas. Beginilah cara kerja refactoring: mengubah struktur kode tanpa mempengaruhi esensinya. Ada banyak metode dan teknik refactoring, yang akan kita bahas lebih detail.

Mengapa pemfaktoran ulang diperlukan?

Ada beberapa alasan. Misalnya, mengejar kesederhanaan dan keringkasan kode. Para pendukung teori ini percaya bahwa kode tersebut harus sesingkat mungkin, meskipun memerlukan beberapa lusin baris komentar untuk memahaminya. Pengembang lain percaya bahwa kode harus difaktorkan ulang agar dapat dimengerti dengan jumlah komentar yang minimal. Masing-masing tim memilih posisinya, namun kita harus ingat bahwa refactoring bukanlah pengurangan . Tujuan utamanya adalah memperbaiki struktur kode. Beberapa tujuan dapat dimasukkan dalam tujuan global ini:
  1. Refactoring meningkatkan pemahaman kode yang ditulis oleh pengembang lain;
  2. Membantu menemukan dan memperbaiki kesalahan;
  3. Memungkinkan Anda meningkatkan kecepatan pengembangan perangkat lunak;
  4. Secara keseluruhan meningkatkan komposisi perangkat lunak.
Jika refactoring tidak dilakukan dalam waktu lama, kesulitan pengembangan mungkin timbul, hingga penghentian total pekerjaan.

“Kode berbau”

Ketika kode memerlukan pemfaktoran ulang, mereka mengatakan kode tersebut “berbau”. Tentu saja, tidak secara harfiah, tetapi kode seperti itu sebenarnya tidak terlihat bagus. Di bawah ini kami akan mempertimbangkan teknik refactoring utama untuk tahap awal.

Elemen berukuran besar yang tidak perlu

Ada kelas dan metode rumit yang tidak mungkin digunakan secara efektif justru karena ukurannya yang besar.

Kelas besar

Kelas seperti itu memiliki banyak baris kode dan banyak metode berbeda. Biasanya lebih mudah bagi pengembang untuk menambahkan fitur ke kelas yang sudah ada daripada membuat yang baru, itulah sebabnya kelas tersebut berkembang. Biasanya, fungsionalitas kelas ini kelebihan beban. Dalam hal ini, memisahkan sebagian fungsi ke dalam kelas terpisah akan membantu. Kami akan membicarakan hal ini lebih detail di bagian teknik refactoring.

Metode Besar

“Bau” ini terjadi ketika pengembang menambahkan fungsionalitas baru ke suatu metode. “Mengapa saya harus menempatkan pemeriksaan parameter dalam metode terpisah jika saya dapat menulisnya di sini?”, “Mengapa perlu memisahkan metode untuk menemukan elemen maksimum dalam array, biarkan saja di sini. Dengan cara ini kodenya menjadi lebih jelas,” dan kesalahpahaman lainnya. Ada dua aturan untuk melakukan refactoring metode besar:
  1. Jika, saat menulis suatu metode, Anda ingin menambahkan komentar ke kode, Anda perlu memisahkan fungsi ini menjadi metode terpisah;
  2. Jika suatu metode membutuhkan lebih dari 10-15 baris kode, Anda harus mengidentifikasi tugas dan subtugas yang dijalankannya dan mencoba memisahkan subtugas tersebut ke dalam metode terpisah.
Beberapa cara menghilangkan metode besar:
  • Pisahkan bagian fungsionalitas suatu metode menjadi metode tersendiri;
  • Jika variabel lokal tidak memungkinkan Anda mengekstrak sebagian fungsionalitas, Anda dapat meneruskan seluruh objek ke metode lain.

Menggunakan banyak tipe data primitif

Biasanya, masalah ini terjadi ketika jumlah bidang untuk menyimpan data di kelas bertambah seiring waktu. Misalnya, jika Anda menggunakan tipe primitif alih-alih objek kecil untuk menyimpan data (mata uang, tanggal, nomor telepon, dll.) atau konstanta untuk menyandikan informasi apa pun. Praktik yang baik dalam hal ini adalah mengelompokkan bidang secara logis dan menempatkannya di kelas terpisah (memilih kelas). Anda juga bisa memasukkan metode untuk memproses data ini di kelas.

Daftar opsi yang panjang

Kesalahan yang cukup umum, terutama jika dikombinasikan dengan metode yang besar. Biasanya terjadi jika fungsionalitas metode kelebihan beban, atau metode menggabungkan beberapa algoritma. Daftar parameter yang panjang sangat sulit untuk dipahami, dan metode seperti itu tidak nyaman untuk digunakan. Oleh karena itu, lebih baik untuk mentransfer seluruh objek. Jika objek tidak memiliki cukup data, sebaiknya gunakan objek yang lebih umum atau pisahkan fungsionalitas metode sehingga dapat memproses data yang terkait secara logis.

Grup data

Kelompok data yang terkait secara logis sering kali muncul dalam kode. Misalnya, parameter koneksi ke database (URL, nama pengguna, kata sandi, nama skema, dll.). Jika tidak ada satu field pun yang dapat dikeluarkan dari daftar elemen, maka daftar tersebut adalah sekelompok data yang harus ditempatkan dalam kelas tersendiri (pemilihan kelas).

Solusi yang merusak konsep OOP

Jenis “bau” ini terjadi ketika pengembang melanggar desain OOP. Hal ini terjadi jika ia tidak sepenuhnya memahami kemampuan paradigma ini, menggunakannya secara tidak lengkap atau salah.

Penolakan warisan

Jika subkelas menggunakan sebagian kecil fungsi kelas induk, hal ini akan menimbulkan bau hierarki yang salah. Biasanya, dalam kasus ini, metode yang tidak perlu tidak ditimpa atau pengecualian diberikan. Jika suatu kelas diwarisi dari kelas lain, ini berarti fungsionalitasnya hampir sepenuhnya digunakan. Contoh hierarki yang benar: Cara kerja refactoring di Java - 2 Contoh hierarki yang salah: Cara kerja refactoring di Java - 3

pernyataan peralihan

Apa yang salah dengan operator switch? Buruk bila desainnya sangat rumit. Ini juga mencakup banyak blok bersarang if.

Kelas alternatif dengan antarmuka berbeda

Beberapa kelas sebenarnya melakukan hal yang sama, tetapi metodenya diberi nama berbeda.

Bidang sementara

Jika kelas berisi bidang sementara yang hanya dibutuhkan objek sesekali, saat diisi dengan nilai, dan di waktu lain kosong atau, amit-amit, null, maka kodenya “berbau”, dan desain seperti itu meragukan keputusan.

Bau yang membuat modifikasi menjadi sulit

“Bau” ini lebih serius. Sisanya terutama mengganggu pemahaman kode, sementara ini tidak memungkinkan untuk memodifikasinya. Saat memperkenalkan fitur apa pun, separuh pengembang akan berhenti, dan separuh lagi akan menjadi gila.

Hierarki warisan paralel

Saat Anda membuat subkelas dari suatu kelas, Anda harus membuat subkelas lain untuk kelas lain.

Distribusi ketergantungan yang seragam

Saat melakukan modifikasi apa pun, Anda harus mencari semua dependensi (penggunaan) kelas ini dan membuat banyak perubahan kecil. Satu perubahan - pengeditan di banyak kelas.

Pohon modifikasi yang kompleks

Bau ini adalah kebalikan dari yang sebelumnya: perubahan mempengaruhi sejumlah besar metode di kelas yang sama. Biasanya, ketergantungan pada kode tersebut bersifat cascading: setelah mengubah satu metode, Anda perlu memperbaiki sesuatu di metode lain, lalu di metode ketiga, dan seterusnya. Satu kelas - banyak perubahan.

“Bau sampah”

Kategori bau yang agak tidak sedap yang menyebabkan sakit kepala. Kode lama yang tidak berguna dan tidak perlu. Untungnya, IDE dan linter modern telah belajar untuk memperingatkan tentang bau tersebut.

Sejumlah besar komentar dalam metode ini

Metode ini memiliki banyak komentar penjelasan di hampir setiap baris. Ini biasanya dikaitkan dengan algoritme yang kompleks, jadi lebih baik membagi kode menjadi beberapa metode yang lebih kecil dan memberinya nama yang bermakna.

Duplikasi kode

Kelas atau metode yang berbeda menggunakan blok kode yang sama.

Kelas malas

Kelas ini hanya memiliki sedikit fungsi, meskipun banyak yang telah direncanakan.

Kode yang tidak digunakan

Kelas, metode, atau variabel tidak digunakan dalam kode dan merupakan “bobot mati”.

Kopling yang berlebihan

Kategori bau ini ditandai dengan banyaknya koneksi yang tidak perlu dalam kode.

Metode pihak ketiga

Suatu metode lebih sering menggunakan data objek lain daripada menggunakan datanya sendiri.

Keintiman yang tidak pantas

Sebuah kelas menggunakan bidang layanan dan metode kelas lain.

Panggilan kelas yang panjang

Satu kelas memanggil kelas lain, yang meminta data dari kelas ketiga, kelas keempat, dan seterusnya. Rantai panggilan yang begitu panjang berarti tingginya tingkat ketergantungan pada struktur kelas saat ini.

Dealer tugas kelas

Sebuah kelas hanya diperlukan untuk meneruskan tugas ke kelas lain. Mungkin itu harus dihapus?

Teknik Refaktorisasi

Di bawah ini kita akan membahas teknik refactoring awal yang akan membantu menghilangkan bau kode yang dijelaskan.

Pemilihan kelas

Kelas menjalankan terlalu banyak fungsi; beberapa di antaranya perlu dipindahkan ke kelas lain. Misalnya, ada kelas Humanyang juga berisi alamat tempat tinggal dan metode yang memberikan alamat lengkap:
class Human {
   private String name;
   private String age;
   private String country;
   private String city;
   private String street;
   private String house;
   private String quarter;

   public String getFullAddress() {
       StringBuilder result = new StringBuilder();
       return result
                       .append(country)
                       .append(", ")
                       .append(city)
                       .append(", ")
                       .append(street)
                       .append(", ")
                       .append(house)
                       .append(" ")
                       .append(quarter).toString();
   }
}
Sebaiknya tempatkan informasi alamat dan metode (perilaku pemrosesan data) di kelas terpisah:
class Human {
   private String name;
   private String age;
   private Address address;

   private String getFullAddress() {
       return address.getFullAddress();
   }
}
class Address {
   private String country;
   private String city;
   private String street;
   private String house;
   private String quarter;

   public String getFullAddress() {
       StringBuilder result = new StringBuilder();
       return result
                       .append(country)
                       .append(", ")
                       .append(city)
                       .append(", ")
                       .append(street)
                       .append(", ")
                       .append(house)
                       .append(" ")
                       .append(quarter).toString();
   }
}

Pemilihan metode

Jika ada fungsi dalam suatu metode yang dapat dikelompokkan, maka fungsi tersebut harus ditempatkan dalam metode terpisah. Misalnya, metode menghitung akar-akar persamaan kuadrat:
public void calcQuadraticEq(double a, double b, double c) {
    double D = b * b - 4 * a * c;
    if (D > 0) {
        double x1, x2;
        x1 = (-b - Math.sqrt(D)) / (2 * a);
        x2 = (-b + Math.sqrt(D)) / (2 * a);
        System.out.println("x1 = " + x1 + ", x2 = " + x2);
    }
    else if (D == 0) {
        double x;
        x = -b / (2 * a);
        System.out.println("x = " + x);
    }
    else {
        System.out.println("Equation has no roots");
    }
}
Mari kita pindahkan penghitungan ketiga opsi yang mungkin ke dalam metode terpisah:
public void calcQuadraticEq(double a, double b, double c) {
    double D = b * b - 4 * a * c;
    if (D > 0) {
        dGreaterThanZero(a, b, D);
    }
    else if (D == 0) {
        dEqualsZero(a, b);
    }
    else {
        dLessThanZero();
    }
}

public void dGreaterThanZero(double a, double b, double D) {
    double x1, x2;
    x1 = (-b - Math.sqrt(D)) / (2 * a);
    x2 = (-b + Math.sqrt(D)) / (2 * a);
    System.out.println("x1 = " + x1 + ", x2 = " + x2);
}

public void dEqualsZero(double a, double b) {
    double x;
    x = -b / (2 * a);
    System.out.println("x = " + x);
}

public void dLessThanZero() {
    System.out.println("Equation has no roots");
}
Kode untuk setiap metode menjadi lebih pendek dan jelas.

Mentransfer seluruh objek

Saat memanggil metode dengan parameter, terkadang Anda dapat melihat kode seperti ini:
public void employeeMethod(Employee employee) {
    // Некоторые действия
    double yearlySalary = employee.getYearlySalary();
    double awards = employee.getAwards();
    double monthlySalary = getMonthlySalary(yearlySalary, awards);
    // Продолжение обработки
}

public double getMonthlySalary(double yearlySalary, double awards) {
     return (yearlySalary + awards)/12;
}
Dalam metodenya, employeeMethodsebanyak 2 baris dialokasikan untuk memperoleh nilai dan menyimpannya dalam variabel primitif. Terkadang desain seperti itu membutuhkan hingga 10 baris. Jauh lebih mudah untuk meneruskan objek itu sendiri ke metode, dari mana Anda dapat mengekstrak data yang diperlukan:
public void employeeMethod(Employee employee) {
    // Некоторые действия
    double monthlySalary = getMonthlySalary(employee);
    // Продолжение обработки
}

public double getMonthlySalary(Employee employee) {
    return (employee.getYearlySalary() + employee.getAwards())/12;
}
Sederhana, singkat dan padat.

Pengelompokan bidang secara logis dan menempatkannya di kelas terpisah

Terlepas dari kenyataan bahwa contoh di atas sangat sederhana dan ketika melihatnya banyak yang mungkin bertanya "Siapa sebenarnya yang melakukan ini?", banyak pengembang, karena kurangnya perhatian, keengganan untuk memfaktorkan ulang kode, atau sekadar "Ini akan berhasil", membuat kesalahan struktural serupa.

Mengapa refactoring efektif

Hasil dari refactoring yang baik adalah program yang kodenya mudah dibaca, modifikasi logika program tidak menjadi ancaman, dan pengenalan fitur-fitur baru tidak berubah menjadi penguraian kode, tetapi aktivitas yang menyenangkan selama beberapa hari. . Refactoring sebaiknya tidak digunakan jika akan lebih mudah untuk menulis ulang program dari awal. Misalnya, tim memperkirakan biaya tenaga kerja untuk menguraikan, menganalisis, dan memfaktorkan ulang kode lebih tinggi dibandingkan mengimplementasikan fungsi yang sama dari awal. Atau kode yang perlu di refactoring banyak errornya sehingga sulit untuk di-debug. Mengetahui cara memperbaiki struktur kode adalah suatu keharusan dalam pekerjaan seorang programmer. Nah, lebih baik belajar pemrograman Java di JavaRush - kursus online dengan penekanan pada latihan. 1200+ tugas dengan verifikasi instan, sekitar 20 proyek mini, tugas permainan - semua ini akan membantu Anda merasa percaya diri dalam coding. Waktu terbaik untuk memulai adalah sekarang :) Cara kerja refactoring di Java - 4

Sumber daya untuk mempelajari lebih lanjut tentang pemfaktoran ulang

Buku paling terkenal tentang refactoring adalah “Refactoring. Memperbaiki Desain Kode yang Ada” oleh Martin Fowler. Ada juga publikasi menarik tentang refactoring, yang ditulis berdasarkan buku sebelumnya - “Refactoring with Patterns” oleh Joshua Kiriewski. Berbicara tentang template. Saat melakukan refactoring, mengetahui pola desain aplikasi dasar selalu sangat berguna. Buku-buku hebat ini akan membantu dalam hal ini:
  1. “Pola Desain” - oleh Eric Freeman, Elizabeth Freeman, Kathy Sierra, Bert Bates dari seri Head First;
  2. “Kode yang Dapat Dibaca, atau Pemrograman sebagai Seni” - Dustin Boswell, Trevor Faucher.
  3. “Perfect Code” oleh Steve McConnell, yang menguraikan prinsip-prinsip kode yang indah dan elegan.
Nah, beberapa artikel tentang refactoring:
  1. Tugas yang luar biasa: mari mulai memfaktorkan ulang kode lama ;
  2. pemfaktoran ulang ;
  3. Memfaktorkan ulang untuk semua orang .
    Komentar
    TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
    GO TO FULL VERSION