Pemrograman reaktif java. FRP: Pemrograman Reaktif Fungsional apa adanya. Komponen utama ReaktifCocoa




Seiring waktu, bahasa pemrograman terus berubah dan berkembang karena munculnya teknologi baru, persyaratan modern, atau keinginan sederhana untuk menyegarkan gaya penulisan kode. Pemrograman reaktif dapat diimplementasikan menggunakan berbagai kerangka kerja seperti Kakao Reaktif. Itu mengubah ruang lingkup gaya imperatif dari bahasa Objective-C, dan pendekatan pemrograman ini memiliki banyak hal untuk menawarkan paradigma standar. Hal ini tentu saja menarik perhatian para developer iOS.

ReactiveCocoa menghadirkan gaya deklaratif ke Objective-C. Apa yang kita maksud dengan ini? Gaya imperatif tradisional yang digunakan oleh bahasa seperti C, C++, Objective-C, dan Java, dll. Dapat dijelaskan sebagai berikut: Anda menulis arahan untuk program komputer yang harus dijalankan dengan cara tertentu. Dengan kata lain, Anda mengatakan "bagaimana melakukan" sesuatu. Sementara pemrograman deklaratif memungkinkan Anda menggambarkan aliran kontrol sebagai urutan tindakan, "apa yang harus dilakukan", tanpa menentukan "bagaimana melakukannya".

Pemrograman Imperatif vs Fungsional

Pendekatan imperatif untuk pemrograman melibatkan deskripsi terperinci dari setiap langkah yang harus diambil komputer untuk menyelesaikan tugas. Faktanya, gaya imperatif digunakan dalam bahasa pemrograman asli (atau digunakan saat menulis kode mesin). Ngomong-ngomong, ini adalah fitur karakteristik dari sebagian besar bahasa pemrograman.

Sebaliknya, pendekatan fungsional memecahkan masalah dengan sekumpulan fungsi yang perlu dilakukan. Anda menentukan parameter input untuk setiap fungsi, dan apa yang dikembalikan oleh setiap fungsi. Kedua pendekatan pemrograman ini sangat berbeda.

Berikut adalah perbedaan bahasa utama:

1. Perubahan status

Untuk pemrograman fungsional murni, tidak ada perubahan keadaan karena tidak ada efek samping. Efek samping menyiratkan perubahan keadaan selain nilai pengembalian karena beberapa interaksi eksternal. SR (transparansi referensial) dari subekspresi sering didefinisikan sebagai "tidak adanya efek samping" dan terutama mengacu pada fungsi murni. SP tidak mengizinkan eksekusi fungsi memiliki akses eksternal ke status volatil fungsi, karena setiap subekspresi adalah pemanggilan fungsi menurut definisi.

Untuk memperjelas, fungsi murni memiliki atribut berikut:

  • satu-satunya keluaran penting adalah nilai kembalian
  • satu-satunya ketergantungan parameter input adalah argumen
  • argumen sepenuhnya memenuhi syarat sebelum menghasilkan keluaran apa pun

Terlepas dari kenyataan bahwa pendekatan fungsional meminimalkan efek samping, mereka tidak dapat sepenuhnya dihindari, karena merupakan bagian intrinsik dari setiap pengembangan.

Di sisi lain, fungsi dalam pemrograman imperatif tidak memiliki transparansi referensial, dan ini mungkin satu-satunya perbedaan antara pendekatan deklaratif dan imperatif. Efek samping banyak digunakan untuk mengimplementasikan status dan I/O. Perintah dalam bahasa sumber dapat mengubah status, menghasilkan nilai yang berbeda untuk ekspresi bahasa yang sama.

Bagaimana dengan Kakao Reaktif? Ini adalah kerangka kerja fungsional untuk Objective-C, yang merupakan bahasa imperatif konseptual, tidak termasuk fungsi murni secara eksplisit. Saat mencoba menghindari perubahan keadaan, efek sampingnya tidak terbatas.

2. Objek kelas satu

Dalam pemrograman fungsional, ada objek dan fungsi yang merupakan objek kelas satu. Apa artinya? Ini berarti bahwa fungsi dapat diteruskan sebagai parameter, ditetapkan ke variabel, atau dikembalikan dari suatu fungsi. Mengapa nyaman? Ini membuatnya mudah untuk mengelola blok eksekusi, membuat dan menggabungkan fungsi dalam berbagai cara tanpa kerumitan penunjuk fungsi (char *(*(**foo)()); - selamat bersenang-senang!).

Bahasa yang menggunakan pendekatan imperatif memiliki kekhasan tersendiri sehubungan dengan ekspresi kelas satu. Bagaimana dengan Objective-C? Ini memiliki blok sebagai implementasi penutupan. Fungsi tingkat tinggi (HFO) dapat dimodelkan dengan mengambil blok sebagai parameter. Dalam hal ini, blok adalah penutup, dan fungsi tingkat tinggi dapat dibuat dari sekumpulan blok tertentu.

Namun, proses manipulasi FVP dalam bahasa fungsional lebih cepat dan membutuhkan lebih sedikit baris kode.

3. Kontrol aliran utama

Loop gaya imperatif direpresentasikan sebagai panggilan ke fungsi rekursi dalam pemrograman fungsional. Iterasi dalam bahasa fungsional biasanya dilakukan melalui rekursi. Mengapa? Mungkin demi kerumitan. Untuk pengembang Objective-C, loop tampaknya jauh lebih ramah programmer. Rekursi dapat menyebabkan kesulitan, seperti konsumsi RAM yang berlebihan.

Tetapi! Kita dapat menulis sebuah fungsi tanpa menggunakan perulangan atau rekursi. Untuk setiap tindakan khusus yang tak terbatas yang dapat diterapkan ke setiap elemen koleksi, pemrograman fungsional menggunakan fungsi berulang yang dapat digunakan kembali seperti " peta”, “melipat”, “". Fungsi-fungsi ini berguna untuk memfaktorkan ulang kode sumber. Mereka mengurangi duplikasi dan tidak memerlukan penulisan fungsi terpisah. (baca terus, kami memiliki lebih banyak informasi tentang itu!)

4. Urutan pelaksanaan

Ekspresi deklaratif hanya menampilkan hubungan logis dari argumen fungsi subekspresi dan hubungan status persisten. Jadi dengan tidak adanya efek samping, transisi status dari setiap pemanggilan fungsi terjadi secara independen satu sama lain.

Urutan fungsional eksekusi ekspresi imperatif bergantung pada status volatil. Oleh karena itu, urutan eksekusi penting dan secara implisit ditentukan oleh pengorganisasian kode sumber. Dalam pertanyaan ini, kita dapat menunjukkan perbedaan antara strategi evaluasi dari kedua pendekatan tersebut.

Lazy atau call-by-need evaluasi adalah strategi dalam bahasa pemrograman fungsional. Dalam kasus seperti itu, evaluasi ekspresi ditunda hingga nilainya diperlukan, sehingga kami menghindari evaluasi berulang. Dengan kata lain, ekspresi hanya dievaluasi ketika ekspresi dependen dievaluasi. Urutan operasi menjadi tidak terdefinisi.

Sebaliknya, evaluasi yang kuat dalam bahasa imperatif berarti bahwa ekspresi akan dievaluasi segera setelah terikat pada variabel. Ini menyiratkan mendikte urutan eksekusi, sehingga lebih mudah untuk menentukan kapan subekspresi (termasuk fungsi) akan dievaluasi, karena subekspresi dapat memiliki efek samping yang mempengaruhi evaluasi ekspresi lainnya.

5. Nomor kode

Ini penting, pendekatan fungsional membutuhkan penulisan kode yang lebih sedikit daripada yang penting. Ini berarti lebih sedikit error, lebih sedikit kode untuk diuji, dan siklus pengembangan yang lebih produktif. Karena sistem terus berkembang dan berkembang, ini penting.

Komponen Utama Kakao Reaktif

Pemrograman fungsional berurusan dengan konsep yang dikenal sebagai masa depan (representasi hanya baca dari variabel) dan janji (representasi hanya baca dari variabel masa depan). Apa yang baik tentang mereka? Dalam pemrograman imperatif, Anda harus bekerja dengan nilai yang sudah ada, yang mengarah pada kebutuhan untuk menyinkronkan kode asinkron dan kesulitan lainnya. Tetapi konsep masa depan dan janji memungkinkan Anda untuk bekerja dengan nilai yang belum dibuat (kode asinkron ditulis secara sinkron).


Sinyal

Masa depan dan janji direpresentasikan sebagai sinyal dalam pemrograman reaktif. - komponen utama ReaktifCocoa. Ini memberikan kesempatan untuk menyajikan aliran acara yang akan disajikan di masa depan. Anda berlangganan sinyal dan mendapatkan akses ke acara yang akan terjadi seiring waktu. Sinyal adalah utas yang didorong oleh dorongan dan dapat berupa penekanan tombol, operasi jaringan asinkron, pengatur waktu, peristiwa UI lainnya, atau apa pun yang berubah seiring waktu. Mereka dapat menautkan hasil operasi asinkron dan menggabungkan beberapa sumber peristiwa secara efisien.

Selanjutnya

Jenis aliran lainnya adalah urutan. Tidak seperti sinyal, urutan adalah aliran yang digerakkan oleh tarikan. Ini adalah jenis koleksi yang memiliki tujuan yang sama dengan NSArray. RACSequence memungkinkan operasi tertentu dilakukan saat Anda membutuhkannya, bukan secara berurutan, seperti pada koleksi NSArray. Nilai dalam urutan hanya dievaluasi bila ditentukan secara default. Menggunakan hanya sebagian dari urutan berpotensi meningkatkan kinerja. Urutan RAC memungkinkan koleksi Kakao ditangani dengan cara umum dan deklaratif. RAC menambahkan metode -rac_sequence ke sebagian besar kelas koleksi Kakao sehingga dapat digunakan sebagai Urutan RAC.

Tim

Menanggapi tindakan tertentu, perintah RAC dan berlangganan sinyal. Ini berlaku terutama untuk interaksi UI. Kategori UIkit disediakan oleh ReactiveCocoa untuk sebagian besar kontrol UIkit, beri kami cara yang benar untuk menangani acara UI. Bayangkan kita harus mendaftarkan pengguna sebagai respons terhadap klik tombol. Dalam hal ini, perintah dapat mewakili permintaan jaringan. Saat proses dimulai, tombol mengubah statusnya menjadi "tidak aktif" dan sebaliknya. Apa lagi? Kita dapat mengirimkan sinyal aktif dalam sebuah perintah (Reachability adalah contoh yang bagus). Oleh karena itu, jika server tidak tersedia (yang merupakan "sinyal aktif" kami), maka perintah tidak akan tersedia, dan setiap perintah dari kontrol terkait akan mencerminkan keadaan ini.

Contoh Operasi Dasar

Berikut adalah beberapa diagram tentang cara kerja operasi dasar dengan RACSignals:

Menggabungkan

+ (RACSignal *)gabungkan:(id ) sinyal;


Aliran hasil memiliki kedua aliran peristiwa yang digabungkan menjadi satu. Jadi "+penggabungan" berguna saat Anda tidak peduli dengan sumber acara tertentu, tetapi ingin menanganinya di satu tempat. Dalam contoh kita, stateLabel.text menggunakan 3 sinyal berbeda: penyelesaian, penyelesaian, kesalahan.

RACCommand *loginCommand = [ initWithSignalBlock:^RACSignal *(input id) ( // ayo masuk!)]; RACSignal *executionSignal = ; RACSignal *completionSignal = filter:^BOOL(RACEvent *event) ( return event.eventType == RACEventTypeCompleted; )] map:^id(id value) ( ​​​​return @"Done"; )]; )]; RACSignal *errorSignal = ; RAC(self.stateLabel, text) = ];

+ (RACSignal *)gabungkan Terbaru:(id )sinyal berkurang:(id (^)())reduceBlock;

Hasilnya, aliran tersebut berisi nilai terbaru dari aliran yang sedang dikirim. Jika salah satu aliran tidak penting, maka hasilnya akan kosong.


Kapan kita bisa menggunakannya? Mari ambil contoh kita sebelumnya dan tambahkan lebih banyak logika ke dalamnya. Mengaktifkan tombol login hanya berguna jika pengguna telah memasukkan email dan kata sandi yang benar, bukan? Kita dapat mendeklarasikan aturan ini seperti ini:

ACSignal *enabledSignal = kurangi:^id (NSString *email, NSString *kata sandi) ( kembalikan @( && kata sandi.panjang > 3); )]);

* Sekarang mari kita ubah sedikit perintah login kita dan kaitkan ke tombol login yang sebenarnya

RACCommand *loginCommand = [ initWithEnabled:enabledSignal signalBlock:^RACSignal *(masukan id) ( // ayo masuk! )]; ;

- (RACSignal *)flattenMap:(RACStream * (^)(nilai id))blok;

Anda membuat aliran baru untuk setiap nilai dalam aliran asli menggunakan fungsi yang diberikan (f). Aliran hasil mengembalikan sinyal baru berdasarkan nilai yang dihasilkan di aliran asli. Jadi bisa asinkron.


Bayangkan permintaan otorisasi Anda ke sistem terdiri dari dua bagian terpisah: dapatkan data dari Facebook (ID, dll.) dan berikan ke Backend. Salah satu syaratnya adalah bisa membatalkan login. Oleh karena itu, kode klien harus menangani status proses login agar dapat membatalkannya. Ini memberikan banyak kode boilerplate, terutama jika Anda dapat masuk dari berbagai lokasi.

Bagaimana ReaktifCocoa membantu Anda? Ini bisa menjadi implementasi login:

- (RACSignal *)otorisasiMenggunakanFacebook ( return [[ flattenMap:^RACStream *(FBSession *session) ( return ; )] flattenMap:^RACStream *(NSDictionary *profile) ( return ; )]; )

legenda:

+ - sinyal yang mengarah ke pembukaan FBSession. Jika perlu, ini dapat menyebabkan masuk ke Facebook.

- - sinyal yang mengambil data profil melalui sesi, yang ditransmisikan sebagai diri sendiri.

Keuntungan dari pendekatan ini adalah bagi pengguna, seluruh aliran bersifat fuzzy, diwakili oleh satu sinyal yang dapat dibatalkan pada "tahap" apa pun, baik itu login Facebook atau panggilan Backend.

Saring

- (RACSignal *)filter:(BOOL (^)(nilai id))blok;

Hasilnya, aliran tersebut berisi nilai aliran "a", yang difilter sesuai dengan fungsi yang diberikan.


RACSequence *urutan = @[@"Beberapa", @"contoh", @"dari", @"urutan"].rac_sequence; RACSequence *filteredSequence = ; )]);

Peta

- (RACSignal *)peta:(id (^)(nilai id))blok;

Tidak seperti FlattenMap, Peta berjalan serentak. Nilai properti "a" melewati fungsi yang diberikan f (x + 1) dan mengembalikan nilai asli yang dipetakan.


Katakanlah Anda ingin memasukkan judul model di layar, menerapkan beberapa atribut padanya. Peta berperan saat "Menerapkan beberapa atribut" dideskripsikan sebagai fungsi mandiri:

RAC(self.titleLabel, teks) = initWithString:modelTitle atribut:atribut]; )]);

Cara kerjanya: bersatu self.titleLabel.text dengan perubahan model.title dengan menerapkan atribut khusus padanya.

Ritsleting

+ (RACSignal *)zip:(id )streaming berkurang:(id (^)())reduceBlock;

Hasil aliran peristiwa dihasilkan ketika masing-masing aliran telah menghasilkan jumlah peristiwa yang sama. Ini berisi nilai, satu dari masing-masing dari 3 aliran gabungan.


Untuk beberapa contoh praktis, zip dapat digambarkan sebagai dispatch_group_notify Misalnya, Anda memiliki 3 sinyal terpisah dan ingin menggabungkan tanggapannya pada satu titik:

NSArray *sinyal = @; kembali;

- (RACSignal *)throttle:(NSTimeInterval)interval;

Dengan pengatur waktu yang disetel untuk jangka waktu tertentu, nilai pertama aliran "a" hanya diteruskan ke aliran hasil saat pengatur waktu berakhir. Jika nilai baru dihasilkan dalam interval waktu tertentu, nilai pertama akan disimpan, mencegahnya diteruskan ke aliran hasil. Sebagai gantinya, nilai kedua muncul di aliran hasil.


Kasus yang mengejutkan: kita perlu mencari kueri saat pengguna mengubah kolom pencarian. Masalah standar, kan? Namun, ini tidak terlalu efisien untuk membangun dan mengirim permintaan jaringan setiap kali teks berubah, karena textField dapat menghasilkan banyak kejadian seperti itu per detik, dan Anda berakhir dengan penggunaan jaringan yang tidak efisien.
Solusinya di sini adalah menambahkan penundaan setelah itu kami benar-benar membuat permintaan jaringan. Ini biasanya dicapai dengan menambahkan NSTimer. Dengan ReactiveCocoa jauh lebih mudah!

[[ throttle:0.3] berlanggananBerikutnya:^(NSString *teks) ( // melakukan permintaan jaringan )];

* Catatan penting di sini adalah bahwa semua bidang teks "sebelumnya" dimodifikasi sebelum yang "terakhir" dihapus.

Penundaan

- (RACSignal *)penundaan:(NSTimeInterval)interval;

Nilai yang diterima dalam aliran "a" ditunda dan ditransfer ke aliran hasil setelah selang waktu tertentu.


Seperti -, penundaan hanya akan menunda pengiriman acara "berikutnya" dan "selesai".

[berlanggananBerikutnya:^(NSString *teks) ( )];

Apa yang kami sukai dari Kakao Reaktif

  • Memperkenalkan Cocoa Bindings ke iOS
  • Kemampuan untuk membuat operasi pada data masa depan. Berikut adalah beberapa teori tentang masa depan & janji dari Scala.
  • Kemampuan untuk merepresentasikan operasi asinkron dengan cara yang sinkron. Kakao Reaktif menyederhanakan perangkat lunak asinkron seperti kode jaringan.
  • Dekomposisi yang nyaman. Kode yang berhubungan dengan peristiwa pengguna dan perubahan status aplikasi bisa menjadi sangat rumit dan membingungkan. Kakao Reaktif membuat model operasi ketergantungan sangat sederhana. Saat kami merepresentasikan operasi sebagai utas gabungan (mis., pemrosesan permintaan jaringan, aktivitas pengguna, dll.), kami dapat mencapai modularitas tinggi dan sambungan longgar, yang menghasilkan lebih banyak penggunaan kembali kode.
  • Perilaku dan hubungan antar properti didefinisikan sebagai deklaratif.
  • Memecahkan masalah sinkronisasi - jika Anda menggabungkan beberapa sinyal maka ada satu tempat tunggal untuk menangani semua hasil (apakah nilai selanjutnya, penyelesaian atau sinyal kesalahan)

Dengan kerangka kerja RAC, Anda dapat membuat dan mengubah urutan nilai dengan cara yang lebih baik dan lebih tinggi. RAC membuatnya lebih mudah untuk mengelola semua yang menunggu operasi asinkron selesai: respons jaringan, perubahan nilai dependen, dan reaksi selanjutnya. Sulit untuk ditangani pada pandangan pertama, tetapi ReaktifCocoa menular!

Periksa informasi. Penting untuk memeriksa keakuratan fakta dan keandalan informasi yang disajikan dalam artikel ini. Seharusnya ada penjelasan di halaman pembicaraan ... Wikipedia

Interaktivitas adalah konsep yang mengungkapkan sifat dan tingkat interaksi antar objek. Digunakan di berbagai bidang: teori informasi, ilmu komputer dan pemrograman, sistem telekomunikasi, sosiologi, desain industri dan lain-lain. Di ... ... Wikipedia

Artikel ini harus di-wikifikasi. Silahkan format sesuai aturan format artikel. Istilah ini memiliki arti lain, lihat Electromash (makna) ... Wikipedia

teknik psikoterapi asing- TEKNIK DALAM Psikoterapi aktif (Fromm Reichmann). Analisis keberadaan (Binswanger). Analisis nasib (Sondi). Analisis karakter (W. Reich). Analisis I (H. Kohut, E. Erickson). Terapi permainan analitik (M. Klein). Terapi Analitik Keluarga (Richter).… … Ensiklopedia Psikologi Hebat

Buku

  • Pemrograman reaktif dalam C++. Merancang Aplikasi Paralel dan Asinkron, Pai Praseed, Abraham Peter. Merancang aplikasi paralel dan asinkron menggunakan library RxCpp dan C++ modern 17 Alat pemrograman paralel yang didukung Kolaborasi…
  • , Nurkevich T., Christensen B.. Saat ini, ketika program tidak sinkron, dan respons cepat adalah properti terpenting, pemrograman reaktif akan membantu menulis kode yang lebih andal, lebih terukur, dan lebih cepat.…
  • Pemrograman Reaktif dengan RxJava, Tomas Nurkevich, Ben Christensen. Saat ini, ketika program tidak sinkron dan respons cepat adalah properti terpenting, pemrograman reaktif akan membantu Anda menulis kode yang lebih andal, lebih terukur, dan lebih cepat.…

Dunia pengembangan OOP pada umumnya dan bahasa Jawa pada khususnya menjalani kehidupan yang sangat aktif. Ini memiliki tren fesyennya sendiri, dan hari ini kami akan menganalisis salah satu tren utama musim ini - kerangka kerja ReactiveX. Jika Anda masih menyendiri dari gelombang ini - saya jamin Anda akan menyukainya! Ini pasti lebih baik daripada jeans berpinggang tinggi :).

Pemrograman reaktif

Segera setelah bahasa OOP matang untuk digunakan secara massal, pengembang menyadari betapa kemampuan bahasa mirip-C terkadang kurang. Karena menulis kode dengan gaya pemrograman fungsional secara serius merusak kualitas kode OOP, dan karenanya pemeliharaan proyek, sebuah hibrida ditemukan - pemrograman reaktif.

Paradigma pengembangan reaktif didasarkan pada gagasan untuk terus melacak perubahan keadaan suatu objek. Jika perubahan seperti itu telah terjadi, maka semua objek yang tertarik harus menerima data yang sudah diperbarui dan hanya bekerja dengannya, melupakan yang lama.

Contoh bagus dari ide pemrograman reaktif adalah spreadsheet Excel. Jika Anda menautkan beberapa sel dengan satu rumus, hasil penghitungan akan berubah setiap kali data dalam sel tersebut berubah. Untuk akuntansi, perubahan data yang dinamis seperti itu adalah hal yang umum, tetapi bagi pemrogram ini merupakan pengecualian.

A=3; b=4; c=a+b; F1(c); a=1; F2(c);

Dalam contoh ini, fungsi F1 dan F2 akan bekerja dengan nilai yang berbeda dari variabel C. Seringkali kedua fungsi tersebut hanya membutuhkan data terbaru - pemrograman reaktif akan memungkinkan Anda untuk segera memanggil F1 dengan yang baru parameter tanpa mengubah logika fungsi itu sendiri. Struktur kode ini memberi aplikasi kemampuan untuk merespons perubahan apa pun secara instan, yang akan membuatnya cepat, fleksibel, dan responsif.

ReaktifX

Menerapkan ide-ide pemrograman reaktif dari awal bisa sangat merepotkan - ada jebakan, dan itu akan memakan waktu yang cukup lama. Oleh karena itu, bagi banyak pengembang, paradigma ini hanya menjadi bahan teoretis hingga ReactiveX muncul.

Kerangka kerja ReactiveX adalah alat pemrograman reaktif yang bekerja dengan semua bahasa OOP populer. Pembuatnya sendiri menyebutnya API multi-platform untuk pengembangan asinkron, berdasarkan pola Pengamat.

Jika istilah "pemrograman reaktif" adalah sejenis model teoretis, maka pola Pengamat adalah mekanisme siap pakai untuk melacak perubahan dalam suatu program. Dan Anda harus cukup sering melacaknya: memuat dan memperbarui data, pemberitahuan acara, dan sebagainya.

Pola Pengamat telah ada selama OOP itu sendiri. Objek yang statusnya dapat berubah disebut penerbit (terjemahan populer dari istilah Observable). Semua peserta lain yang tertarik dengan perubahan ini adalah pelanggan (Pengamat, Pelanggan). Untuk menerima notifikasi, pelanggan mendaftar ke penerbit dengan secara eksplisit menentukan ID mereka. Penerbit dari waktu ke waktu menghasilkan notifikasi, yang dikirim oleh penerbit ke daftar pelanggan terdaftar.

Sebenarnya, pembuat ReactiveX tidak menghasilkan sesuatu yang revolusioner, mereka hanya menerapkan polanya dengan nyaman. Dan meskipun banyak bahasa OOP, dan khususnya Java, memiliki implementasi pola yang sudah jadi, kerangka kerja ini memiliki "penyetelan" tambahan yang mengubah "Pengamat" menjadi alat yang sangat kuat.

RxAndroid

Porta perpustakaan ReactiveX untuk dunia Android disebut rxAndroid dan terhubung, seperti biasa, melalui Gradle.

Kompilasi "io.reactivex:rxandroid:1.1.0"

Penerbit yang menghasilkan notifikasi ditentukan di sini menggunakan kelas Observable. Penerbit dapat memiliki beberapa pelanggan, untuk mengimplementasikannya, kami akan menggunakan kelas Pelanggan. Perilaku default untuk Observable adalah mengeluarkan satu atau beberapa pesan ke pelanggan dan kemudian keluar atau mengeluarkan pesan kesalahan. Pesan dapat berupa variabel dan objek bilangan bulat.

Rx.Observable myObserv = rx.Observable.create(baru rx.Observable.OnSubscribe () ( @Override public void call(Subscriberpelanggan) ( pelanggan.onNext("Halo"); pelanggan.onNext("dunia"); pelanggan.onSelesai(); ) ));

Dalam hal ini, penerbit myObserv pertama-tama akan mengirimkan string halo dan pesan, lalu pesan sukses. Penayang dapat memanggil metode onNext() , onCompleted() , dan onEror() , sehingga pelanggan harus menentukannya.

Pelanggan mySub = Pelanggan baru () (... @Override public void onNext(Nilai string) (Log.e("dapatkan data", " " + nilai);) );

Semuanya siap untuk bekerja. Tetap menghubungkan objek satu sama lain - dan "Halo, dunia!" dalam pemrograman reaktif sudah siap!

MyObserv.subscribe(mySub);

Saya harus mengatakan bahwa ini adalah contoh yang sangat sederhana. ReactiveX memiliki banyak opsi untuk perilaku semua peserta dalam pola: pemfilteran, pengelompokan, penanganan kesalahan. Manfaat pemrograman reaktif hanya bisa dirasakan dengan mencobanya dalam tindakan. Mari kita mulai tugas dengan lebih serius.

Terus tersedia untuk anggota saja

Opsi 1. Bergabunglah dengan komunitas "situs" untuk membaca semua materi di situs

Keanggotaan dalam komunitas selama periode yang ditentukan akan memberi Anda akses ke SEMUA materi Peretas, meningkatkan diskon kumulatif pribadi Anda, dan memungkinkan Anda mengumpulkan peringkat Skor Xakep profesional!

Pergi.

Pemrograman reaktif pada awalnya terdengar seperti nama paradigma yang baru lahir, tetapi sebenarnya mengacu pada metode pemrograman yang menggunakan pendekatan berbasis peristiwa untuk bekerja dengan aliran data asinkron. Berdasarkan data yang terus-menerus terkini, sistem reaktif bereaksi terhadapnya dengan menjalankan serangkaian peristiwa.
Pemrograman reaktif mengikuti pola desain Pengamat, yang dapat didefinisikan sebagai berikut: jika perubahan status terjadi pada satu objek, maka semua objek lainnya akan diberi tahu dan diperbarui sesuai dengan itu. Jadi, alih-alih polling peristiwa untuk perubahan, peristiwa didorong secara asinkron sehingga pengamat dapat memprosesnya. Dalam contoh ini, pengamat adalah fungsi yang dijalankan saat suatu peristiwa dikirimkan. Dan aliran data yang disebutkan adalah yang sebenarnya dapat diamati.

Hampir semua bahasa dan kerangka kerja menggunakan pendekatan ini dalam ekosistemnya, dan versi terbaru Java tidak terkecuali. Pada artikel ini, saya akan menjelaskan bagaimana pemrograman reaktif dapat diterapkan menggunakan JAX-RS versi terbaru di fungsionalitas Java EE 8 dan Java 8.

Manifesto Reaktif

Manifesto Reaktif mencantumkan empat aspek mendasar yang diperlukan aplikasi agar lebih fleksibel, digabungkan secara longgar, dan mudah untuk diskalakan, dan karenanya dapat menjadi reaktif. Dikatakan bahwa aplikasi harus responsif, fleksibel (dan karenanya dapat diskalakan), tangguh, dan digerakkan oleh pesan.

Tujuan yang mendasarinya adalah aplikasi yang benar-benar responsif. Katakanlah Anda memiliki aplikasi yang memiliki satu utas besar yang memproses permintaan pengguna, dan saat pekerjaan selesai, utas tersebut mengirimkan respons kembali ke pemohon asli. Saat aplikasi menerima lebih banyak permintaan daripada yang dapat ditanganinya, alur ini menjadi hambatan dan aplikasi kehilangan daya tanggap sebelumnya. Agar tetap responsif, aplikasi harus dapat diskalakan dan tangguh. Aplikasi tangguh adalah aplikasi yang memiliki fungsi pemulihan otomatis. Dalam pengalaman sebagian besar pengembang, hanya arsitektur berbasis pesan yang memungkinkan aplikasi untuk dapat diskalakan, kuat, dan responsif.

Pemrograman reaktif diperkenalkan di Java 8 dan Java EE 8. Bahasa Java memperkenalkan konsep seperti CompletionStage dan implementasi CompletableFuture, dan Java mulai menggunakan fitur ini dalam spesifikasi seperti API Klien Reaktif di JAX-RS.

JAX-RS 2.1 API Klien Reaktif

Mari kita lihat bagaimana pemrograman reaktif dapat digunakan dalam aplikasi Java EE 8. Untuk memahami prosesnya, Anda memerlukan pengetahuan dasar tentang Java EE API.

JAX-RS 2.1 memperkenalkan cara baru untuk membuat klien REST reaktif. Implementasi default dari invoker yang ditawarkan oleh JAX-RS adalah sinkron, yang berarti bahwa klien yang sedang dibuat akan mengirimkan panggilan pemblokiran ke titik akhir server. Contoh implementasi disediakan di Listing 1.

Tanggapan tanggapan = ClientBuilder.newClient() .target("http://localhost:8080/service-url") .request() .get();
Dimulai dengan versi 2.0, JAX-RS menyediakan dukungan untuk membuat invoker asinkron pada API klien dengan panggilan sederhana ke metode async(), seperti yang ditunjukkan pada Listing 2.

Masa depan respon = ClientBuilder.newClient() .target("http://localhost:8080/service-url") .request() .async() .get();
Menggunakan invoker asinkron pada klien mengembalikan instance Future dari tipe javax.ws.rs.core.Response . Hal ini dapat menghasilkan polling untuk respons, memanggil future.get() , atau mendaftarkan callback yang akan dipanggil saat ada respons HTTP yang tersedia. Kedua implementasi cocok untuk pemrograman asinkron, tetapi hal-hal cenderung menjadi lebih rumit jika Anda ingin mengelompokkan panggilan balik atau menambahkan kasus bersyarat ke minima eksekusi asinkron tersebut.

JAX-RS 2.1 menyediakan cara reaktif untuk mengatasi masalah ini dengan API Klien Reaktif JAX-RS baru untuk rakitan klien. Sesederhana memanggil metode rx() selama pembuatan klien. Di Listing 3, metode rx() mengembalikan invoker reaktif yang ada selama eksekusi klien, dan klien mengembalikan respons dengan tipe CompletionStage.rx() , yang memungkinkan transisi dari invoker sinkron ke invoker asinkron dengan sederhana panggilan.

Tahap Penyelesaian respon = ClientBuilder.newClient() .target("http://localhost:8080/service-url") .request() .rx() .get();
Tahap Penyelesaian<Т>adalah antarmuka baru yang diperkenalkan di Java 8. Ini merupakan perhitungan, yang bisa menjadi langkah dalam perhitungan yang lebih besar, seperti namanya. Ini adalah satu-satunya reaktivitas Java 8 yang membuatnya menjadi JAX-RS.
Setelah menerima instance respons, saya dapat memanggil AcceptAsync() , di mana saya dapat memberikan potongan kode yang akan dieksekusi secara asinkron saat respons tersedia, seperti yang ditunjukkan pada Listing 4.

Response.thenAcceptAsync(res -> ( Temperature t = res.readEntity(Temperature.class); //lakukan sesuatu dengan t ));
Menambahkan reaktivitas ke titik akhir REST

Pendekatan reaktif tidak terbatas pada sisi klien di JAX-RS; itu dapat digunakan di sisi server juga. Sebagai contoh, pertama-tama saya akan membuat skrip sederhana tempat saya dapat meminta daftar lokasi untuk satu tujuan. Untuk setiap posisi, saya akan melakukan panggilan terpisah dengan data lokasi ke titik lain untuk mendapatkan nilai suhu. Interaksi tujuan akan seperti yang ditunjukkan pada Gambar 1.

Gambar 1. Interaksi antar destinasi

Pertama saya hanya menentukan model domain dan kemudian layanan untuk setiap model. Daftar 5 menunjukkan bagaimana kelas Prakiraan didefinisikan, yang membungkus kelas Lokasi dan Suhu.

Kelas publik Suhu ( suhu Ganda pribadi; skala String pribadi; // getter & setter ) Lokasi kelas publik ( Nama string; Lokasi publik() () Lokasi publik(Nama string) ( this.name = nama; ) // getter & setter ) Prakiraan kelas publik ( lokasi Lokasi pribadi; Suhu suhu pribadi; Prakiraan publik(Lokasi lokasi) ( this.location = lokasi; ) Prakiraan publik setTemperature(Suhu akhir suhu) ( this.temperature = suhu; kembalikan ini; ) // getter )
Untuk membungkus daftar prediksi, kelas ServiceResponse diimplementasikan di Listing 6.

ServiceResponse kelas publik (waktu pemrosesan panjang pribadi; Daftar pribadi perkiraan = ArrayList baru<>(); public void setProcessingTime(long processingTime) ( this.processingTime = processingTime; ) perkiraan ServiceResponse publik (Daftar forecasts) ( this.forecasts = forecasts; return this; ) // getter )
LocationResource , ditunjukkan pada Listing 7, mendefinisikan tiga pola lokasi yang dikembalikan dengan path /location .

@Path("/location") kelas publik LocationResource ( @GET @Produces(MediaType.APPLICATION_JSON) respons publik getLocations() ( Daftar lokasi = ArrayList baru<>(); lokasi.tambahkan(Lokasi baru ("London")); lokasi.tambahkan(lokasi baru("Istanbul")); lokasi.tambahkan(lokasi baru("Praha")); return Response.ok(new GenericEntity >(lokasi)()).bangun(); ) )
TemperatureResource , ditampilkan di Listing 8, mengembalikan nilai suhu yang dihasilkan secara acak antara 30 dan 50 untuk lokasi tertentu. Penundaan 500ms telah ditambahkan ke implementasi untuk mensimulasikan pembacaan sensor.

@Path("/temperature") kelas publik TemperatureResource ( @GET @Path("/(city)") @Produces(MediaType.APPLICATION_JSON) Public Response getAverageTemperature(@PathParam("city") String cityName) ( Suhu suhu = baru Temperature(); temperature.setTemperature((double) (new Random().nextInt(20) + 30)); temperature.setScale("Celsius"); try ( Thread.sleep(500); ) catch (InterruptedException diabaikan) ( diabaikan.printStackTrace(); ) mengembalikan Response.ok(temperature).build(); ) )
Pertama, saya akan menunjukkan implementasi ForecastResource sinkron (lihat Listing 9) yang mengembalikan semua lokasi. Kemudian untuk setiap posisi memanggil layanan suhu untuk mendapatkan nilai dalam derajat Celcius.

@Path("/forecast") kelas publik ForecastResource ( @Uri("location") private WebTarget locationTarget; @Uri("temperature/(city)") private WebTarget temperatureTarget; @GET @Produces(MediaType.APPLICATION_JSON) public Response getLocationsWithTemperature () ( long startTime = System.currentTimeMillis(); ServiceResponse response = new ServiceResponse(); Daftar lokasi = locationTarget .request() .get(new GenericType >()()); forEach(location -> ( Temperature temperature = temperatureTarget .resolveTemplate("city", location.getName()) .request() .get(Temperature.class); response.getForecasts().add(new Forecast(location) .setTemperature (suhu)); )); long endTime = System.currentTimeMillis(); response.setProcessingTime(endTime - startTime); return Response.ok(respons).build(); ) )
Ketika perkiraan tujuan diminta sebagai /forecast , Anda akan mendapatkan output yang mirip dengan Listing 10. Perhatikan bahwa permintaan memerlukan waktu 1,533 md untuk diproses, yang logis karena meminta suhu dari tiga lokasi berbeda secara bersamaan menambahkan hingga 1,5 md.

( "prakiraan": [ ("lokasi": ("nama": "London" ), "suhu": ("skala": "Celcius", "suhu": 33 ) ), ("lokasi": ("nama ": "Istanbul" ), "suhu": ( "skala": "Celcius", "suhu": 38) ), ( "lokasi": ( "nama": "Praha" ), "suhu": ( "skala ": "Celsius", "temperature": 46 ) ], "processingTime": 1533 )
Sejauh ini semuanya berjalan sesuai rencana. Saatnya memperkenalkan pemrograman reaktif di sisi server, di mana panggilan ke setiap lokasi dapat dilakukan secara paralel setelah semua lokasi diterima. Ini jelas dapat meningkatkan aliran sinkron yang ditunjukkan sebelumnya. Ini dilakukan di Listing 11, yang menunjukkan definisi versi reaktif dari layanan prakiraan.

@Path("/reactiveForecast") kelas publik ForecastReactiveResource ( @Uri("location") private WebTarget locationTarget; @Uri("temperature/(city)") private WebTarget temperatureTarget; @GET @Produces(MediaType.APPLICATION_JSON) public void getLocationsWithTemperature (@Suspended final AsyncResponse async) ( long startTime = System.currentTimeMillis(); // Buat stage untuk mengambil lokasi CompletionStage > locationCS = locationTarget.request() .rx() .get(new GenericType >() ()); // Dengan membuat tahap terpisah di tahap lokasi, // dijelaskan di atas, kumpulkan daftar prediksi // seperti dalam satu Tahap Penyelesaian Akhir Tahap Penyelesaian yang besar > forecastCS = locationCS.thenCompose(locations -> ( // Buat tahapan untuk mendapatkan perkiraan // sebagai Daftar Tahap Penyelesaian > forecastList = // Alirkan lokasi dan proses masing-masing // lokasi terpisah.stream().map(location -> ( // Buat langkah untuk mendapatkan // nilai suhu hanya satu kota // dengan namanya Final CompletionStage tempCS = temperatureTarget .resolveTemplate("city", location.getName()) .request() .rx() .get(Temperature.class); // Kemudian buat CompletableFuture yang // berisi instance perkiraan dengan // lokasi dan nilai suhu return CompletableFuture.completedFuture(new Forecast(location)) .thenCombine(tempCS, Forecast::setTemperature); )).collect(Collectors.toList()); // Mengembalikan instance CompletableFuture final di mana // semua objek masa depan yang dapat diselesaikan // selesai // selesai return CompletableFuture.allOf(forecastList.toArray(CompletableFuture baru)) .thenApply(v -> forecastList.stream() .map(CompletionStage::toCompletableFuture ) .map(CompletableFuture::join) .collect(Collectors.toList())); )); // Buat instance ServiceResponse yang // berisi daftar lengkap prediksi // bersama dengan waktu pemrosesan. // Buat masa depannya dan gabungkan dengan // forecastCS untuk mendapatkan perkiraan // dan masukkan ke respons layanan CompletableFuture.completedFuture(new ServiceResponse()) .thenCombine(forecastCS, ServiceResponse::forecasts) .whenCompleteAsync((respons, dapat dibuang) - > ( response.setProcessingTime(System.currentTimeMillis() - startTime); async.resume(response); )); ) )
Implementasi reaktif mungkin tampak rumit pada pandangan pertama, tetapi setelah melihat lebih dekat, Anda akan melihat bahwa ini cukup sederhana. Dalam implementasi ForecastReactiveResource, pertama-tama saya melakukan panggilan klien ke layanan lokasi menggunakan API Klien Reaktif JAX-RS. Seperti yang saya sebutkan di atas, ini adalah tambahan untuk Java EE 8 dan membantu membuat panggilan reaktif hanya dengan metode rx().

Sekarang saya sedang membuat tahap baru berdasarkan lokasi untuk mengumpulkan daftar prediksi. Mereka akan disimpan sebagai daftar prakiraan dalam satu tahap penyelesaian besar yang disebut forecastCS . Pada akhirnya, saya akan membuat respons panggilan layanan hanya menggunakan forecastCS .

Sekarang mari kumpulkan perkiraan sebagai daftar tahapan penyelesaian yang ditentukan dalam variabel forecastList . Untuk membuat tahap penyelesaian untuk setiap prakiraan, saya mengirimkan data lokasi dan kemudian membuat variabel tempCS, sekali lagi menggunakan API Klien Reaktif JAX-RS, yang memanggil layanan suhu dengan nama kota. Di sini, saya menggunakan metode resolveTemplate() untuk membangun klien, dan ini memungkinkan saya meneruskan nama kota ke pembangun sebagai parameter.

Sebagai langkah terakhir streaming, saya memanggil CompletableFuture.completedFuture() , meneruskan instance Forecast baru sebagai parameter. Saya menggabungkan masa depan ini dengan tahap tempCS sehingga saya memiliki nilai suhu untuk lokasi yang diulang.

Metode CompletableFuture.allOf() di Listing 11 mengubah daftar tahapan penyelesaian menjadi forecastCS . Menjalankan langkah ini mengembalikan masa depan besar yang dapat diselesaikan ketika semua masa depan yang dapat diselesaikan yang disediakan telah selesai.

Respons layanan adalah turunan dari kelas ServiceResponse, jadi saya membuat masa depan yang lengkap dan kemudian menggabungkan tahap penyelesaian forecastCS dengan daftar perkiraan dan menghitung waktu respons layanan.

Tentu saja, pemrograman reaktif hanya memaksa sisi server untuk mengeksekusi secara asinkron; sisi klien akan memblokir sampai server mengirimkan tanggapan kembali ke pemohon. Untuk mengatasi masalah ini, Server Sent Events (SSEs) dapat digunakan untuk mengirimkan respons parsial segera setelah tersedia, sehingga nilai suhu untuk setiap lokasi dikirim ke klien satu per satu. Output dari ForecastReactiveResource akan mirip dengan Listing 12. Seperti yang ditunjukkan pada output, waktu pemrosesan adalah 515ms, yang merupakan waktu eksekusi ideal untuk mendapatkan nilai suhu dari satu lokasi.

( "prakiraan": [ ("lokasi": ("nama": "London" ), "suhu": ("skala": "Celcius", "suhu": 49 ) ), ("lokasi": ("nama ": "Istanbul" ), "suhu": ( "skala": "Celcius", "suhu": 32 ) ), ( "lokasi": ( "nama": "Praha" ), "suhu": ( "skala ": "Celsius", "temperature": 45 ) ], "processingTime": 515 )
Kesimpulan

Dalam contoh di artikel ini, saya pertama kali menunjukkan cara sinkron untuk mendapatkan prakiraan menggunakan layanan lokasi dan suhu. Kemudian, saya beralih ke pendekatan reaktif agar pemrosesan asinkron dilakukan di antara panggilan layanan. Saat Anda menggunakan API Klien Reaktif JAX-RS di Java EE 8 bersama dengan kelas CompletionStage dan CompletableFuture yang tersedia di Java 8, kekuatan pemrosesan asinkron dilepaskan melalui pemrograman reaktif.

Pemrograman reaktif lebih dari sekadar mengimplementasikan model asinkron dari model sinkron; itu juga menyederhanakan konsep seperti tahap bersarang. Semakin banyak digunakan, semakin mudah mengelola skenario kompleks dalam pemrograman paralel.

Terima kasih atas perhatian Anda. Seperti biasa, kami menyambut komentar dan pertanyaan Anda.

Anda dapat membantu dan mentransfer sejumlah dana untuk pengembangan situs

Saya ingin memberi tahu Anda tentang disiplin pemrograman modern yang memenuhi tuntutan yang berkembang untuk skalabilitas, toleransi kesalahan, dan respons cepat, dan sangat diperlukan di lingkungan multi-core dan komputasi awan, serta menyajikan kursus online terbuka tentangnya, yang akan dimulai hanya dalam beberapa hari.

Jika Anda belum pernah mendengar apa pun tentang pemrograman reaktif, Anda siap melakukannya. Ini adalah disiplin yang berkembang pesat yang menggabungkan konkurensi dengan event-driven dan asinkron. Reaktivitas melekat dalam layanan web dan sistem terdistribusi apa pun, dan merupakan inti dari banyak sistem berkinerja tinggi dengan tingkat paralelisme yang tinggi. Singkatnya, penulis kursus mengusulkan untuk mempertimbangkan pemrograman reaktif sebagai perpanjangan alami dari pemrograman fungsional (dengan fungsi tingkat tinggi) ke sistem paralel dengan keadaan terdistribusi, dikoordinasikan dan diatur oleh aliran data asinkron yang dipertukarkan oleh subjek aktif, atau aktor.

Dengan kata-kata yang lebih mudah dipahami, ini dijelaskan dalam Reactive Manifesto, di bawah ini saya akan menceritakan kembali ketentuan utama darinya, dan terjemahan lengkapnya diterbitkan di Habré. Seperti kata Wikipedia, istilahnya pemrograman reaktif telah ada sejak lama dan memiliki aplikasi praktis dari berbagai tingkat eksotisme, tetapi baru-baru ini menerima dorongan baru untuk pengembangan dan distribusi, berkat upaya penulis Reactive Manifesto, sebuah kelompok inisiatif dari Typesafe Inc. Typesafe dikenal di komunitas pemrograman fungsional sebagai perusahaan yang didirikan oleh penulis bahasa Scala yang luar biasa dan platform paralel revolusioner Akka. Sekarang mereka memposisikan perusahaan mereka sebagai pencipta platform jet pertama di dunia yang dirancang untuk mengembangkan generasi baru. Platform mereka memungkinkan pengembangan yang cepat dari antarmuka pengguna yang kompleks dan memberikan tingkat abstraksi baru melalui komputasi paralel dan multithreading, mengurangi risiko bawaannya dengan penskalaan yang dijamin dapat diprediksi. Ini mempraktikkan ide-ide Manifesto Reaktif dan memungkinkan pengembang untuk memahami dan membuat aplikasi yang memenuhi kebutuhan saat ini.

Anda dapat mengenal platform ini dan pemrograman reaktif dengan mengikuti Kursus Daring Terbuka Masif Prinsip Reaktif. Kursus ini merupakan kelanjutan dari kursus "Principles of Functional Programming in Scala" dari Martin Odersky, yang telah diikuti oleh lebih dari 100.000 peserta dan menunjukkan salah satu tingkat keberhasilan tertinggi untuk Kursus Daring Terbuka Masif oleh para pesertanya di dunia. Bersama pencipta bahasa Scala, kursus baru ini diajarkan oleh Eric Meyer, yang mengembangkan kerangka kerja Rx untuk pemrograman reaktif di bawah .NET, dan Roland Kuhn, yang saat ini memimpin tim pengembangan Akka di Typesafe. Kursus ini mencakup elemen kunci dari pemrograman reaktif dan menunjukkan bagaimana penerapannya untuk merancang sistem berbasis kejadian yang dapat diskalakan dan toleran terhadap kesalahan. Materi pelatihan diilustrasikan dengan program-program pendek dan disertai dengan serangkaian tugas yang masing-masing merupakan proyek perangkat lunak. Jika berhasil menyelesaikan semua tugas, peserta menerima sertifikat (tentu saja, partisipasi dan sertifikat gratis). Kursus berlangsung 7 minggu dan dimulai Senin ini, 4 November. Garis besar terperinci serta video pengantar tersedia di halaman kursus: https://www.coursera.org/course/reactive.

Bagi mereka yang tertarik atau ragu, saya menawarkan ringkasan singkat tentang konsep dasar Manifesto Reaktif. Penulisnya mencatat perubahan signifikan dalam persyaratan aplikasi dalam beberapa tahun terakhir. Saat ini, aplikasi diterapkan di lingkungan apa pun dari perangkat seluler hingga kluster cloud dengan ribuan prosesor multi-core. Lingkungan ini menempatkan tuntutan baru pada perangkat lunak dan teknologi. Arsitektur generasi sebelumnya berfokus pada server dan wadah terkelola, penskalaan melalui perangkat keras tambahan yang mahal, solusi berpemilik, dan komputasi paralel melalui multithreading. Sebuah arsitektur baru sedang dikembangkan yang memiliki empat fitur utama yang semakin lazim di lingkungan industri konsumen dan perusahaan. Sistem dengan arsitektur ini bersifat: event-driven, scalable, fault-tolerant (Resilient) dan memiliki respon yang cepat, yaitu. responsif (Responsif). Hal ini memberikan pengalaman pengguna yang lancar dan real-time yang didukung oleh tumpukan aplikasi yang dapat menyembuhkan sendiri dan dapat diskalakan yang siap diterapkan di lingkungan multi-core dan cloud. Masing-masing dari empat karakteristik arsitektur reaktif berlaku untuk seluruh tumpukan teknologi, yang membedakannya dari tautan dalam arsitektur berlapis. Mari kita pertimbangkan lebih detail.


Didorong oleh Peristiwa aplikasi mengasumsikan komunikasi komponen asinkron dan mengimplementasikan desainnya yang digabungkan secara longgar: pengirim dan penerima pesan tidak perlu mengetahui satu sama lain atau tentang metode pengiriman pesan, yang memungkinkan mereka untuk berkonsentrasi pada konten komunikasi. Selain fakta bahwa komponen yang digabungkan secara longgar secara signifikan meningkatkan pemeliharaan, ekstensibilitas, dan evolusi sistem, sifat asinkron dan non-pemblokiran interaksinya juga dapat membebaskan sebagian besar sumber daya, mengurangi waktu respons, dan menyediakan HAI throughput yang lebih tinggi daripada aplikasi tradisional. Berkat sifat yang digerakkan oleh peristiwa, fitur arsitektur reaktif lainnya dimungkinkan.

Skalabilitas dalam konteks pemrograman reaktif, ini adalah reaksi sistem terhadap perubahan beban, mis. elastisitas, dicapai dengan kemampuan untuk menambah atau melepaskan node komputasi sesuai kebutuhan. Dengan sambungan rendah, perpesanan asinkron, dan transparansi lokasi, metode penerapan dan topologi aplikasi menjadi keputusan waktu penerapan dan tunduk pada konfigurasi responsif beban dan algoritme adaptif. Dengan demikian, jaringan komputer menjadi bagian dari aplikasi yang awalnya bersifat eksplisit terdistribusi.

toleransi kesalahan arsitektur reaktif juga menjadi bagian dari desain, dan ini membuatnya sangat berbeda dari pendekatan tradisional untuk memastikan ketersediaan sistem yang berkelanjutan melalui redundansi dan kegagalan server. Ketahanan sistem seperti itu dicapai dengan kemampuannya untuk menanggapi kegagalan komponen individu dengan benar, mengisolasi kegagalan ini dengan menyimpan konteksnya dalam bentuk pesan yang menyebabkannya, dan meneruskan pesan ini ke komponen lain yang dapat membuat keputusan tentang bagaimana caranya. menangani kesalahan. Pendekatan ini memungkinkan Anda untuk menjaga logika bisnis aplikasi tetap bersih, memisahkan logika penanganan kegagalan darinya, yang dirumuskan dalam bentuk deklaratif eksplisit untuk mendaftarkan, mengisolasi, dan menangani kegagalan melalui sistem itu sendiri. Untuk membangun sistem penyembuhan diri seperti itu, komponen disusun secara hierarkis, dan masalahnya dinaikkan ke tingkat yang dapat menyelesaikannya.

Dan akhirnya daya tanggap- adalah kemampuan sistem untuk menanggapi input pengguna terlepas dari beban dan kegagalan, aplikasi semacam itu melibatkan pengguna dalam interaksi, menciptakan perasaan terhubung erat dengan sistem dan peralatan yang memadai untuk melakukan tugas saat ini. Daya tanggap relevan tidak hanya dalam sistem real-time, tetapi juga diperlukan untuk berbagai aplikasi. Selain itu, sistem yang tidak dapat merespons dengan cepat bahkan pada saat terjadi kegagalan tidak dapat dianggap toleran terhadap kesalahan. Daya tanggap dicapai dengan menggunakan model yang dapat diamati, aliran peristiwa, dan klien yang stateful. Model yang dapat diamati memancarkan peristiwa ketika statusnya berubah dan menyediakan interaksi waktu nyata antara pengguna dan sistem, sementara aliran peristiwa menyediakan abstraksi di mana interaksi ini dibangun melalui transformasi dan komunikasi asinkron non-pemblokiran.

Dengan demikian, aplikasi reaktif merupakan pendekatan yang seimbang untuk memecahkan berbagai masalah pengembangan perangkat lunak modern. Dibangun di atas fondasi yang digerakkan oleh peristiwa, mereka menyediakan alat yang diperlukan untuk menjamin skalabilitas dan toleransi kesalahan, dan mendukung pengalaman pengguna yang responsif dengan fitur lengkap. Para penulis mengharapkan semakin banyak sistem yang mematuhi prinsip-prinsip manifesto reaktif.

Selain itu, saya memberikan rencana kursus tanpa terjemahan. Kalau-kalau Anda sudah membaca sejauh ini dan masih penasaran.

Minggu 1: Tinjauan Prinsip Pemrograman Fungsional: model substitusi, ekspresi-for dan bagaimana hubungannya dengan monad. Memperkenalkan implementasi baru untuk ekspresi: generator nilai acak. Menunjukkan bagaimana ini dapat digunakan dalam pengujian acak dan memberikan ikhtisar tentang ScalaCheck, alat yang mengimplementasikan ide ini.

Minggu 2: Pemrograman fungsional dan status bisa berubah. Apa yang membuat objek bisa berubah? Bagaimana ini berdampak pada model substitusi. Contoh yang diperluas: Simulasi rangkaian digital

Minggu 3: masa depan. Memperkenalkan masa depan sebagai monad lain, dengan ekspresi-untuk sebagai sintaks konkret. Menunjukkan bagaimana masa depan dapat disusun untuk menghindari pemblokiran utas. Membahas penanganan kesalahan lintas-utas.

Minggu 4: Pemrosesan aliran reaktif. Generalisasi masa depan untuk perhitungan reaktif melalui aliran. operator aliran.

Minggu 5: Aktor. Memperkenalkan Model Aktor, aktor sebagai unit konsistensi yang dienkapsulasi, pengiriman pesan asinkron, membahas semantik pengiriman pesan yang berbeda (paling banyak sekali, setidaknya sekali, tepat sekali) dan konsistensi akhirnya.

Minggu 6: pengawasan. Memperkenalkan reifikasi kegagalan, penanganan kegagalan hierarkis, pola Error Kernel, pemantauan siklus hidup, membahas status transien dan persisten.

Minggu 7: Pola Percakapan. Membahas manajemen keadaan percakapan antara aktor dan pola untuk kontrol aliran, merutekan pesan ke kumpulan aktor untuk ketahanan atau penyeimbangan muatan, pengakuan penerimaan untuk mencapai pengiriman yang andal.