Dalam proses mengembangkan Aplikasi Halaman Tunggal realtime, saya telah secara progresif mengadopsi websockets untuk memberdayakan pengguna saya dengan data terbaru. Selama fase ini, saya sedih melihat bahwa saya terlalu banyak menghancurkan struktur aplikasi saya, dan saya gagal menemukan solusi untuk fenomena ini.
Sebelum masuk ke spesifik, hanya sedikit konteks:
- Webapp adalah SPA waktu nyata;
- Backend ada di Ruby on Rails. Acara realtime didorong oleh Ruby ke kunci Redis, lalu server simpul mikro menariknya kembali dan mendorongnya ke Socket.Io;
- Frontend berada di AngularJS, dan terhubung langsung ke server socket.io di Node.
Di sisi server, sebelum waktu nyata saya memiliki pemisahan yang jelas berbasis kontroler / model dari sumber daya, dengan pemrosesan yang melekat pada masing-masing. Ini desain MVC klasik benar-benar robek bawah, atau setidaknya dilewati, tepat ketika saya mulai mendorong hal melalui WebSockets untuk pengguna saya. Sekarang saya memiliki satu pipa di mana semua aplikasi saya mengalir lebih atau kurang data terstruktur . Dan saya merasa stres.
Di ujung depan, perhatian utama adalah duplikasi logika bisnis. Ketika pengguna memuat halaman, saya harus memuat model saya melalui panggilan AJAX klasik. Tetapi saya juga harus menangani banjir data real-time, dan saya mendapati diri saya menduplikasi banyak logika bisnis sisi klien untuk menjaga konsistensi model sisi klien saya.
Setelah beberapa penelitian, saya tidak dapat menemukan posting, artikel, buku atau apa pun yang akan memberikan saran tentang bagaimana seseorang dapat dan harus merancang arsitektur webapp modern dengan beberapa topik tertentu dalam pikiran:
- Bagaimana cara menyusun data yang dikirim dari server ke pengguna?
- Haruskah saya mengirim acara seperti "sumber ini telah diperbarui dan Anda harus memuatnya kembali melalui panggilan AJAX" atau mendorong data yang diperbarui dan mengganti data sebelumnya yang dimuat melalui panggilan AJAX awal?
- Bagaimana cara mendefinisikan kerangka yang koheren dan skalabel untuk data yang dikirim? apakah ini pesan pembaruan model atau pesan "ada kesalahan dengan blahblahblah"
- Bagaimana tidak mengirim data tentang semuanya dari mana saja di backend?
- Bagaimana cara mengurangi duplikasi logika bisnis di server dan di sisi klien?
sumber
Jawaban:
Gunakan pola olahpesan . Yah, Anda sudah menggunakan protokol pengiriman pesan, tapi maksud saya struktur perubahan sebagai pesan ... khusus acara. Ketika sisi server berubah, itu menghasilkan peristiwa bisnis. Dalam skenario Anda, pandangan klien Anda tertarik dengan acara ini. Peristiwa harus berisi semua data yang relevan dengan perubahan itu (tidak harus semua data tampilan). Halaman klien kemudian harus memperbarui bagian tampilan yang dipertahankan dengan data acara.
Misalnya, jika Anda memperbarui ticker saham dan AAPL berubah, Anda tidak ingin menekan semua harga saham atau bahkan semua data tentang AAPL (nama, deskripsi, dll). Anda hanya akan mendorong AAPL, delta, dan harga baru. Pada klien, Anda hanya akan memperbarui harga saham itu pada tampilan.
Saya akan mengatakan tidak. Jika Anda mengirim acara, silakan dan kirim data yang relevan dengannya (bukan data seluruh objek). Beri nama untuk jenis acara itu. (Penamaan dan data apa yang relevan dengan peristiwa itu berada di luar lingkup kerja mekanis sistem. Ini lebih berkaitan dengan bagaimana logika bisnis dimodelkan.) Tampilan Anda para pemberi pembaruan perlu tahu cara menerjemahkan setiap peristiwa spesifik ke dalam perubahan tampilan yang tepat (yaitu hanya perbarui apa yang berubah).
Saya akan mengatakan ini adalah pertanyaan besar dan terbuka yang harus dipecah menjadi beberapa pertanyaan lain dan diposting secara terpisah.
Secara umum, sistem back-end Anda harus membuat dan mengirimkan peristiwa untuk kejadian penting pada bisnis Anda. Itu bisa datang dari feed eksternal atau dari aktivitas di back-end itu sendiri.
Gunakan pola terbitkan / berlangganan . Ketika SPA Anda memuat halaman baru yang tertarik untuk menerima pembaruan waktu-nyata, halaman tersebut harus berlangganan hanya acara-acara yang dapat digunakan, dan memanggil logika pembaruan tampilan saat peristiwa-peristiwa itu masuk. Anda mungkin perlu pub / sub logika server untuk mengurangi beban jaringan. Perpustakaan ada untuk pub / sub Websocket, tapi saya tidak yakin apa yang ada di ekosistem Rails.
Sepertinya Anda harus memperbarui data tampilan di klien dan server. Dugaan saya adalah Anda memerlukan data tampilan sisi server sehingga Anda memiliki snapshot untuk memulai klien real-time. Karena ada dua bahasa / platform yang terlibat (Ruby dan Javascript), logika pembaruan tampilan harus ditulis dalam keduanya. Selain dari transpiling (yang memiliki masalah sendiri), saya tidak melihat jalan keluarnya.
Poin teknis: Manipulasi data (tampilan pembaruan) bukan logika bisnis. Jika yang Anda maksud validasi use case, maka itu tampaknya tidak dapat dihindari karena validasi klien diperlukan untuk pengalaman pengguna yang baik, tetapi pada akhirnya tidak bisa dipercaya oleh server.
Inilah cara saya melihat hal seperti itu terstruktur dengan baik.
Pandangan Klien:
Perintah Klien:
Sisi server sebenarnya dapat dipecah menjadi beberapa komponen dengan tanggung jawab terbatas. Satu yang hanya memproses permintaan masuk dan membuat acara. Yang lain bisa mengelola langganan klien, mendengarkan acara (katakanlah dalam proses) dan meneruskan acara yang sesuai kepada pelanggan. Anda dapat memiliki pihak ketiga yang mendengarkan acara dan memperbarui tampilan sisi server - mungkin ini bahkan terjadi sebelum pelanggan menerima acara tersebut.
Apa yang saya jelaskan adalah bentuk CQRS + Messaging , dan strategi khas untuk mengatasi jenis masalah yang Anda hadapi.
Saya tidak memasukkan Sourcing Acara ke dalam deskripsi ini karena saya tidak yakin apakah itu sesuatu yang ingin Anda ambil atau jika Anda membutuhkannya. Tetapi ini adalah pola yang terkait.
sumber
Setelah beberapa bulan bekerja di backend terutama, saya telah dapat menggunakan beberapa saran di sini untuk mengatasi masalah yang dihadapi platform.
Tujuan utama ketika memikirkan kembali backend adalah untuk menempel sekuat mungkin ke CRUD. Semua tindakan, pesan, dan permintaan yang tersebar di banyak rute dikelompokkan kembali menjadi sumber daya yang dibuat, diperbarui, dibaca atau dihapus . Kedengarannya jelas sekarang, tetapi ini merupakan cara berpikir yang sangat sulit untuk diterapkan dengan hati-hati.
Setelah semuanya diatur ke dalam sumber daya, saya dapat melampirkan pesan waktu nyata ke model.
Pada API Istirahat, semua membuat, memperbarui, menghapus metode menghasilkan respons hanya kepala, kode HTTP yang menginformasikan keberhasilan atau kegagalan dan data aktual yang didorong melalui soket web.
Di ujung depan, setiap sumber daya ditangani oleh komponen tertentu yang memuatnya melalui HTTP saat inisialisasi, kemudian berlangganan pembaruan dan mempertahankan statusnya dari waktu ke waktu. Tampilan kemudian mengikat komponen tesis ini untuk menampilkan sumber daya dan melakukan tindakan pada sumber daya tersebut melalui komponen yang sama.
Saya menemukan CQRS + Messaging dan Event Sourcing membaca sangat menarik, tetapi merasa itu sedikit rumit untuk masalah saya dan mungkin lebih disesuaikan dengan aplikasi intensif di mana melakukan data ke database terpusat adalah kemewahan yang mahal. Tapi saya pasti akan mengingat pendekatan ini.
Dalam hal ini, aplikasi ini akan memiliki beberapa klien secara bersamaan dan saya mengambil partai dengan mengandalkan banyak pada database. Model yang paling berubah disimpan ke Redis yang saya percaya untuk menangani beberapa ratus pembaruan per detik.
sumber