Arsitektur Bersih: Apa Model Tampilan?

13

Dalam bukunya 'Clean Architecture', Paman Bob mengatakan bahwa Presenter harus memasukkan data yang diterimanya ke dalam sesuatu yang dia sebut 'View Model'.

masukkan deskripsi gambar di sini

Apakah ini sama dengan 'ViewModel' dari pola desain Model-View-ViewModel (MVVM) atau apakah itu Data Transfer Object (DTO) yang sederhana?

Jika ini bukan DTO sederhana, bagaimana hubungannya dengan View? Apakah tampilan mendapatkan pembaruan darinya melalui hubungan Observer?

Dugaan saya adalah lebih seperti ViewModel dari MVVM, karena dalam Bab 23 bukunya, Robert Martin mengatakan:

Pekerjaan [Presenter] adalah untuk menerima data dari aplikasi dan memformatnya untuk presentasi sehingga Tampilan dapat memindahkannya ke layar. Misalnya, jika aplikasi ingin tanggal ditampilkan dalam bidang, itu akan menyerahkan objek Presenter tanggal. Presenter kemudian akan memformat data itu menjadi string yang sesuai dan menempatkannya dalam struktur data sederhana yang disebut model View, di mana View dapat menemukannya.

Ini menyiratkan bahwa View entah bagaimana terhubung ke ViewModel, sebagai lawan dari hanya menerimanya sebagai argumen fungsi misalnya (seperti halnya dengan DTO).

Alasan lain mengapa saya pikir ini adalah karena jika Anda melihat gambar, Presenter menggunakan View Model, tetapi bukan View. Sedangkan penggunaan Presenter baik Output Batas dan Output data DTO.

Jika itu bukan DTO atau ViewModel dari MVVM, tolong jelaskan apa itu.

Fearnbuster
sumber
Saya pikir jawabannya adalah "itu tergantung." Jika itu adalah aplikasi web maka model tampilan pada dasarnya adalah DTO karena pada akhirnya akan diserialisasi sebagai string HTML. Kalau tidak, model tampilan hanya objek khusus untuk menampilkan data ke tampilan.
Greg Burghardt
Dalam MVVM (WPF, aplikasi Winforms) ViewModeladalah pembungkus Controller, Presenterdan ViewModeldalam arsitektur Clean Paman Bob.
Fabio
@Greg Burghardt - Ketika ViewModel adalah struktur data khusus, bagaimana cara View diberitahu tentang perubahan?
Fearnbuster
@ Fabio - Jika saya mengambil arti Anda dengan benar perkataan Anda bahwa dalam pola MVVM, ViewModel setara dengan semua komponen yang ada dalam kelompok diagram paling kiri? Jika itu berlaku untuk arsitektur Paman Bob, lalu mengapa ia membuat daftar Pengendali dan Presenter secara terpisah?
Fearnbuster
Saya pikir dia memisahkan input dan output handler ke objek / kelas yang berbeda. Dalam MVVM bisa jadi Controller-> ICommanddan Presenter-> data-binding mechanism.
Fabio

Jawaban:

17

Apakah ini hal yang sama dengan 'ViewModel' dari pola desain Model-View-ViewModel (MVVM)

Nggak.

Itu akan menjadi ini :

masukkan deskripsi gambar di sini

Itu memiliki siklus. Paman Bob dengan hati-hati menghindari siklus .

Alih-alih Anda memiliki ini:

masukkan deskripsi gambar di sini

Yang pasti tidak memiliki siklus. Tapi itu membuat Anda bertanya-tanya bagaimana pandangan tahu tentang pembaruan. Kita akan membahasnya sebentar lagi.

atau apakah itu Data Transfer Object (DTO) yang sederhana?

Mengutip Bob dari halaman sebelumnya:

Anda dapat menggunakan struct dasar atau objek transfer data sederhana jika Anda mau. Atau Anda bisa mengemasnya ke dalam hashmap, atau membuatnya menjadi sebuah objek.

Arsitektur Bersih p207

Jadi, tentu saja, jika Anda suka.

Tapi saya sangat curiga apa yang sebenarnya mengganggu Anda adalah ini :

masukkan deskripsi gambar di sini

Penyalahgunaan kecil yang lucu dari UML ini kontras arah ketergantungan kode sumber dengan arah aliran kontrol. Di sinilah jawaban untuk pertanyaan Anda dapat ditemukan.

Dalam hubungan menggunakan:

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

aliran kontrol berjalan ke arah yang sama dengan ketergantungan kode sumber.

Dalam hubungan pelaksana:

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

aliran kontrol biasanya berjalan berlawanan arah dengan ketergantungan kode sumber.

Yang berarti Anda benar-benar melihat ini:

masukkan deskripsi gambar di sini

Anda harus dapat melihat bahwa aliran kontrol tidak akan pernah beralih dari Presenter ke View.

Bagaimana itu bisa terjadi? Apa artinya?

Ini berarti view memiliki thread sendiri (yang tidak biasa) atau (seperti yang ditunjukkan oleh @Euphoric) aliran kontrol datang ke tampilan dari sesuatu yang tidak digambarkan di sini.

Jika itu adalah utas yang sama maka View akan tahu kapan View-Model siap dibaca. Tetapi jika itu yang terjadi dan tampilan adalah GUI maka itu akan mengalami kesulitan mengecat ulang layar ketika pengguna memindahkannya sementara mereka menunggu DB.

Jika tampilan memiliki utasnya sendiri maka ia memiliki aliran kontrol sendiri. Itu berarti untuk mengimplementasikan ini, View harus menyurvei View-Model untuk melihat perubahan.

Karena Presenter tidak tahu View itu ada dan View tidak tahu Presenter itu ada, mereka tidak bisa saling memanggil. Mereka tidak bisa saling melemparkan acara. Yang bisa terjadi adalah Presenter akan menulis ke View-Model dan View akan membaca View-Model. Setiap kali terasa seperti itu.

Menurut diagram ini, satu-satunya bagian View dan Presenter berbagi adalah pengetahuan tentang View-Model. Dan itu hanya struktur data. Jadi jangan berharap itu memiliki perilaku.

Itu mungkin tampak mustahil tetapi dapat dibuat untuk bekerja bahkan jika View-Model itu kompleks. Satu bidang kecil yang diperbarui adalah semua tampilan harus polling untuk mendeteksi perubahan.

Sekarang tentu saja Anda dapat bersikeras menggunakan pola pengamat, atau meminta kerangka kerja menyembunyikan masalah ini dari Anda, tetapi harap dipahami bahwa Anda tidak harus melakukannya.

Inilah sedikit kesenangan yang saya ilustrasikan pada aliran kontrol:

masukkan deskripsi gambar di sini

Perhatikan bahwa setiap kali Anda melihat aliran berlawanan dengan arah yang saya tentukan sebelumnya, apa yang Anda lihat adalah panggilan balik. Trik itu tidak akan membantu kita sampai ke View. Baiklah, kecuali kita pertama kembali ke apa pun yang disebut Controller. Atau Anda bisa saja mengubah desainnya sehingga Anda bisa mendapatkan tampilan. Itu juga memperbaiki apa yang tampak seperti awal dari masalah yo-yo dengan Akses Data dan Antarmuka itu.

Satu-satunya hal lain yang perlu dipelajari di sini selain itu adalah Use Case Interactor dapat memanggil banyak hal dalam urutan apa pun yang diinginkan asalkan memanggil presenter yang terakhir.

candied_orange
sumber
Terima kasih banyak untuk jawabannya, saya telah melihat jawaban Anda pada berbagai pertanyaan lain tentang Arsitektur Bersih. Apakah Anda menyarankan agar Lihat terus-menerus memeriksa bendera, misalnya, dalam Model Tampilan untuk melihat apakah ada perubahan? Apakah tampilan kemudian harus menampilkan kembali seluruh Model Tampilan lagi, atau haruskah saya menggunakan set flag bersarang untuk menunjukkan data mana yang telah diubah?
Fearnbuster
Tampilan tidak harus disurvei terus-menerus. Misalnya web 1.0 hanya polling saat pengguna mengklik memuat ulang. Polling terus-menerus adalah keputusan desain yang harus mempertimbangkan kebutuhan nyata pengguna. Saya hanya mengatakan itu mungkin. Inti dari bidang pembaruan adalah membuat deteksi pembaruan dengan cepat. Hanya diperlukan jika Model Tampilan rumit. Juga pertimbangkan apa yang terjadi jika tampilan berbunyi saat presenter sedang melalui pembaruan.
candied_orange
Oke, terima kasih banyak atas bantuannya. Jika / ketika Anda mengikuti arsitektur ini, apakah ini teknik yang biasa Anda gunakan?
Fearnbuster
1
Saya pikir ada kesalahan besar bahwa jawaban ini mengelompokkan ketergantungan desain dan ketergantungan runtime. Keduanya bisa berbeda.
Euforia
1
@Ehhoric Why terima kasih. Saya mengikat mereka bersama karena jika Anda tidak memiliki ketergantungan kode sumber pada sesuatu, Anda tidak dapat menggunakan referensi runtime untuk apa pun karena Anda tidak mengerti apa itu. Yang bisa Anda lakukan hanyalah memegang referensi seperti koleksi. Jika itu kesalahan saya ingin memahaminya.
candied_orange
2

Saya menemukan masalah ini terlalu membingungkan dan akan membutuhkan banyak teks dan waktu untuk menjelaskan masalah dengan benar karena saya percaya Anda salah paham baik Arsitektur Bersih dan MVVM Martin.

Hal pertama yang perlu diperhatikan, adalah bahwa diagram yang Anda posting tidak lengkap. Ini hanya menunjukkan "logika bisnis", tetapi kehilangan semacam "orkestra" yang benar-benar membuat bagian-bagian bergerak dalam urutan yang benar. masukkan deskripsi gambar di sini

Kode orkestra akan sesederhana

string Request(string request) // returns response
{
    Controller.Run(data);
    Presenter.Run();
    return View.Run();
}

Saya percaya saya mendengar Martin berbicara tentang ini dalam salah satu ceramahnya tentang Arsitektur Bersih.

Hal lain yang perlu dikemukakan adalah bahwa pernyataan candied_orange tentang kurangnya siklus salah. Ya, siklus tidak ada (dan tidak seharusnya) dalam arsitektur kode. Tetapi siklus antara proses runtime adalah umum dan sering mengarah pada desain yang lebih sederhana.

Itu adalah kasus di MVVM. Dalam MVVM View tergantung pada ViewModel, dan ViewModel menggunakan acara untuk memberi tahu View tentang perubahan itu. Ini berarti bahwa dalam desain kelas, hanya ada ketergantungan dari kelas Tampilan ke Model, tetapi selama runtime, ada ketergantungan siklus antara instance View dan ViewModel. Karena itu, tidak perlu orkestra, karena ViewModel akan menyediakan cara Tampilan untuk mengetahui kapan harus memperbarui sendiri. Inilah sebabnya mengapa "pemberitahuan" dalam diagram ini menggunakan garis "tepat" dan bukan garis langsung. Itu berarti View mengamati perubahan dalam ViewModel, bukan ViewModel yang bergantung pada View.

masukkan deskripsi gambar di sini

Hal terpenting yang harus Anda ambil dari Arsitektur Bersih Martin bukanlah desain itu sendiri, tetapi bagaimana Anda menangani ketergantungan. Salah satu poin penting yang dia buat dalam pembicaraannya adalah bahwa ketika ada batas, maka semua dependensi kode yang melintasi batas itu melintasinya dalam satu arah. Dalam diagram, batas ini diwakili oleh garis ganda. Dan ada banyak inversi ketergantungan melalui antarmuka ( InputBoundary, OutputBoundarydan DataAccessInterface) yang memperbaiki arah ketergantungan kode.

Sebaliknya ViewModeldalam Arsitektur Bersih hanya DTO tanpa logika. Ini dibuat jelas dengan <DS>tag. Dan ini adalah alasan mengapa orchestratorperlu, karena Viewtidak akan tahu kapan harus menjalankan logika itu.

Jika saya "meratakan" diagram menjadi seperti apa itu selama runtime, itu akan terlihat seperti ini:

masukkan deskripsi gambar di sini

Jadi selama runtime, dependensi berada di arah "salah", tapi itu bagus.

Saya sarankan menonton ceramahnya tentang Arsitektur Bersih untuk lebih memahami alasannya.

Euforia
sumber
"Orkestrator" Anda seharusnya tidak memanggil Presenter. Use Case Interactor melakukan itu.
candied_orange
@candied_orange Benar, itu kesalahan.
Euforia
Terima kasih atas jawabannya, selalu baik untuk mendapatkan beberapa pendapat berbeda. Saya membatalkan jawaban kedua teman Anda. Apakah Anda berdua tahu kalau Robert Martin memiliki basis kode di suatu tempat di mana ia menerapkan bentuk Arsitekturnya? Saya melihat proyek FitNess-nya, tetapi saya tidak bisa melihat hutan untuk pepohonan. Juga, apakah saya benar dalam berspekulasi bahwa, meskipun gambar yang saya posting adalah diagram yang selalu digunakan Paman Bob dalam pembicaraannya, itu sebenarnya hanya contoh dari apa arsitektur Anda MUNGKIN terlihat seperti? Padahal itu bisa terlihat sangat berbeda selama aliran ketergantungan benar?
Fearnbuster
@Fearnbuster Untuk pertanyaan terakhir Anda, ya. Arah ketergantungan lebih penting daripada struktur. Saya percaya bahwa "Arsitektur bersih", "arsitektur bawang" dan "arsitektur heksagonal" benar-benar implementasi dari ide yang sama "Simpan dependensi dalam cek".
Euforia
@ Euphoric Jujur, saya akan mengatakan bahwa ini mungkin terjadi, karena dalam gambar yang berbeda dari bukunya (Gambar 8.2 Bab 8), ia menunjukkan arsitektur yang terlihat berbeda. Dalam diagram itu, Pengendali sebenarnya adalah perantara antara Interactor dan Presenter. Juga tidak ada Batas Output untuk Interactor; tampaknya Interactor menerima permintaan melalui antarmuka, dan kemudian mengembalikan respons melalui antarmuka yang sama (saya berasumsi ini dilakukan melalui nilai pengembalian fungsi sederhana, karena saya tidak bisa memikirkan mekanisme lain yang akan bekerja seperti itu).
Fearnbuster