Program-driven programming: kapan itu layak?

19

Ok, saya tahu judul pertanyaan ini hampir identik dengan Kapan saya harus menggunakan pemrograman berbasis acara? tetapi jawaban dari pertanyaan tersebut tidak membantu saya dalam memutuskan apakah saya harus menggunakan acara dalam kasus tertentu yang saya hadapi.

Saya sedang mengembangkan aplikasi kecil. Ini adalah aplikasi sederhana, dan sebagian besar fungsinya adalah CRUD dasar.

Setelah peristiwa tertentu (saat memodifikasi data tertentu) aplikasi harus menulis salinan lokal dari data tersebut dalam file. Saya tidak yakin tentang apa cara terbaik untuk mengimplementasikan ini. Saya bisa:

  • Kejadian kebakaran ketika data diubah dan mengikat respons (menghasilkan file) untuk peristiwa tersebut. Atau, terapkan pola pengamat. Kelihatannya seperti kompleksitas yang tidak perlu.
  • Panggil kode penghasil file langsung dari kode yang memodifikasi data. Jauh lebih sederhana, tetapi tampaknya salah bahwa ketergantungan harus seperti ini, yaitu, tampaknya salah bahwa fungsionalitas inti dari aplikasi (kode yang memodifikasi data) harus digabungkan dengan tambahan (kode yang menghasilkan file cadangan). Saya tahu, bagaimanapun, bahwa aplikasi ini tidak akan berkembang ke titik di mana kopling itu menimbulkan masalah.

Apa pendekatan terbaik dalam kasus ini?

abl
sumber
2
Saya akan mengatakan jangan mengimplementasikan apa pun sendiri - cukup gunakan bus acara yang ada. Ini akan membuat hidup lebih sederhana ...
Boris the Spider
Pemrograman yang digerakkan oleh peristiwa pada dasarnya asinkron. Peristiwa mungkin atau mungkin tidak terjadi, dalam urutan yang Anda inginkan atau mungkin dalam urutan lain atau tidak sama sekali. Jika Anda dapat mengatasi kompleksitas ekstra itu, lakukan saja.
Pieter B
Event-driven biasanya berarti bahwa kode Anda disediakan sebagai panggilan balik dan ini dipanggil dari tempat lain dengan cara yang tidak dapat Anda prediksi. Deskripsi Anda lebih terdengar seperti itu ketika sesuatu yang spesifik terjadi dalam kode Anda, Anda perlu melakukan lebih dari yang dibutuhkan oleh implementasi yang naif. Hanya kode panggilan tambahan masuk
Thorbjørn Ravn Andersen
Ada adalah perbedaan antara event-driven dan event-based. Lihat misalnya episode .NET Rocks podcast episode 355 yang sangat menggugah perhatian bersama Ted Faison, Ted Faison Membawa Peristiwa hingga Batas! ( URL unduhan langsung ) dan buku Pemrograman berbasis acara: membuat acara hingga batasnya .
Peter Mortensen
Wawancara dengan Ted Faison dimulai pada 13 menit 10 detik.
Peter Mortensen

Jawaban:

31

Ikuti prinsip KISS: Keep It Simple, Bodoh, atau prinsip YAGNI: Anda Tidak Akan Membutuhkannya.

Anda dapat menulis kode seperti:

void updateSpecialData() {
    // do the update.
    backupData();
}

Atau Anda dapat menulis kode seperti:

void updateSpecialData() {
     // do the update.
     emit SpecialDataUpdated();
}

void SpecialDataUpdatedHandler() {
     backupData();
}

void configureEventHandlers() {
     connect(SpecialDataUpdate, SpecialDataUpdatedHandler);
}

Dengan tidak adanya alasan kuat untuk melakukan sebaliknya, ikuti rute yang lebih sederhana. Teknik seperti penanganan acara memang kuat, tetapi mereka meningkatkan kompleksitas kode Anda. Itu membutuhkan lebih banyak kode untuk bekerja, dan itu membuat apa yang terjadi dalam kode Anda lebih sulit untuk diikuti.

Peristiwa sangat penting dalam situasi yang benar (bayangkan mencoba melakukan pemrograman UI tanpa peristiwa!) Tetapi jangan menggunakannya saat Anda dapat KISS atau YAGNI sebagai gantinya.

Winston Ewert
sumber
Saya secara khusus menyukai fakta bahwa Anda menyebutkan bahwa memecat peristiwa ketika data diubah tidak sepele.
NoChance
13

Contoh yang Anda gambarkan dari data sederhana, di mana modifikasi memicu beberapa efek dapat dengan sempurna diimplementasikan dengan pola desain pengamat :

  • ini lebih mudah untuk diterapkan dan dipelihara daripada kode penuh event driven
  • hubungan antara subjek dan pengamat dapat bersifat abstrak, yang memfasilitasi pemisahan masalah.
  • ini ideal untuk hubungan satu ke banyak (subjek memiliki satu atau banyak pengamat).

Pendekatan event driven bernilai investasi untuk skenario yang lebih kompleks, ketika banyak interaksi yang berbeda dapat terjadi, dalam konteks banyak ke banyak, atau jika reaksi berantai dipertimbangkan (misalnya subjek menginformasikan pengamat, yang dalam beberapa kasus ingin memodifikasi subjek atau subjek lain)

Christophe
sumber
1
Saya bingung, bukankah pengamat hanya satu cara untuk mengimplementasikan acara?
svick
1
@vick saya tidak berpikir begitu. Dalam pemrograman berbasis peristiwa, Anda memiliki lingkaran utama yang memproses peristiwa dalam hubungan banyak ke banyak, dengan pengirim dan pengamat yang dipisahkan. Saya pikir pengamat dapat berkontribusi dengan memproses jenis peristiwa tertentu, tetapi Anda tidak dapat mencapai spektrum penuh EDP hanya dengan pengamat. Saya pikir kebingungan berasal dari fakta bahwa dalam perangkat lunak yang digerakkan oleh peristiwa, pengamat kadang-kadang diimplementasikan di atas pemrosesan acara (biasanya MVC dengan GUI)
Christophe
5

Seperti yang Anda katakan, acara adalah alat yang hebat untuk mengurangi sambungan antar kelas; jadi walaupun dapat melibatkan penulisan kode tambahan dalam beberapa bahasa tanpa dukungan bawaan untuk acara, ini mengurangi kompleksitas gambaran besar.

Acara bisa dibilang salah satu alat paling penting dalam OO (Menurut Alan Kay - Objek berkomunikasi dengan mengirim dan menerima pesan ). Jika Anda menggunakan bahasa yang memiliki dukungan bawaan untuk acara, atau memperlakukan fungsi sebagai warga negara kelas satu, maka menggunakannya adalah hal yang sulit.

Bahkan dalam bahasa tanpa dukungan bawaan, jumlah pelat untuk sesuatu seperti pola Observer cukup minim. Anda mungkin dapat menemukan perpustakaan acara generik yang layak di suatu tempat yang dapat Anda gunakan di semua aplikasi Anda untuk meminimalkan boilerplate. (Agregator acara umum atau mediator acara berguna di hampir semua jenis aplikasi).

Apakah ini berguna dalam aplikasi kecil? Saya akan mengatakan ya .

  • Menjaga kelas dipisahkan satu sama lain menjaga grafik ketergantungan kelas Anda bersih.
  • Kelas tanpa dependensi konkret dapat diuji secara terpisah tanpa mempertimbangkan kelas lain dalam tes.
  • Kelas tanpa ketergantungan konkret membutuhkan tes unit lebih sedikit untuk cakupan lengkap.

Jika Anda berpikir "Oh, tetapi itu benar-benar hanya aplikasi yang sangat kecil, itu tidak terlalu penting" , pertimbangkan:

  • Aplikasi kecil terkadang berakhir dengan digabungkan dengan aplikasi yang lebih besar nantinya.
  • Aplikasi kecil cenderung menyertakan setidaknya beberapa logika atau komponen yang nantinya perlu digunakan kembali dalam aplikasi lain.
  • Persyaratan untuk aplikasi kecil dapat berubah, mendorong perlunya refactor, yang lebih mudah ketika kode yang ada dipisahkan.
  • Fitur tambahan dapat ditambahkan kemudian, mendorong kebutuhan untuk memperluas kode yang ada, yang juga jauh lebih mudah ketika kode yang sudah ada dipisahkan.
  • Kode yang digabungkan secara longgar biasanya tidak membutuhkan waktu lebih lama untuk menulis daripada kode yang digabungkan secara ketat; tetapi kode yang dipasangkan dengan erat membutuhkan waktu lebih lama untuk melakukan refactor dan menguji daripada kode yang dipasangkan secara longgar.

Secara keseluruhan, ukuran aplikasi seharusnya tidak menjadi faktor penentu apakah akan mempertahankan kelas secara longgar; Prinsip SOLID tidak hanya untuk aplikasi besar, tetapi juga berlaku untuk perangkat lunak dan basis kode pada skala apa pun.

Faktanya, waktu yang dihemat dalam unit untuk menguji kelas yang longgar digabungkan secara terpisah harus melawan keseimbangan waktu tambahan yang dihabiskan untuk memisahkan kelas-kelas tersebut.

Ben Cottrell
sumber
2

Pola pengamat dapat diimplementasikan dengan cara yang jauh lebih kecil daripada yang dijelaskan oleh artikel Wikipedia (atau buku GOF), dengan asumsi bahasa pemrograman Anda mendukung sesuatu seperti "panggilan balik" atau "delegasi". Cukup kirimkan metode panggilan balik ke kode CRUD Anda (metode pengamat, yang bisa berupa metode "menulis-ke-file" umum, atau yang kosong). Alih-alih "event firing" panggil saja callback itu.

Kode yang dihasilkan hanya akan minimal lebih kompleks daripada memanggil kode penghasil file secara langsung, tetapi tanpa kelemahan dari kopling ketat dari komponen yang tidak terkait.

Itu akan membawa Anda "terbaik dari kedua dunia", tanpa mengorbankan decoupling untuk "YAGNI".

Doc Brown
sumber
Itu berfungsi pertama kali Doc, tetapi ketika acara perlu memicu hal kedua, kemungkinan kelas perlu dimodifikasi dengan melakukannya dengan cara ini. Jika Anda menggunakan pola pengamat, Anda bisa menambahkan perilaku baru sebanyak yang Anda inginkan tanpa membuka kelas asli cadangan untuk modifikasi.
RubberDuck
2
@RubberDuck: OP sedang mencari solusi "menghindari kompleksitas yang tidak perlu" - jika ada berbagai peristiwa / perilaku yang berbeda yang diperlukan, dia mungkin tidak akan menganggap pola pengamat sebagai terlalu kompleks. Jadi saya setuju dengan apa yang Anda katakan, ketika segalanya menjadi lebih kompleks, seorang pengamat penuh akan melayani dia dengan lebih baik, tetapi baru setelah itu.
Doc Brown
Pernyataan yang adil, tapi rasanya seperti jendela pecah bagi saya.
RubberDuck
2
@RubberDuck: menambahkan pengamat penuh, dengan mekanisme penerbit / pelanggan "untuk berjaga-jaga", ketika itu tidak benar-benar dibutuhkan, terasa bagi saya seperti rekayasa ulang - itu tidak lebih baik.
Doc Brown
1
Saya tidak sependapat bahwa itu bisa karena rekayasa. Saya mungkin merasakan hal yang saya lakukan karena itu sepele untuk diterapkan dalam tumpukan pilihan saya. Lagi pula, kita hanya akan setuju untuk tidak setuju?
RubberDuck