CodeGym /Java Blog /Acak /Apa itu anti-pola? Mari kita lihat beberapa contoh (Bagia...
John Squirrels
Level 41
San Francisco

Apa itu anti-pola? Mari kita lihat beberapa contoh (Bagian 2)

Dipublikasikan di grup Acak
Apa itu anti-pola? Mari kita lihat beberapa contoh (Bagian 1) Hari ini kami melanjutkan ulasan kami tentang anti-pola paling populer. Jika Anda melewatkan bagian pertama, ini dia. Apa itu anti-pola?  Mari kita lihat beberapa contoh (Bagian 2) - 1Jadi, pola desain adalah praktik terbaik. Dengan kata lain, mereka adalah contoh cara yang baik dan telah teruji oleh waktu untuk memecahkan masalah tertentu. Pada gilirannya, anti-pola adalah kebalikannya, dalam arti bahwa mereka adalah pola jebakan atau kesalahan saat memecahkan berbagai masalah (pola jahat). Mari kita lanjutkan ke anti-pola pengembangan perangkat lunak berikutnya.

8. Palu emas

Palu emas adalah anti-pola yang ditentukan oleh keyakinan bahwa solusi tertentu dapat diterapkan secara universal. Contoh:
  1. Setelah menemui masalah dan menemukan pola untuk solusi yang sempurna, seorang programmer mencoba menempelkan pola ini di mana-mana, menerapkannya pada proyek saat ini dan semua proyek masa depan, alih-alih mencari solusi yang tepat untuk kasus tertentu.

  2. Beberapa pengembang pernah membuat varian cache mereka sendiri untuk situasi tertentu (karena tidak ada lagi yang cocok). Kemudian, pada proyek berikutnya yang tidak melibatkan logika cache khusus, mereka menggunakan variannya lagi alih-alih menggunakan pustaka yang sudah jadi (misalnya, Ehcache). Hasilnya adalah banyak bug dan ketidakcocokan, serta banyak waktu yang terbuang dan saraf yang tergores.

    Siapa saja bisa tertipu dengan anti-pola ini. Jika Anda seorang pemula, Anda mungkin tidak memiliki pengetahuan tentang pola desain. Hal ini dapat mengarahkan Anda untuk mencoba menyelesaikan semua masalah dengan satu cara yang telah Anda kuasai. Jika kita berbicara tentang profesional, maka kita menyebutnya deformasi profesional atau nerdview. Anda memiliki pola desain pilihan Anda sendiri, dan alih-alih menggunakan yang benar, Anda menggunakan favorit Anda, dengan asumsi bahwa kecocokan yang baik di masa lalu menjamin hasil yang sama di masa mendatang.

    Jebakan ini dapat menghasilkan hasil yang sangat menyedihkan — mulai dari implementasi yang buruk, tidak stabil, dan sulit dipertahankan hingga kegagalan total proyek. Sama seperti tidak ada satu pil untuk semua penyakit, tidak ada satu pola desain untuk semua kesempatan.

9. Optimalisasi prematur

Pengoptimalan prematur adalah anti-pola yang namanya berbicara sendiri.
"Programmer menghabiskan banyak waktu untuk memikirkan dan mengkhawatirkan tempat-tempat non-kritis dalam kode dan mencoba mengoptimalkannya, yang hanya berdampak negatif pada proses debug dan dukungan selanjutnya. Secara umum, kita harus melupakan pengoptimalan dalam, katakanlah, 97% kasus. Selain itu , pengoptimalan prematur adalah akar dari semua kejahatan. Karena itu, kita harus memperhatikan 3% sisanya." —Donald Knuth
Misalnya, menambahkan indeks sebelum waktunya ke database. Mengapa itu buruk? Yah, itu buruk karena indeks disimpan sebagai pohon biner. Akibatnya, setiap kali nilai baru ditambahkan dan dihapus, pohon akan dihitung ulang, dan ini menghabiskan sumber daya dan waktu. Oleh karena itu, indeks harus ditambahkan hanya jika ada kebutuhan mendesak (jika Anda memiliki data dalam jumlah besar dan permintaan terlalu lama) dan hanya untuk bidang yang paling penting (bidang yang paling sering ditanyakan).

10. Kode spageti

Kode spageti adalah anti-pola yang ditentukan oleh kode yang terstruktur dengan buruk, membingungkan, dan sulit dipahami, berisi semua jenis percabangan, seperti pengecualian pembungkus, kondisi, dan loop. Sebelumnya, operator goto adalah sekutu utama anti-pola ini. Pernyataan Goto tidak benar-benar digunakan lagi, yang dengan senang hati menghilangkan sejumlah kesulitan dan masalah terkait.

public boolean someDifficultMethod(List<String> XMLAttrList) {
           ...
   int prefix = stringPool.getPrefixForQName(elementType);
   int elementURI;
   try {
       if (prefix == -1) {
        ...
           if (elementURI != -1) {
               stringPool.setURIForQName(...);
           }
       } else {
        ...
           if (elementURI == -1) {
           ...
           }
       }
   } catch (Exception e) {
       return false;
   }
   if (attrIndex != -1) {
       int index = attrList.getFirstAttr(attrIndex);
       while (index != -1) {
           int attName = attrList.getAttrName(index);
           if (!stringPool.equalNames(...)){
           ...
               if (attPrefix != namespacesPrefix) {
                   if (attPrefix == -1) {
                    ...
                   } else {
                       if (uri == -1) {
                       ...
                       }
                       stringPool.setURIForQName(attName, uri);
                   ...
                   }
                   if (elementDepth >= 0) {
                   ...
                   }
                   elementDepth++;
                   if (elementDepth == fElementTypeStack.length) {
                   ...
                   }
               ...
                   return contentSpecType == fCHILDRENSymbol;
               }
           }
       }
   }
}
Kelihatannya mengerikan, bukan? Sayangnya, ini adalah anti-pola yang paling umum :( Bahkan orang yang menulis kode seperti itu tidak akan dapat memahaminya di masa mendatang. Pengembang lain yang melihat kode tersebut akan berpikir, "Baiklah, jika berhasil, oke — lebih baik tidak menyentuhnya". Seringkali, sebuah metode pada awalnya sederhana dan sangat transparan, tetapi ketika persyaratan baru ditambahkan, metode ini secara bertahap dibebani dengan pernyataan bersyarat yang semakin banyak, mengubahnya menjadi keburukan seperti ini. Jika metode seperti itu muncul, Anda perlu memfaktorkan ulangnya sepenuhnya atau setidaknya bagian yang paling membingungkan. Biasanya, saat menjadwalkan proyek, waktu dialokasikan untuk pemfaktoran ulang, misalnya, 30% waktu sprint adalah untuk pemfaktoran ulang dan pengujian. Tentu saja, ini mengasumsikan bahwa tidak ada terburu-buru (tetapi kapan itu pernah terjadi).di sini .

11. Angka ajaib

Angka ajaib adalah anti-pola di mana semua jenis konstanta digunakan dalam program tanpa penjelasan apa pun tentang tujuan atau artinya. Artinya, mereka umumnya diberi nama yang buruk atau dalam kasus ekstrim, tidak ada komentar yang menjelaskan apa atau mengapa komentar tersebut. Seperti kode spageti, ini adalah salah satu anti-pola yang paling umum. Seseorang yang tidak menulis kode mungkin atau mungkin tidak memiliki petunjuk tentang angka ajaib atau cara kerjanya (dan pada waktunya, penulis sendiri tidak akan dapat menjelaskannya). Akibatnya, mengubah atau menghapus nomor menyebabkan kode berhenti bekerja secara bersamaan. Misalnya, 36 dan 73. Untuk mengatasi anti-pola ini, saya merekomendasikan tinjauan kode. Kode Anda perlu dilihat oleh pengembang yang tidak terlibat dalam bagian kode yang relevan. Mata mereka akan segar dan mereka akan bertanya: apa ini dan mengapa Anda melakukan itu? Dan tentu saja, Anda perlu menggunakan nama penjelas atau meninggalkan komentar.

12. Salin dan tempel pemrograman

Pemrograman salin dan tempel adalah anti-pola di mana kode orang lain disalin dan ditempel tanpa berpikir, kemungkinan mengakibatkan efek samping yang tidak terduga. Misalnya, metode salin dan tempel dengan perhitungan matematis atau algoritme rumit yang tidak sepenuhnya kita pahami. Ini mungkin berhasil untuk kasus khusus kami, tetapi dalam beberapa keadaan lain dapat menyebabkan masalah. Misalkan saya memerlukan metode untuk menentukan jumlah maksimum dalam sebuah array. Mengaduk-aduk Internet, saya menemukan solusi ini:

public static int max(int[] array) {
   int max = 0;
   for(int i = 0; i < array.length; i++) {
       if (Math.abs(array[i]) > max){
           max = array[i];
       }
   }
   return max;
}
Kami mendapatkan array dengan angka 3, 6, 1, 4, dan 2, dan metode mengembalikan 6. Hebat, mari kita pertahankan! Tapi nanti kita mendapatkan array yang terdiri dari 2.5, -7, 2, dan 3, dan hasilnya adalah -7. Dan hasil ini tidak baik. Masalahnya di sini adalah Math.abs() mengembalikan nilai absolut. Ketidaktahuan akan hal ini menyebabkan bencana, tetapi hanya dalam situasi tertentu. Tanpa pemahaman mendalam tentang solusinya, ada banyak kasus yang tidak dapat Anda verifikasi. Kode yang disalin juga dapat melampaui struktur internal aplikasi, baik secara gaya maupun pada tingkat arsitektur yang lebih mendasar. Kode seperti itu akan lebih sulit dibaca dan dipelihara. Dan tentu saja, kita tidak boleh lupa bahwa langsung menyalin kode orang lain adalah jenis plagiarisme khusus.

13. Menemukan kembali roda

Menemukan kembali roda adalah anti-pola, terkadang juga dikenal sebagai menemukan kembali roda persegi. Intinya, template ini adalah kebalikan dari anti-pola copy-paste yang dipertimbangkan di atas. Dalam anti-pola ini, pengembang mengimplementasikan solusinya sendiri untuk masalah yang solusinya sudah ada. Terkadang solusi yang ada ini lebih baik daripada yang diciptakan oleh programmer. Paling sering, ini hanya menyebabkan hilangnya waktu dan produktivitas yang lebih rendah: pemrogram mungkin tidak menemukan solusi sama sekali atau mungkin menemukan solusi yang jauh dari yang terbaik. Meskipun demikian, kami tidak dapat mengesampingkan kemungkinan untuk membuat solusi independen, karena melakukan itu adalah jalan langsung ke pemrograman salin dan tempel. Pemrogram harus dipandu oleh tugas pemrograman khusus yang muncul untuk menyelesaikannya secara kompeten, baik dengan menggunakan solusi yang sudah jadi atau dengan membuat solusi khusus. Sangat sering, alasan menggunakan anti-pola ini hanya karena tergesa-gesa. Hasilnya adalah analisis dangkal (mencari) solusi yang sudah jadi. Menemukan kembali roda persegi adalah kasus di mana anti-pola yang dipertimbangkan memiliki hasil negatif. Artinya, proyek memerlukan solusi khusus, dan pengembang membuatnya, tetapi buruk. Pada saat yang sama, opsi yang bagus sudah ada dan yang lain berhasil menggunakannya. Intinya: banyak waktu yang hilang. Pertama, kami membuat sesuatu yang tidak berfungsi. Lalu kita coba refactor, dan akhirnya kita ganti dengan yang sudah ada. Contohnya adalah mengimplementasikan cache kustom Anda sendiri ketika banyak implementasi sudah ada. Tidak peduli seberapa berbakat Anda sebagai seorang programmer, Anda harus ingat bahwa menemukan kembali roda persegi paling tidak hanya membuang-buang waktu. Dan, seperti yang Anda ketahui, waktu adalah sumber daya yang paling berharga.

14. Masalah yo-yo

Masalah yo-yo adalah anti-pola di mana struktur aplikasi menjadi terlalu rumit karena fragmentasi yang berlebihan (misalnya, rantai pewarisan yang dibagi secara berlebihan). "Masalah yo-yo" muncul saat Anda perlu memahami program yang hierarki pewarisannya panjang dan kompleks, membuat pemanggilan metode bersarang dalam. Akibatnya, pemrogram perlu menavigasi di antara banyak kelas dan metode yang berbeda untuk memeriksa perilaku program. Nama anti pola ini berasal dari nama mainannya. Sebagai contoh, mari kita lihat rantai pewarisan berikut: Kami memiliki antarmuka Teknologi:

public interface Technology {
   void turnOn();
}
Antarmuka Transport mewarisinya:

public interface Transport extends Technology {
   boolean fillUp();
}
Dan kemudian kami memiliki antarmuka lain, GroundTransport:

public interface GroundTransportation extends Transport {
   void startMove();
   void brake();
}
Dan dari sana, kami memperoleh kelas Mobil abstrak:

public abstract class Car implements GroundTransportation {
   @Override
   public boolean fillUp() {
       /* some implementation */
       return true;
   }
   @Override
   public void turnOn() {
       /* some implementation */
   }
   public boolean openTheDoor() {
       /* some implementation */
       return true;
   }
   public abstract void fixCar();
}
Berikutnya adalah kelas Volkswagen abstrak:

public abstract class Volkswagen extends Car {
   @Override
   public void startMove() {
       /* some implementation */
   }
   @Override
   public void brake() {
       /* some implementation */
   }
}
Dan akhirnya, model tertentu:

public class VolkswagenAmarok extends Volkswagen {
   @Override
   public void fixCar(){
       /* some implementation */
   }
}
Rantai ini memaksa kita untuk mencari jawaban atas pertanyaan seperti:
  1. Berapa banyak metode yang VolkswagenAmarokdimiliki?

  2. Jenis apa yang harus dimasukkan alih-alih tanda tanya untuk mencapai abstraksi maksimum:

    
    ? someObj = new VolkswagenAmarok();
           someObj.brake();
    
Sulit untuk menjawab pertanyaan seperti itu dengan cepat — ini mengharuskan kita untuk melihat dan menyelidiki, dan mudah untuk menjadi bingung. Dan bagaimana jika hierarkinya jauh lebih besar, lebih panjang, dan lebih rumit, dengan segala macam kelebihan dan penggantian? Struktur yang kami miliki akan menjadi kabur karena fragmentasi yang berlebihan. Solusi terbaik adalah mengurangi pembagian yang tidak perlu. Dalam kasus kami, kami akan meninggalkan Teknologi → Mobil → VolkswagenAmarok.

15. Kompleksitas yang tidak disengaja

Kompleksitas yang tidak perlu adalah anti-pola di mana komplikasi yang tidak perlu diperkenalkan ke solusi.
"Orang bodoh mana pun bisa menulis kode yang bisa dimengerti komputer. Pemrogram yang baik menulis kode yang bisa dimengerti manusia." —Martin Fowler
Jadi apa itu kompleksitas? Ini dapat didefinisikan sebagai tingkat kesulitan yang dilakukan setiap operasi dalam program. Sebagai aturan, kompleksitas dapat dibagi menjadi dua jenis. Jenis kompleksitas pertama adalah jumlah fungsi yang dimiliki suatu sistem. Ini dapat dikurangi hanya dengan satu cara — dengan menghapus beberapa fungsi. Metode yang ada perlu dipantau. Suatu metode harus dihilangkan jika sudah tidak digunakan lagi atau masih digunakan tetapi tidak membawa nilai apapun. Terlebih lagi, Anda perlu menilai bagaimana semua metode dalam aplikasi digunakan, untuk memahami di mana investasi akan bermanfaat (banyak penggunaan kembali kode) dan apa yang dapat Anda katakan tidak. Jenis kompleksitas kedua adalah kompleksitas yang tidak perlu. Ini dapat disembuhkan hanya melalui pendekatan profesional. Alih-alih melakukan sesuatu yang "keren" (pengembang muda bukan satu-satunya yang rentan terhadap penyakit ini), Anda perlu memikirkan cara melakukannya sesederhana mungkin, karena solusi terbaik selalu sederhana. Misalnya, kita memiliki tabel terkait kecil dengan deskripsi beberapa entitas, seperti pengguna: Apa itu anti-pola?  Mari kita lihat beberapa contoh (Bagian 2) - 3Jadi, kami memiliki id pengguna, id bahasa tempat deskripsi dibuat, dan deskripsi itu sendiri. Demikian pula, kami memiliki deskriptor tambahan untuk mobil, file, paket, dan tabel pelanggan. Lalu seperti apa memasukkan nilai baru ke dalam tabel seperti itu?

public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
   switch (type){
       case CAR:
           jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
       case USER:
           jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
       case FILE:
           jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
       case PLAN:
           jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
       case CUSTOMER:
           jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
       default:
           throw new Exception();
   }
}
Dan karenanya, kami memiliki enum ini:

public enum ServiceType {
   CAR(),
   USER(),
   FILE(),
   PLAN(),
   CUSTOMER()
}
Segalanya tampak sederhana dan bagus... Tapi bagaimana dengan metode lainnya? Memang, mereka semua juga akan memiliki banyak switchpernyataan dan banyak kueri basis data yang hampir sama, yang pada gilirannya akan sangat memperumit dan menggembungkan kelas kita. Bagaimana semua ini bisa dipermudah? Mari tingkatkan enum kita sedikit:

@Getter
@AllArgsConstructor
public enum ServiceType {
   CAR("cars_descriptions", "car_id"),
   USER("users_descriptions", "user_id"),
   FILE("files_descriptions", "file_id"),
   PLAN("plans_descriptions", "plan_id"),
   CUSTOMER("customers_descriptions", "customer_id");
   private String tableName;
   private String columnName;
}
Sekarang setiap jenis memiliki nama bidang asli tabelnya. Akibatnya, metode untuk membuat deskripsi menjadi:

private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
   jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
   }
Nyaman, sederhana, dan kompak, bukan begitu? Indikasi pengembang yang baik bukanlah seberapa sering dia menggunakan pola, melainkan seberapa sering dia menghindari anti-pola. Ketidaktahuan adalah musuh terburuk, karena Anda perlu mengetahui musuh Anda melalui penglihatan. Yah, itu saja yang saya miliki untuk hari ini. Terima kasih semuanya! :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION