Menggunakan perpustakaan pihak ketiga - selalu menggunakan pembungkus?


78

Sebagian besar proyek yang saya gunakan menggunakan beberapa komponen open-source. Sebagai prinsip umum, apakah itu ide yang baik untuk selalu menghindari mengikat semua komponen kode ke perpustakaan pihak ketiga dan bukannya pergi melalui pembungkus enkapsulasi untuk menghindari rasa sakit perubahan?

Sebagai contoh, sebagian besar proyek PHP kami secara langsung menggunakan log4php sebagai kerangka logging, yaitu mereka instantiate melalui \ Logger :: getLogger (), mereka menggunakan -> info () atau -> memperingatkan () metode, dll. Di masa depan, namun, kerangka kerja logging hipotetis mungkin muncul yang lebih baik dalam beberapa hal. Seperti yang terjadi, semua proyek yang sangat dekat dengan tanda tangan metode log4php harus berubah, di puluhan tempat, agar sesuai dengan tanda tangan baru. Ini jelas akan memiliki dampak luas pada basis kode dan setiap perubahan adalah masalah potensial.

Untuk membuktikan basis kode baru dari skenario semacam ini, saya sering mempertimbangkan (dan kadang-kadang mengimplementasikan) kelas wrapper untuk merangkum fungsionalitas logging dan membuatnya lebih mudah, meskipun tidak mudah, untuk mengubah cara penebangan bekerja di masa depan dengan perubahan minimal ; kode memanggil pembungkus, pembungkus meneruskan panggilan ke kerangka kerja logging du jour .

Mengingat bahwa ada contoh yang lebih rumit dengan perpustakaan lain, apakah saya over-engineering atau ini tindakan pencegahan yang bijaksana dalam banyak kasus?

EDIT: Lebih banyak pertimbangan - menggunakan injeksi dependensi dan uji ganda secara praktis mengharuskan kita abstrak sebagian besar API ("Saya ingin memeriksa kode saya mengeksekusi dan memperbarui statusnya, tetapi tidak menulis komentar log / mengakses database nyata"). Bukankah ini penentu?


3
log4XYZ adalah merek dagang yang kuat. API-nya akan berubah tidak lebih cepat daripada ketika API untuk daftar tertaut akan berubah. Keduanya merupakan masalah yang sudah lama terpecahkan sekarang.
Pekerjaan

1
Duplikat tepat dari pertanyaan SO ini: stackoverflow.com/questions/1916030/…
Michael Borgwardt

1
Jika Anda hanya menggunakannya secara internal, apakah Anda membungkus atau tidak hanyalah pertukaran antara pekerjaan yang diketahui sekarang dan pekerjaan yang mungkin nanti. Panggilan penilaian. Tetapi sesuatu yang tampaknya diabaikan oleh responden lain adalah apakah itu ketergantungan API atau ketergantungan implementasi . Dengan kata lain, apakah Anda membocorkan kelas dari API pihak ketiga ini melalui API publik Anda sendiri, dan mengeksposnya kepada pengguna? Dalam hal ini bukan lagi masalah sederhana dari kerja keras untuk pindah ke perpustakaan yang berbeda, masalahnya adalah sekarang tidak mungkin tanpa merusak API Anda sendiri. Ini sangat buruk!
Elias Vasylenko

1
Untuk referensi lebih lanjut: Pola ini disebut arsitektur bawang di mana infrastruktur eksternal (Anda menyebutnya lib eksternal) disembunyikan di belakang sebuah antarmuka
k3b

Jawaban:


42

Jika Anda hanya menggunakan sebagian kecil dari API pihak ketiga, masuk akal untuk menulis pembungkus - ini membantu enkapsulasi dan penyembunyian informasi, memastikan Anda tidak memaparkan API yang mungkin besar ke kode Anda sendiri. Ini juga dapat membantu memastikan bahwa setiap fungsionalitas yang tidak ingin Anda gunakan "tersembunyi".

Alasan bagus lainnya untuk pembungkus adalah jika Anda berharap untuk mengubah perpustakaan pihak ketiga. Jika ini adalah infrastruktur yang Anda tahu tidak akan berubah, jangan tulis pembungkus untuk itu.


Poin yang bagus, tetapi kami diajarkan bahwa kode yang digabungkan dengan erat adalah buruk, karena banyak alasan yang dipahami dengan baik (lebih sulit untuk diuji, lebih sulit untuk refactor, dll). Alternatif kata-kata dari pertanyaan adalah "jika kopling buruk, mengapa boleh berpasangan dengan API?"
lotsoffreetime

7
@lotsoffreetime Anda tidak dapat menghindari sambungan ke API. Karena itu, lebih baik memasangkan ke API Anda sendiri. Dengan begitu, Anda dapat mengubah perpustakaan dan umumnya tidak perlu mengubah API yang disediakan oleh pembungkus.
George Marian

@ george-marian Jika saya tidak bisa menghindari menggunakan API yang diberikan, saya pasti bisa meminimalkan titik sentuh. Pertanyaannya adalah, haruskah saya mencoba melakukan ini sepanjang waktu atau apakah itu berlebihan?
lotsoffreetime

2
@lotsoffreetime Itu adalah pertanyaan yang sulit dijawab. Saya telah memperluas jawaban saya untuk tujuan itu. (Pada dasarnya, ini tergantung pada banyak hal.)
George Marian

2
@ lotsoffreetime: jika Anda memiliki banyak waktu luang, maka Anda dapat melakukan keduanya. Tapi saya akan merekomendasikan untuk tidak menulis bungkus API, kecuali dalam kondisi ini: 1) API asli adalah tingkat yang sangat rendah, sehingga Anda menulis API tingkat yang lebih tinggi agar sesuai dengan kebutuhan spesifik proyek Anda, atau 2) Anda memiliki rencana di dalam waktu dekat untuk beralih perpustakaan, Anda menggunakan perpustakaan saat ini hanya sebagai batu loncatan saat mencari yang lebih baik.
Lie Ryan

28

Tanpa mengetahui fitur baru apa yang akan dimiliki oleh pencatat masa depan yang ditingkatkan ini, bagaimana Anda akan menulis bungkusnya? Pilihan paling logis adalah membuat wrapper Anda meng-instantiate semacam kelas logger, dan memiliki metode seperti ->info()atau ->warn(). Dengan kata lain, pada dasarnya identik dengan API Anda saat ini.

Daripada kode masa depan-bukti bahwa saya mungkin tidak perlu mengubah, atau yang mungkin memerlukan penulisan ulang yang tidak dapat dihindari, saya lebih memilih kode "bukti masa lalu". Artinya, pada kesempatan langka ketika saya secara signifikan mengubah komponen, itulah saat saya menulis bungkus agar kompatibel dengan kode terakhir. Namun, kode baru apa pun menggunakan API baru, dan saya refactor kode lama untuk menggunakannya setiap kali saya membuat perubahan pada file yang sama, atau sesuai jadwal. Setelah beberapa bulan, saya dapat menghapus bungkusnya, dan perubahannya bertahap dan kuat.

Dengan kata lain, pembungkus benar-benar hanya masuk akal ketika Anda sudah tahu semua API yang perlu Anda bungkus. Contoh yang bagus adalah jika aplikasi Anda saat ini perlu mendukung banyak driver database, sistem operasi, atau versi PHP yang berbeda.


"... pembungkus benar-benar masuk akal ketika Anda sudah tahu semua API yang perlu Anda bungkus." Ini akan benar jika saya mencocokkan API di bungkus; mungkin saya harus menggunakan istilah "enkapsulasi" lebih kuat daripada bungkus. Saya akan abstrak panggilan API ini untuk "log teks ini entah bagaimana" daripada "panggil foo :: log () dengan parameter ini".
lotsoffreetime

"Tanpa mengetahui fitur baru yang luar biasa apa yang dimiliki oleh pencatat masa depan yang ditingkatkan ini, bagaimana Anda akan menulis bungkusnya?" @ kevin-cline di bawah menyebutkan logger masa depan dengan kinerja yang lebih baik, daripada fitur yang lebih baru. Dalam hal ini, tidak ada API baru untuk dibungkus, hanya metode pabrik yang berbeda.
lotsoffreetime

27

Dengan membungkus perpustakaan pihak ketiga Anda menambahkan lapisan abstraksi tambahan di atasnya. Ini memiliki beberapa keunggulan:

  • Basis kode Anda menjadi lebih fleksibel terhadap perubahan

    Jika Anda perlu mengganti pustaka dengan pustaka lain, Anda hanya perlu mengubah implementasi Anda di pembungkus Anda - di satu tempat . Anda dapat mengubah implementasi pembungkus dan tidak perlu mengubah apa pun tentang hal lain, dengan kata lain Anda memiliki sistem yang digabungkan secara longgar. Kalau tidak, Anda harus melalui seluruh basis kode Anda dan membuat modifikasi di mana-mana - yang jelas bukan yang Anda inginkan.

  • Anda dapat menentukan API pembungkus secara independen dari API perpustakaan

    Pustaka yang berbeda dapat memiliki API yang sangat berbeda dan pada saat yang sama tidak ada pustaka yang tepat seperti yang Anda butuhkan. Bagaimana jika beberapa perpustakaan membutuhkan token untuk diteruskan bersama dengan setiap panggilan? Anda dapat melewatkan token di aplikasi Anda di mana pun Anda perlu menggunakan perpustakaan atau Anda dapat menyimpannya di tempat yang lebih terpusat, tetapi dalam hal apa pun Anda memerlukan token tersebut. Kelas wrapper Anda membuat semuanya menjadi sederhana lagi - karena Anda bisa menyimpan token di dalam kelas wrapper Anda, jangan pernah memaparkannya ke komponen apa pun di dalam aplikasi Anda dan sepenuhnya abstrak jauh dari kebutuhan untuk itu. Keuntungan besar jika Anda pernah menggunakan perpustakaan yang tidak menekankan desain API yang baik.

  • Pengujian unit jauh lebih sederhana

    Tes unit seharusnya hanya menguji satu hal. Jika Anda ingin menguji unit kelas Anda harus mengejek dependensinya. Ini menjadi lebih penting jika kelas itu melakukan panggilan jaringan atau mengakses sumber daya lain di luar perangkat lunak Anda. Dengan membungkus pustaka pihak ketiga, mudah untuk mengejek panggilan itu dan mengembalikan data pengujian atau apa pun yang dibutuhkan pengujian unit. Jika Anda tidak memiliki lapisan abstraksi seperti itu, menjadi jauh lebih sulit untuk melakukan ini - dan sebagian besar waktu ini menghasilkan banyak kode jelek.

  • Anda membuat sistem yang digabungkan secara longgar

    Perubahan pada pembungkus Anda tidak berpengaruh pada bagian lain dari perangkat lunak Anda - setidaknya selama Anda tidak mengubah perilaku pembungkus Anda. Dengan memperkenalkan lapisan abstraksi seperti pembungkus ini, Anda dapat menyederhanakan panggilan ke perpustakaan dan dan hampir sepenuhnya menghapus ketergantungan aplikasi Anda di perpustakaan itu. Perangkat lunak Anda hanya akan menggunakan pembungkus dan itu tidak akan membuat perbedaan bagaimana pembungkus diimplementasikan atau bagaimana ia melakukan apa yang dilakukannya.


Contoh Praktis

Mari jujur. Orang-orang dapat berdebat tentang kelebihan dan kekurangan dari hal seperti ini selama berjam-jam - itulah sebabnya saya lebih suka hanya menunjukkan contoh kepada Anda.

Katakanlah Anda memiliki beberapa jenis aplikasi Android dan Anda perlu mengunduh gambar. Ada banyak perpustakaan di luar sana yang membuat memuat dan menyimpan gambar dengan mudah, misalnya Picasso atau Universal Image Loader .

Kita sekarang dapat mendefinisikan antarmuka yang akan kita gunakan untuk membungkus perpustakaan mana pun yang akhirnya kita gunakan:

public interface ImageService {
    Bitmap load(String url);
}

Ini adalah antarmuka yang sekarang dapat kita gunakan di seluruh aplikasi kapan pun kita perlu memuat gambar. Kami dapat membuat implementasi antarmuka ini dan menggunakan injeksi ketergantungan untuk menyuntikkan contoh implementasi di mana pun kami menggunakan ImageService.

Katakanlah kita awalnya memutuskan untuk menggunakan Picasso. Kami sekarang dapat menulis implementasi ImageServiceyang menggunakan Picasso secara internal:

public class PicassoImageService implements ImageService {

    private final Context mContext;

    public PicassoImageService(Context context) {
        mContext = context;
    }

    @Override
    public Bitmap load(String url) {
        return Picasso.with(mContext).load(url).get();
    }
}

Cukup lurus ke depan jika Anda bertanya kepada saya. Membungkus perpustakaan tidak harus rumit untuk menjadi berguna. Antarmuka dan implementasinya memiliki kurang dari 25 baris kode gabungan sehingga hampir tidak ada upaya untuk membuat ini, tapi kami sudah mendapatkan sesuatu dengan melakukan ini. Lihat Contextbidang dalam implementasinya? Kerangka kerja injeksi ketergantungan pilihan Anda sudah akan siap menyuntikkan dependensi itu sebelum kami menggunakan ImageServiceaplikasi kami , sekarang aplikasi Anda tidak perlu peduli tentang bagaimana gambar diunduh dan dependensi apa pun yang mungkin dimiliki perpustakaan. Semua aplikasi Anda lihat adalah ImageServicedan ketika itu membutuhkan gambar yang dipanggil load()dengan url - sederhana & mudah.

Namun manfaat nyata datang ketika kita mulai mengubah banyak hal. Bayangkan kita sekarang perlu mengganti Picasso dengan Universal Image Loader karena Picasso tidak mendukung beberapa fitur yang benar-benar kita butuhkan saat ini. Apakah kita sekarang harus menyisir basis kode kita dan dan dengan teliti mengganti semua panggilan ke Picasso dan kemudian menangani puluhan kesalahan kompilasi karena kita lupa beberapa panggilan Picasso? Tidak. Yang perlu kita lakukan adalah membuat implementasi baru ImageServicedan memberi tahu kerangka kerja injeksi ketergantungan kita untuk menggunakan implementasi ini mulai sekarang:

public class UniversalImageLoaderImageService implements ImageService {

    private final ImageLoader mImageLoader;

    public UniversalImageLoaderImageService(Context context) {

        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .build();

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .defaultDisplayImageOptions(defaultOptions)
                .build();

        mImageLoader = ImageLoader.getInstance();
        mImageLoader.init(config);
    }

    @Override
    public Bitmap load(String url) {
        return mImageLoader.loadImageSync(url);
    }
}

Seperti yang Anda lihat implementasi mungkin sangat berbeda, tetapi itu tidak masalah. Kami tidak perlu mengubah satu baris kode pun di aplikasi kami. Kami menggunakan pustaka yang sangat berbeda yang mungkin memiliki fitur yang sama sekali berbeda atau mungkin digunakan sangat berbeda tetapi aplikasi kami tidak peduli. Sama seperti sebelumnya aplikasi kami hanya melihat ImageServiceantarmuka dengan load()metodenya dan bagaimanapun metode ini diterapkan tidak masalah lagi.

Setidaknya bagi saya ini semua sudah terdengar cukup bagus, tapi tunggu! Masih ada lagi. Bayangkan Anda sedang menulis unit test untuk kelas yang sedang Anda kerjakan dan kelas ini menggunakan ImageService. Tentu saja Anda tidak dapat membiarkan unit test Anda melakukan panggilan jaringan ke beberapa sumber daya yang terletak di beberapa server lain, tetapi karena Anda sekarang menggunakan ImageServiceAnda dapat dengan mudah membiarkan load()kembali statis yang Bitmapdigunakan untuk unit test dengan menerapkan mocked ImageService:

public class MockImageService implements ImageService {

    private final Bitmap mMockBitmap;

    public MockImageService(Bitmap mockBitmap) {
        mMockBitmap = mockBitmap;
    }

    @Override
    public Bitmap load(String url) {
        return mMockBitmap;
    }
}

Untuk meringkas dengan membungkus perpustakaan pihak ketiga, basis kode Anda menjadi lebih fleksibel terhadap perubahan, secara keseluruhan lebih sederhana, lebih mudah untuk diuji dan Anda mengurangi penggabungan komponen yang berbeda dalam perangkat lunak Anda - semua hal yang menjadi semakin penting saat Anda memelihara perangkat lunak.


1
Ini berlaku juga untuk API yang tidak stabil. Kode kami tidak berubah di 1000 tempat hanya karena pustaka yang mendasarinya berubah. Jawaban yang sangat bagus
RubberDuck

Jawabannya sangat singkat dan jelas. Saya melakukan pekerjaan front-end di web. Jumlah perubahan dalam lanskap itu gila. Fakta bahwa orang "berpikir" tidak akan ada perubahan tidak berarti tidak akan ada perubahan. Saya melihat menyebutkan YAGNI. Saya ingin menambahkan akronim baru, YDKYAGNI, Anda tidak tahu Anda tidak akan membutuhkannya. Apalagi dengan implementasi terkait web. Sebagai aturan saya selalu membungkus perpustakaan yang hanya memperlihatkan API kecil (seperti select2). Pustaka yang lebih besar memengaruhi arsitektur Anda dan membungkusnya berarti Anda mengharapkan arsitektur Anda berubah, mungkin saja, tetapi kecil kemungkinannya untuk melakukannya.
Byebye

Jawaban Anda sangat membantu dan menyajikan konsep dengan contoh membuat konsep itu semakin jelas.
Anil Gorthy

24

Saya pikir membungkus perpustakaan pihak ketiga hari ini kalau-kalau ada sesuatu yang lebih baik datang besok adalah pelanggaran yang sangat boros dari YAGNI. Jika Anda berulang kali memanggil kode pihak ketiga dengan cara yang khas untuk aplikasi Anda, Anda akan (harus) mengubah panggilan itu menjadi kelas pembungkus untuk menghilangkan pengulangan. Kalau tidak, Anda sepenuhnya menggunakan API perpustakaan dan pembungkus apa pun akan terlihat seperti perpustakaan itu sendiri.

Sekarang anggaplah perpustakaan baru muncul dengan kinerja superior atau apa pun. Dalam kasus pertama, Anda hanya menulis ulang pembungkus untuk API baru. Tidak masalah.

Dalam kasus kedua, Anda membuat pembungkus mengadaptasi antarmuka lama untuk mendorong perpustakaan baru. Sedikit lebih banyak pekerjaan, tetapi tidak ada masalah, dan tidak ada lebih banyak pekerjaan daripada yang akan Anda lakukan jika Anda telah menulis bungkus sebelumnya.


4
Saya tidak berpikir bahwa YAGNI berlaku dalam situasi ini. Ini bukan tentang membangun fungsionalitas jika Anda mungkin membutuhkannya di masa depan. Ini tentang membangun fleksibilitas ke dalam arsitektur. Jika fleksibilitas itu tidak perlu, maka, ya, YAGNI berlaku. Namun, tekad itu cenderung dibuat di masa depan ketika membuat perubahan kemungkinan akan menyakitkan.
George Marian

7
@ George Marian: masalahnya adalah 95% dari waktu, Anda tidak akan pernah membutuhkan fleksibilitas untuk berubah. Jika Anda perlu beralih ke perpustakaan baru di masa mendatang yang memiliki kinerja unggul, maka itu seharusnya cukup sepele untuk mencari / mengganti panggilan atau menulis pembungkus saat Anda membutuhkannya. Di sisi lain, jika perpustakaan baru Anda datang dengan fungsi yang berbeda, pembungkus sekarang menjadi penghalang karena sekarang Anda memiliki dua masalah: porting kode lama untuk mengeksploitasi fitur baru dan memelihara pembungkus.
Lie Ryan

3
@lotsoffreetime: Tujuan dari "desain yang baik" adalah untuk meminimalkan total biaya aplikasi selama masa pakainya. Menambahkan lapisan tipuan untuk perubahan masa depan yang dibayangkan adalah asuransi yang sangat mahal. Saya belum pernah melihat orang yang menyadari penghematan dari pendekatan itu. Itu hanya menciptakan pekerjaan sepele untuk programmer yang waktunya akan jauh lebih baik dihabiskan untuk persyaratan khusus pelanggan. Sebagian besar waktu, jika Anda menulis kode yang tidak spesifik untuk pelanggan Anda, Anda membuang-buang waktu dan uang.
kevin cline

1
@ George: jika perubahan ini menyakitkan, saya pikir itu adalah proses bau. Di Jawa, saya akan membuat kelas baru dengan nama yang sama dengan kelas lama, tetapi dalam paket yang berbeda, ubah semua kemunculan nama paket lama, dan jalankan kembali tes otomatis.
kevin cline

1
@ kevin Itu lebih banyak pekerjaan, dan dengan demikian membawa lebih banyak risiko, daripada sekadar memperbarui pembungkus dan menjalankan tes.
George Marian

9

Alasan dasar untuk menulis pembungkus di sekitar perpustakaan pihak ketiga adalah agar Anda bisa menukar perpustakaan pihak ketiga itu tanpa mengubah kode yang menggunakannya. Anda tidak dapat menghindari penggabungan ke sesuatu, jadi argumennya adalah bahwa lebih baik memasangkan ke API yang telah Anda tulis.

Apakah ini sepadan dengan usaha adalah cerita yang berbeda. Debat itu kemungkinan akan berlanjut untuk waktu yang lama.

Untuk proyek-proyek kecil, di mana kemungkinan perubahan seperti itu diperlukan rendah, itu mungkin upaya yang tidak perlu. Untuk proyek yang lebih besar, fleksibilitas itu mungkin lebih besar daripada upaya ekstra untuk membungkus perpustakaan. Namun, sulit untuk mengetahui apakah itu yang terjadi sebelumnya.

Cara lain untuk melihatnya adalah prinsip dasar mengabstraksi apa yang mungkin berubah. Jadi, jika perpustakaan pihak ketiga sudah mapan dan tidak mungkin diubah, mungkin tidak apa-apa untuk membungkusnya. Namun, jika perpustakaan pihak ketiga relatif baru, ada kemungkinan lebih besar bahwa perpustakaan itu perlu diganti. Yang mengatakan, pengembangan perpustakaan yang mapan telah ditinggalkan banyak kali. Jadi, ini bukan pertanyaan yang mudah dijawab.


Dalam kasus pengujian unit di mana bisa menyuntikkan tiruan API berfungsi untuk meminimalkan unit yang diuji, "perubahan potensial" bukanlah faktor. Karena itu, ini masih jawaban favorit saya karena paling dekat dengan cara saya berpikir. Apa yang akan dikatakan Paman Bob? :)
lotsoffreetime

Juga, proyek-proyek kecil (tidak ada tim, spek dasar, dll) memiliki aturan sendiri di mana Anda dapat melanggar praktik yang baik seperti ini dan lolos begitu saja, sampai tingkat tertentu. Tapi itu pertanyaan yang berbeda ...
lotoffreetime

1

Selain apa yang sudah dikatakan @Oded , saya hanya ingin menambahkan jawaban ini untuk tujuan khusus pencatatan.


Saya selalu memiliki antarmuka untuk logging, tetapi saya belum pernah mengganti log4fookerangka kerja.

Hanya perlu setengah jam untuk menyediakan antarmuka dan menulis bungkusnya, jadi saya kira Anda tidak membuang waktu terlalu banyak jika ternyata tidak perlu.

Ini adalah kasus khusus YAGNI. Meskipun saya tidak membutuhkannya, tidak butuh banyak waktu dan saya merasa lebih aman. Jika hari pertukaran logger benar-benar datang, saya akan senang saya berinvestasi setengah jam karena itu akan menyelamatkan saya lebih dari satu hari bertukar panggilan dalam proyek dunia nyata. Dan saya tidak pernah menulis atau melihat unit test untuk logging (terlepas dari tes untuk implementasi logger itu sendiri), jadi harapkan cacat tanpa pembungkus.


Saya tidak berharap untuk mengubah log4foo, tetapi ini dikenal luas dan berfungsi sebagai contoh. Menarik juga bagaimana kedua jawaban sejauh ini saling melengkapi - "jangan selalu membungkus"; "Bungkus berjaga-jaga".
lotsoffreetime

@ Falcon: apakah Anda membungkus semuanya? ORM, antarmuka log, kelas bahasa inti? Lagi pula, orang tidak pernah tahu kapan HashMap yang lebih baik mungkin dibutuhkan.
kevin cline

1

Saya sedang berurusan dengan masalah ini pada proyek yang sedang saya kerjakan. Tetapi dalam kasus saya perpustakaan adalah untuk grafis dan dengan demikian saya dapat membatasi itu digunakan untuk sejumlah kecil kelas yang berurusan dengan grafik, dibandingkan menaburkannya di seluruh proyek. Dengan demikian, cukup mudah untuk beralih API nanti jika perlu; dalam kasus seorang penebang masalah menjadi jauh lebih rumit.

Jadi saya akan mengatakan keputusan itu banyak berkaitan dengan apa yang sebenarnya dilakukan perpustakaan pihak ketiga dan seberapa banyak rasa sakit yang terkait dengan mengubahnya. Jika mengubah semua panggilan API akan mudah, maka itu mungkin tidak layak dilakukan. Namun jika mengubah perpustakaan nanti akan sangat sulit maka saya mungkin akan membungkusnya sekarang.


Di luar itu, jawaban lain telah mencakup pertanyaan utama dengan sangat baik sehingga saya hanya ingin fokus pada tambahan terakhir itu, tentang injeksi ketergantungan dan benda tiruan. Tentu saja ini tergantung pada bagaimana tepatnya kerangka logging Anda bekerja, tetapi dalam kebanyakan kasus tidak ada yang tidak memerlukan pembungkus (meskipun mungkin akan mendapat manfaat dari satu). Buat saja API untuk objek tiruan Anda persis sama dengan pustaka pihak ke-3 dan kemudian Anda dapat dengan mudah bertukar di objek tiruan untuk pengujian.

Faktor utama di sini adalah apakah perpustakaan pihak ke-3 bahkan diimplementasikan melalui injeksi dependensi (atau pelacak layanan atau beberapa pola yang longgar seperti itu). Jika fungsi pustaka diakses melalui metode statis atau singleton atau sesuatu, maka Anda harus membungkusnya dalam objek yang dapat Anda gunakan dengan injeksi dependensi.


1

Saya sangat di kamp pembungkus dan tidak bisa mengganti perpustakaan pihak ketiga dengan prioritas terbesar (meskipun itu adalah bonus). Alasan utama saya bahwa nikmat pembungkus sederhana

Perpustakaan pihak ketiga tidak dirancang untuk kebutuhan spesifik kami.

Dan ini memanifestasikan dirinya, biasanya, dalam bentuk satu kapal duplikasi kode, seperti pengembang menulis 8 baris kode hanya untuk membuat QButtondan gaya itu cara itu harus mencari aplikasi, hanya untuk desainer yang ingin tidak hanya melihat tetapi juga fungsi tombol untuk berubah sepenuhnya untuk seluruh perangkat lunak yang pada akhirnya mengharuskan kembali dan menulis ulang ribuan baris kode, atau menemukan bahwa memodernisasi pipa rendering memerlukan penulisan ulang epik karena basis kode menaburkan ad-hoc tingkat rendah yang diperbaiki pipeline kode OpenGL di semua tempat alih-alih memusatkan desain penyaji waktu nyata dan meninggalkan penggunaan OGL hanya untuk implementasinya.

Desain ini tidak disesuaikan dengan kebutuhan desain khusus kami. Mereka cenderung menawarkan superset besar-besaran dari apa yang sebenarnya dibutuhkan (dan apa yang bukan bagian dari desain sama pentingnya, jika tidak lebih dari apa yang ada), dan antarmuka mereka tidak dirancang untuk secara khusus melayani kebutuhan kita dalam "tingkat tinggi" pikir = satu permintaan "semacam cara yang menghalangi kita dari semua kontrol desain pusat jika kita menggunakannya secara langsung. Jika pengembang akhirnya menulis kode tingkat jauh lebih rendah dari yang seharusnya diperlukan untuk mengekspresikan apa yang mereka butuhkan, mereka kadang-kadang bisa berakhir dengan membungkusnya sendiri dengan cara ad-hoc yang membuatnya jadi Anda berakhir dengan lusinan yang ditulis dengan tergesa-gesa dan kasar- pembungkus yang dirancang dan didokumentasikan, bukan pembungkus yang dirancang dengan baik dan terdokumentasi dengan baik.

Tentu saja saya akan menerapkan pengecualian yang kuat untuk perpustakaan di mana pembungkusnya adalah terjemahan satu-ke-satu dari apa yang ditawarkan API pihak ketiga. Dalam hal ini mungkin tidak ada desain tingkat lebih tinggi untuk dicari yang lebih langsung mengungkapkan persyaratan bisnis dan desain (seperti itu mungkin terjadi untuk sesuatu yang lebih menyerupai perpustakaan "utilitas"). Tetapi jika ada desain yang jauh lebih tersesuaikan tersedia yang jauh lebih langsung mengekspresikan kebutuhan kita, maka saya sangat berada di kamp pembungkus, sama seperti saya sangat mendukung penggunaan fungsi tingkat yang lebih tinggi dan menggunakannya kembali dengan menguraikan kode perakitan seluruh tempat.

Anehnya saya telah berbenturan dengan pengembang dengan cara-cara di mana mereka tampak sangat tidak percaya dan pesimis terhadap kemampuan kita merancang, katakanlah, fungsi untuk membuat tombol dan mengembalikannya sehingga mereka lebih suka menulis 8 baris kode tingkat lebih rendah yang berfokus pada mikroskopis rincian pembuatan tombol (yang akhirnya perlu diubah berulang kali di masa mendatang) selama mendesain dan menggunakan fungsi tersebut. Saya bahkan tidak melihat tujuan dari kita mencoba merancang apa pun di tempat pertama jika kita tidak bisa mempercayai diri kita untuk merancang pembungkus semacam ini dengan cara yang masuk akal.

Dengan kata lain saya melihat perpustakaan pihak ketiga sebagai cara untuk berpotensi menghemat waktu yang sangat besar dalam implementasi, bukan sebagai pengganti untuk merancang sistem.


0

Gagasan saya tentang Perpustakaan Pihak ketiga:

Ada beberapa diskusi baru-baru ini di komunitas iOS tentang pro dan kontra (OK, sebagian besar kontra) menggunakan dependensi pihak ketiga. Banyak argumen yang saya lihat agak umum - mengelompokkan semua perpustakaan pihak ketiga ke dalam satu keranjang. Seperti kebanyakan hal, tidak sesederhana itu. Jadi, mari kita fokus pada satu kasus saja

Haruskah kita menghindari menggunakan perpustakaan UI pihak ketiga?

Alasan untuk mempertimbangkan perpustakaan pihak ketiga:

Tampaknya ada dua alasan utama pengembang mempertimbangkan untuk menggunakan perpustakaan pihak ketiga:

  1. Kurangnya keterampilan atau pengetahuan. Katakanlah, Anda sedang mengerjakan aplikasi berbagi foto. Anda tidak memulai dengan menggulung crypto Anda sendiri.
  2. Kurang waktu atau minat untuk membangun sesuatu. Kecuali jika Anda memiliki waktu yang tidak terbatas (yang belum dimiliki manusia) Anda harus memprioritaskan.

Sebagian besar perpustakaan UI ( tidak semua! ) Cenderung masuk ke dalam kategori kedua. Benda ini bukan ilmu roket, tetapi butuh waktu untuk membangunnya dengan benar.

Jika ini adalah fungsi bisnis inti - lakukan sendiri, apa pun itu.

Ada cukup banyak dua jenis kontrol / tampilan:

  1. Generik, memungkinkan Anda untuk menggunakannya dalam berbagai konteks yang berbeda yang bahkan tidak terpikirkan oleh pembuatnya, misalnya UICollectionViewdari UIKit.
  2. Spesifik, dirancang untuk kasus penggunaan tunggal, mis UIPickerView. Sebagian besar perpustakaan pihak ketiga cenderung masuk dalam kategori kedua. Terlebih lagi, mereka sering diekstraksi dari basis kode yang sudah ada yang dioptimalkan.

Asumsi awal tidak diketahui

Banyak pengembang melakukan review kode dari kode internal mereka tetapi mungkin mengambil kualitas kode sumber pihak ketiga begitu saja. Layak untuk menghabiskan sedikit waktu hanya menjelajahi kode perpustakaan. Anda mungkin pada akhirnya terkejut melihat beberapa bendera merah, misalnya swizzling digunakan di tempat yang tidak diperlukan.

Seringkali belajar ide itu lebih bermanfaat daripada mendapatkan kode yang dihasilkan itu sendiri.

Anda tidak bisa menyembunyikannya

Karena cara UIKit dirancang, Anda kemungkinan besar tidak akan dapat menyembunyikan perpustakaan UI pihak ketiga, misalnya di belakang adaptor. Perpustakaan akan terjalin dengan kode UI Anda menjadi de-facto proyek Anda.

Biaya waktu masa depan

UIKit berubah dengan setiap rilis iOS. Segalanya akan pecah. Ketergantungan pihak ketiga Anda tidak akan bebas perawatan seperti yang Anda harapkan.

Kesimpulan:

Dari pengalaman pribadi saya, sebagian besar penggunaan kode UI pihak ketiga bermula untuk bertukar fleksibilitas yang lebih kecil untuk mendapatkan waktu tertentu.

Kami menggunakan kode yang sudah jadi untuk mengirimkan rilis kami saat ini lebih cepat. Cepat atau lambat, kami mencapai batas perpustakaan dan berdiri di depan keputusan yang sulit: apa yang harus dilakukan selanjutnya?


0

Menggunakan perpustakaan secara langsung lebih ramah bagi tim pengembang. Ketika pengembang baru bergabung, ia mungkin sepenuhnya berpengalaman dengan semua kerangka kerja yang digunakan namun tidak akan dapat berkontribusi secara produktif sebelum mempelajari API yang dikembangkan di rumah Anda. Ketika pengembang yang lebih muda mencoba untuk maju dalam grup Anda, ia akan dipaksa untuk mempelajari API spesifik Anda yang tidak ada di tempat lain, alih-alih memperoleh kompetensi generik yang lebih berguna. Jika seseorang mengetahui fitur atau kemungkinan yang berguna dari API asli, mungkin tidak dapat menjangkau lapisan yang ditulis oleh seseorang yang tidak menyadarinya. Jika seseorang akan mendapatkan tugas pemrograman sambil mencari pekerjaan, mungkin tidak dapat mendemonstrasikan hal-hal dasar yang ia gunakan berkali-kali, hanya karena selama ini ia mengakses fungsionalitas yang dibutuhkan melalui pembungkus Anda.

Saya pikir masalah ini mungkin lebih penting daripada kemungkinan jauh menggunakan perpustakaan yang sama sekali berbeda nanti. Satu-satunya kasus saya akan menggunakan pembungkus adalah ketika migrasi ke implementasi lain pasti direncanakan atau API yang dibungkus tidak cukup beku dan terus berubah.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.