Apakah MVVM tidak ada gunanya? [Tutup]

91

Apakah implementasi MVVM ortodoks tidak ada gunanya? Saya membuat aplikasi baru dan saya mempertimbangkan Formulir Windows dan WPF. Saya memilih WPF karena tahan masa depan dan menawarkan banyak fleksibilitas. Ada lebih sedikit kode dan lebih mudah untuk membuat perubahan signifikan pada UI Anda menggunakan XAML.

Karena pilihan untuk WPF sudah jelas, saya pikir saya sebaiknya menggunakan MVVM sebagai arsitektur aplikasi saya karena menawarkan perpaduan, masalah pemisahan, dan kemampuan pengujian unit. Secara teoritis, ini tampak indah seperti cawan suci pemrograman UI. Petualangan singkat ini; Namun, telah berubah menjadi sakit kepala yang nyata. Seperti yang diharapkan dalam praktik, saya menemukan bahwa saya telah menukar satu masalah dengan masalah lainnya. Saya cenderung menjadi programmer yang obsesif karena saya ingin melakukan hal-hal dengan cara yang benar sehingga saya bisa mendapatkan hasil yang tepat dan mungkin menjadi programmer yang lebih baik. Pola MVVM baru saja gagal dalam pengujian saya tentang produktivitas dan baru saja berubah menjadi peretasan besar yang menjijikkan!

Kasus yang jelas adalah menambahkan dukungan untuk kotak dialog Modal. Cara yang benar adalah dengan memasang kotak dialog dan mengikatnya ke model tampilan. Membuat ini berhasil itu sulit. Untuk memanfaatkan pola MVVM, Anda harus mendistribusikan kode di beberapa tempat di seluruh lapisan aplikasi Anda. Anda juga harus menggunakan konstruksi pemrograman esoterik seperti template dan ekspresi lamba. Hal-hal yang membuat Anda menatap layar sambil menggaruk-garuk kepala. Hal ini membuat pemeliharaan dan debugging menjadi mimpi buruk yang menunggu untuk terjadi seperti yang baru-baru ini saya temukan. Saya memiliki tentang kotak yang berfungsi dengan baik sampai saya mendapat pengecualian untuk kedua kalinya saya memanggilnya, mengatakan bahwa itu tidak dapat menampilkan kotak dialog lagi setelah ditutup. Saya harus menambahkan event handler untuk fungsi tutup ke jendela dialog, satu lagi dalam implementasi IDialogView-nya dan terakhir satu lagi di IDialogViewModel. Saya pikir MVVM akan menyelamatkan kita dari peretasan boros seperti itu!

Ada beberapa orang di luar sana dengan solusi yang bersaing untuk masalah ini dan mereka semua adalah peretasan dan tidak memberikan solusi yang bersih, mudah digunakan kembali, dan elegan. Sebagian besar toolkit MVVM mengabaikan dialog dan ketika mereka mengatasinya, itu hanya kotak peringatan yang tidak memerlukan antarmuka kustom atau model tampilan.

Saya berencana untuk menyerah pada pola tampilan MVVM, setidaknya implementasi ortodoksnya. Bagaimana menurut anda? Apakah itu sepadan dengan masalah Anda jika Anda punya? Apakah saya hanya seorang programmer yang tidak kompeten atau apakah MVVM tidak sesuai dengan keinginannya?

Joel Rodgers
sumber
8
Saya selalu mempertanyakan apakah MVVM adalah rekayasa berlebihan atau tidak. Pertanyaan menarik.
Taylor Leese
12
Pola seperti MVVM dan MVC tampak seperti rekayasa berlebihan, hingga Anda harus melakukan beberapa modifikasi atau mengganti komponen. Pertama kali Anda harus melakukannya, semua upacara akan terbayar dengan sendirinya.
Robert Harvey
42
Lambdas itu esoterik? berita untuk saya.
Ray Booysen
6
@Ray - Haha, +1 untuk komentar itu! : D
Venemo
8
Seperti yang ditunjukkan Alan Cooper lebih dari satu dekade lalu di About Face , jika Anda mendesain UI dan dialog modal bukanlah kasus tepi, Anda mungkin melakukan sesuatu yang salah.
Robert Rossney

Jawaban:

61

Maaf jika jawaban saya menjadi sedikit panjang, tapi jangan salahkan saya! Pertanyaan Anda juga panjang.

Singkatnya, MVVM bukannya tidak berarti.

Kasus yang jelas adalah menambahkan dukungan untuk kotak dialog Modal. Cara yang benar adalah dengan memasang kotak dialog dan mengikatnya ke model tampilan. Sulit untuk membuat ini berhasil.

Ya, benar.
Namun, MVVM memberi Anda cara untuk memisahkan tampilan UI dari logikanya. Tidak ada yang memaksa Anda untuk menggunakannya di mana saja, dan tidak ada yang memegang pistol di dahi Anda untuk membuat Anda membuat ViewModel terpisah untuk semuanya.

Berikut adalah solusi saya untuk contoh khusus ini:
Bagaimana UI menangani input tertentu bukanlah urusan ViewModel. Saya akan menambahkan kode ke file .xaml.cs View, yang membuat instance kotak dialog dan menetapkan instance ViewModel yang sama (atau yang lain, jika diperlukan) sebagai DataContext-nya.

Untuk memanfaatkan pola MVVM, Anda harus mendistribusikan kode di beberapa tempat di seluruh lapisan aplikasi Anda. Anda juga harus menggunakan konstruksi pemrograman esoterik seperti template dan ekspresi lamba.

Nah, Anda tidak harus menggunakannya di beberapa tempat. Beginilah cara saya menyelesaikannya:

  • Tambahkan XAML ke View, dan tidak ada apa pun di .xaml.cs
  • Tulis setiap logika aplikasi (kecuali hal-hal yang akan beroperasi langsung dengan elemen UI) di dalam ViewModel
  • Semua kode yang harus dilakukan oleh UI tetapi tidak ada hubungannya dengan logika bisnis masuk ke file .xaml.cs

Saya pikir tujuan MVVM terutama untuk memisahkan logika aplikasi dan UI konkret, oleh karena itu memungkinkan modifikasi mudah (atau penggantian lengkap) UI.
Saya menggunakan prinsip berikut: Tampilan dapat mengetahui dan mengasumsikan apa pun yang diinginkan dari ViewModel, tetapi ViewModel tidak dapat mengetahui APA PUN tentang Tampilan.
WPF menyediakan model pengikatan yang bagus yang dapat Anda gunakan untuk mencapai hal itu.

(BTW, template dan ekspresi lambda tidak esoterik jika digunakan dengan benar. Tetapi jika Anda tidak ingin, jangan gunakan mereka.)

Hal-hal yang membuat Anda menatap layar sambil menggaruk-garuk kepala.

Ya, saya tahu perasaan itu. Persis seperti yang saya rasakan saat pertama kali melihat MVVM. Tapi begitu Anda menguasainya, itu tidak akan terasa buruk lagi.

Saya memiliki tentang kotak yang berfungsi dengan baik ...

Mengapa Anda meletakkan ViewModel di belakang kotak tentang? Tidak ada gunanya.

Sebagian besar toolkit MVVM mengabaikan dialog dan ketika mereka mengatasinya, itu hanya kotak peringatan yang tidak memerlukan antarmuka kustom atau model tampilan.

Ya, karena fakta bahwa elemen UI berada di jendela yang sama, atau jendela lain, atau mengorbit Mars saat ini bukanlah urusan ViewModels.
Pemisahan Masalah

EDIT:

Berikut adalah video yang sangat bagus yang judulnya Bangun kerangka kerja MVVM Anda sendiri . Layak untuk ditonton.

Venemo
sumber
3
1 untuk tiga kata terakhir. Tapi jawaban selebihnya bagus juga. :)
Robert Harvey
13
1 untuk saran tentang penggunaan kode di belakang. Ini adalah kesalahpahaman umum bahwa "buruk" menggunakan kode di belakang di MVVM ... tetapi untuk hal-hal yang murni terkait UI, itulah cara yang harus dilakukan.
Thomas Levesque
1
@ Thomas: Ya, saya sangat setuju. Saya telah melihat beberapa implementasi di mana orang-orang meletakkan semua kode (bahkan yang berhubungan dengan UI) ke dalam ViewModel, karena (menurut mereka) "di situlah kodenya". Itu cukup hacky.
Venemo
4
@Venemo, menurut saya Anda dapat merangkum banyak hal yang ingin Anda masukkan ke dalam kode di belakang menggunakan teknik seperti Perilaku khusus, yang berguna jika Anda berulang kali menulis kode lem. Secara umum, saya pikir lebih baik menggunakan kode di belakang untuk lem daripada meretas XAML yang canggung. Perhatian utama, dalam pikiran saya, adalah memastikan tidak ada apa pun di belakang kode yang cukup canggih untuk menjamin pengujian unit. Apa pun yang cukup kompleks lebih baik dikemas dalam ViewModel atau kelas ekstensi, seperti Behavior atau MarkupExtension.
Dan Bryant
8
@ Thomas: Anda benar, mitos terbesar tentang MVVM adalah bahwa tujuan MVVM adalah untuk menghilangkan kode di belakang. Tujuannya adalah untuk mengeluarkan ocde Non-UI dari kode di belakangnya. Menempatkan kode khusus UI di ViewModel sama buruknya dengan meletakkan kode domain masalah di belakang kode.
Jim Reineri
8

Sulit untuk membuat ini berhasil. Untuk memanfaatkan pola MVVM, Anda harus mendistribusikan kode di beberapa tempat di seluruh lapisan aplikasi Anda. Anda juga harus menggunakan konstruksi pemrograman esoterik seperti template dan ekspresi lamba.

Untuk kotak dialog modal biasa? Anda pasti melakukan sesuatu yang salah di sana - implementasi MVVM tidak harus serumit itu.

Mengingat Anda baru mengenal MVVM dan WPF, kemungkinan Anda menggunakan solusi suboptimal di mana-mana dan hal-hal yang tidak perlu mempersulit - setidaknya saya melakukannya ketika saya pertama kali menggunakan WPF. Pastikan bahwa masalahnya benar-benar MVVM dan bukan implementasi Anda sebelum menyerah.

MVVM, MVC, Document-View, dll. Adalah keluarga pola lama .. Ada kekurangannya, tapi tidak ada kekurangan fatal dari jenis yang Anda gambarkan.

ima
sumber
5

Saya sedang dalam pengembangan MVVM yang cukup kompleks menggunakan PRISM jadi saya sudah harus mengatasi masalah seperti ini.

Kesimpulan pribadi saya:

MVVM vs MVC / PopUps & co

  • MVVM benar-benar pola yang hebat dan dalam banyak kasus itu sepenuhnya menggantikan MVC berkat pengikatan data yang kuat di WPF
  • Memanggil lapisan layanan Anda langsung dari penyaji adalah implementasi yang sah dalam banyak kasus
  • Bahkan skenario Daftar / Detail yang cukup kompleks dapat diimplementasikan oleh MVVM murni berkat sintaks {Binding Path = /}
  • Meskipun demikian, ketika koordinasi yang kompleks antara beberapa tampilan perlu diterapkan, pengontrol wajib
  • Acara dapat digunakan; pola lama yang menyiratkan penyimpanan instance IView (atau AbstractObserver) di controller sudah usang
  • Pengontrol dapat disuntikkan di setiap Presenter oleh wadah IOC
  • Layanan IEventAggregator Prism adalah solusi lain yang mungkin jika satu-satunya penggunaan pengontrol adalah pengiriman peristiwa (dalam hal ini dapat sepenuhnya menggantikan pengontrol)
  • Jika tampilan akan dibuat secara dinamis, ini adalah pekerjaan yang sangat cocok untuk pengontrol (dalam prisma pengontrol akan diinjeksi (IOC) sebuah IRegionManager)
  • Kotak dialog Modal sebagian besar sudah usang dalam aplikasi komposit modern, kecuali untuk operasi yang benar-benar memblokir seperti konfirmasi wajib; dalam kasus ini aktivasi modal dapat diabstraksikan sebagai layanan yang dipanggil di dalam pengontrol, dan diimplementasikan oleh kelas khusus, yang juga memungkinkan pengujian unit tingkat presentasi lanjutan. Pengontrol akan, misalnya, memanggil IConfirmationService.RequestConfirmation (“apakah Anda yakin”) yang akan memicu tampilan dialog modal pada waktu proses dan dapat dengan mudah diejek selama pengujian unit
dan ionescu
sumber
5

Saya menangani masalah dialog dengan curang. MainWindow saya mengimplementasikan antarmuka IWindowServices yang memperlihatkan semua dialog khusus aplikasi. ViewModels saya yang lain kemudian dapat mengimpor antarmuka layanan (saya menggunakan MEF, tetapi Anda dapat dengan mudah meneruskan antarmuka melalui konstruktor secara manual) dan menggunakannya untuk mencapai apa yang diperlukan. Misalnya, inilah tampilan antarmuka untuk aplikasi utilitas kecil saya:

//Wrapper interface for dialog functionality to allow for mocking during tests
public interface IWindowServices
{
    bool ExecuteNewProject(NewProjectViewModel model);

    bool ExecuteImportSymbols(ImportSymbolsViewModel model);

    bool ExecuteOpenDialog(OpenFileDialog dialog);

    bool ExecuteSaveDialog(SaveFileDialog dialog);

    bool ExecuteWarningConfirmation(string text, string caption);

    void ExitApplication();
}

Ini menempatkan semua eksekusi Dialog di satu tempat dan dapat dengan mudah dihentikan untuk pengujian unit. Saya mengikuti pola bahwa klien dialog harus membuat ViewModel yang sesuai, yang kemudian dapat mereka konfigurasi sesuai kebutuhan. Blok panggilan Execute dan setelah itu klien dapat melihat konten ViewModel untuk melihat hasil Dialog.

Desain MVVM yang lebih 'murni' mungkin penting untuk aplikasi besar, di mana Anda memerlukan isolasi yang lebih bersih dan komposisi yang lebih kompleks, tetapi untuk aplikasi berukuran kecil hingga sedang, menurut saya pendekatan praktis, dengan layanan yang sesuai untuk mengekspos pengait yang diperlukan, sudah cukup memadai .

Dan Bryant
sumber
Tapi di mana Anda menyebutnya? Bukankah lebih baik untuk hanya membuat dialog di dalam fungsi kelas IWindowServices daripada membiarkannya masuk. Dengan cara itu tampilan model pemanggil tidak perlu mengetahui apapun tentang implementasi dialog tertentu.
Joel Rodgers
Antarmuka dimasukkan ke dalam instance ViewModel saya yang mana saja yang memerlukan akses ke dialog aplikasi. Dalam kebanyakan kasus, saya meneruskan ViewModel untuk dialog, tetapi saya agak malas dan menggunakan WPF OpenFileDialog dan SaveFileDialog untuk panggilan dialog file. Tujuan utama saya adalah isolasi untuk tujuan pengujian unit, jadi ini cukup untuk tujuan itu. Jika Anda menginginkan isolasi yang lebih baik, Anda mungkin ingin membuat OpenFileViewModel dan SaveFileViewModel, yang akan menduplikasi properti yang diperlukan untuk dialog.
Dan Bryant
Perhatikan bahwa ini jelas bukan pendekatan murni, karena ViewModel yang menggunakan dialog mengetahui tentang ViewModel spesifik untuk setiap dialog yang ingin dibuka. Saya merasa ini cukup bersih, tetapi Anda selalu dapat menambahkan lapisan isolasi tambahan dengan kelas yang murni mengekspos parameter yang diperlukan untuk penggunaan dialog, menyembunyikan visibilitas properti ViewModel yang tidak perlu yang digunakan selama pengikatan. Untuk aplikasi yang lebih kecil, saya merasa insulasi tambahan ini berlebihan.
Dan Bryant
5

Pola desain ada untuk membantu Anda, bukan menghalangi. Bagian kecil dari menjadi pengembang yang baik adalah mengetahui kapan harus "melanggar aturan". Jika MVVM merepotkan untuk sebuah tugas dan Anda telah menentukan bahwa nilai masa depan tidak sebanding dengan usaha, maka jangan gunakan polanya. Misalnya, seperti yang telah dikomentari oleh poster lain, mengapa Anda harus melakukan semua pengeluaran untuk menerapkan kotak sederhana tentang?

Pola desain tidak pernah dimaksudkan untuk diikuti secara dogmatis.

RMart
sumber
2
Benar. Kotak sederhana tentang seharusnya sederhana, tetapi bagaimana jika Anda harus menampilkan informasi seperti versi, lisensi, proses yang berjalan, nama perusahaan, dll. Ini semua informasi yang ada di suatu tempat. Dalam bentuk standar, Anda bisa mengikat semua informasi itu dan menyelesaikannya. MVVM mengatakan Anda harus membuat model tampilan untuknya, yang berlebihan.
ATL_DEV
1

Karena polanya sendiri, MVVM sangat bagus. Tetapi pustaka kontrol WPF yang dikirimkan dengan dukungan pengikatan data NET 4.0 sangat terbatas, jauh lebih baik daripada WinForm, tetapi tetap saja itu tidak cukup untuk MVVM yang dapat diikat, saya akan mengatakan bahwa kekuatannya adalah sekitar 30% dari apa yang dibutuhkan untuk MVVM yang dapat diikat.
MVVM yang dapat diikat: ini adalah UI tempat ViewModel dihubungkan dengan View hanya menggunakan data binding.
Pola MVVM adalah tentang representasi objek dari Kondisi Tampilan, itu tidak menjelaskan bagaimana Anda menjaga sinkronisasi antara View dan ViewModel, di WPF itu mengikat data tetapi bisa apa saja. Dan sebenarnya Anda dapat menggunakan pola MVVM di setiap toolkit UI yang mendukung event \ callbacks, Anda dapat menggunakannya di WinAPI murni di WinForms (saya lakukan, dan ini tidak lebih berfungsi dengan event \ callbacks), dan Anda bahkan dapat menggunakannya dalam Teks Konsol, seperti menulis ulang Norton Commander DoS menggunakan pola MVVM.

Singkatnya: MVVM bukan tidak berarti, itu bagus. Pustaka kendali NET 4.0 WPF adalah sampah.

Berikut adalah bukti sederhana dari konsep ViewModel dimana Anda tidak dapat mengikat data dengan cara MVVM murni menggunakan WPF.

public class PersonsViewModel
{
    public IList<Person> PersonList;
    public IList<ColumnDescription> TableColumns;
    public IList<Person> SelectedPersons;
    public Person ActivePerson;
    public ColumnDescription SortedColumn;
}

Anda tidak dapat mengikat data header kolom DataGrid WPF, Anda tidak dapat mengikat data baris yang dipilih, dll, dll., Anda akan melakukannya dengan cara sederhana, atau menulis 200 baris kode peretasan XAML untuk 5 baris ViewModel yang paling sederhana ini. Anda hanya bisa membayangkan bagaimana hal-hal menjadi lebih buruk dengan ViewModels yang kompleks.
Jadi jawabannya sederhana kecuali Anda menulis aplikasi Hello World, menggunakan MVVM yang dapat diikat di WPF tidak ada gunanya. Anda akan menghabiskan sebagian besar waktu Anda memikirkan hack untuk mengikat ViewModel Anda. Pengikatan data bagus, tetapi bersiaplah untuk kembali ke 70% waktu acara.

Alex Burtsev
sumber
Anda bisa mengikat ini, dengan konverter, ke datagrid.
Cameron MacFarland
@CameronMacFarland: Tidak semua, beberapa properti hanya dapat dibaca dan tidak dapat diikat, beberapa tidak ada dan hanya ada peristiwa yang status laporannya berubah.
Alex Burtsev
Saya akui saya tidak memiliki banyak pengalaman menggunakan WPF DataGrid. Saya cenderung menghindarinya karena jelek dan tidak sesuai dengan WPF lagi. Karena itu, kombinasi konverter dan AttachedProperties untuk menangani peristiwa akan memberi Anda apa yang Anda butuhkan.
Cameron MacFarland
1
Alex, masalah yang Anda hadapi ada pada desain DataGrid, bukan MVVM. Tidaklah benar untuk mengatakan bahwa "Pengikatan data itu bagus, tetapi bersiaplah untuk kembali ke 70% waktu peristiwa." Saya telah menulis beberapa aplikasi WPF yang sangat besar dan obyektif di mana tidak ada event handler di UI apapun - dengan pengecualian event handler yang dibutuhkan grid data (Telerik) untuk inisialisasi.
Robert Rossney
3
Saya pikir Anda mungkin lebih berhasil jika alih-alih mengadopsi sikap, "Ini dirancang dengan buruk dan tidak berhasil," Anda mencoba, "Mengapa ini berhasil untuk orang lain tetapi tidak untuk saya?" Anda mungkin menemukan bahwa alasan hal-hal sulit dilakukan adalah karena Anda belum tahu cara melakukannya.
Robert Rossney
0

Tidak, itu tidak sia-sia, tetapi sulit untuk membungkus kepala Anda meskipun polanya sendiri sangat sederhana. Ada banyak informasi yang salah di luar sana dan berbagai kelompok yang memperebutkan cara yang tepat. Saya pikir dengan WPF dan Silverlight Anda harus menggunakan MVVM atau Anda akan over coding dan mencoba untuk memecahkan masalah dalam model baru metodologi bentuk menang "lama" yang hanya membawa Anda ke dalam masalah. Ini lebih banyak terjadi di Silverlight karena semuanya harus asinkron (peretasan di sekitar ini dimungkinkan, tetapi Anda harus memilih platform lain).

Saya sarankan membaca artikel ini Menyederhanakan WPF TreeView dengan Menggunakan Pola ViewModel dengan hati-hati untuk melihat bagaimana MVVM dapat diimplementasikan dengan baik dan memungkinkan Anda untuk mengubah mentalitas bentuk kemenangan Anda ke cara berpikir yang baru di MVVM. Singkatnya, ketika Anda ingin menyelesaikan sesuatu, terapkan logika ke ViewModel terlebih dahulu, bukan View. Anda ingin memilih item? Ubah ikon? Jangan mengulangi elemen UI, cukup perbarui properti model dan biarkan pengikatan data melakukan intinya.

Kapal Tunda Kapten
sumber
-1

Saya telah melihat masalah yang sama dengan banyak implementasi MVVM dalam hal dialog (modal). Ketika saya melihat peserta Pola MVVM maka saya merasa ada sesuatu yang hilang untuk membangun aplikasi yang koheren.

  • View berisi kontrol GUI tertentu dan mendefinisikan tampilan antarmuka pengguna.
  • ViewModel mewakili keadaan dan perilaku presentasi.
  • Model dapat berupa objek bisnis dari lapisan domain atau layanan yang menyediakan data yang diperlukan.

Tapi yang hilang adalah:

  • Siapa yang membuat ViewModels?
  • Siapa yang bertanggung jawab atas alur kerja aplikasi?
  • Siapa yang menjadi perantara di antara ViewModels saat mereka perlu berkomunikasi satu sama lain?

Pendekatan saya adalah untuk memperkenalkan (Use-Case) Controller yang bertanggung jawab atas poin yang hilang. Cara kerjanya dapat dilihat di contoh aplikasi WPF Application Framework (WAF) .

jbe
sumber
Pola Mediator yang diterapkan oleh Josh Smith menyelesaikan semua masalah komunikasi Model Tampilan saya. Messenger.NotifyColleagues menyediakan cara untuk memiliki model tampilan yang sepenuhnya independen yang tahu bagaimana menanggapi peristiwa global (jika mereka peduli) tanpa memiliki dua model tampilan yang saling mengenal. Ini sudah menghemat daging kita beberapa kali sekarang.
JasonD