
كثير اليوم يحبون البرمجة التفاعلية. لديها الكثير من المزايا: عدم وجود ما يسمى ب "
الجحيم رد الاتصال " ، وآلية معالجة الأخطاء المضمنة ، وأسلوب البرمجة وظيفية يقلل من احتمال الأخطاء. أسهل بكثير لكتابة رمز متعدد الخيوط وأسهل لإدارة تدفقات البيانات (الجمع ، وتقسيم وتحويل).
تحتوي العديد من لغات البرمجة على مكتبة تفاعلية خاصة بها: RxJava for JVM ، RxJS for JavaScript ، RxSwift لـ iOS ، Rx.NET ، إلخ.
ولكن ماذا لدينا لكوتلين؟ سيكون من المنطقي أن نفترض أن RxKotlin. وبالفعل ، توجد مثل هذه المكتبة ، لكنها مجرد مجموعة من الامتدادات لـ RxJava2 ، ما يسمى "السكر".
ومن الناحية المثالية ، أود الحصول على حل يفي بالمعايير التالية:
- multi-platform - لتتمكن من كتابة مكتبات متعددة المنصات باستخدام البرمجة التفاعلية وتوزيعها داخل الشركة ؛
- الأمان الفارغ - نظام النوع Kotlin يحمينا من " الأخطاء بمليارات الدولارات " ، لذلك يجب أن تكون القيم الخالية صالحة (على سبيل المثال ،
Observable<String?>
) ؛
- يعد التباين والتناقض ميزة أخرى مفيدة للغاية لكوتلين ، مما يجعل من الممكن ، على سبيل المثال ، الإدلاء بأمان نوع
Observable<CharSequence>
Observable<String>
Observable<CharSequence>
.
قررنا في Badoo عدم انتظار الطقس عن طريق البحر وعمل مثل هذه المكتبة. كما كنت قد خمنت ، أطلقنا عليه Reaktive ونشرناه على
جيثب .
في هذه المقالة ، سوف نلقي نظرة فاحصة على توقعات البرمجة التفاعلية لدى Kotlin ونرى كيف تتطابق قدرات Reaktive معهم.
ثلاث فوائد Reaktive الطبيعية
المتعدد
الميزة
الطبيعية الأولى هي الأكثر أهمية. توجد فرق iOS و Android و Mobile Web الخاصة بنا حاليًا بشكل منفصل. المتطلبات عامة ، التصميم هو نفسه ، لكن كل فريق يقوم بعمله الخاص.
يسمح لك Kotlin بكتابة كود متعدد المنصات ، لكن عليك أن تنسى البرمجة التفاعلية. وأود أن أكون قادرًا على كتابة مكتبات مشتركة باستخدام البرمجة التفاعلية وتوزيعها داخل الشركة أو تحميلها على GitHub. من المحتمل أن يقلل هذا الأسلوب من وقت التطوير ويقلل إجمالي مقدار الكود.
سلامة خالية
هو بالأحرى عن عيب Java و RxJava2. باختصار ، لا يمكن استخدام خالية. دعنا نحاول معرفة السبب. ألق نظرة على واجهة جافا هذه:
public interface UserDataSource { Single<User> load(); }
يمكن أن تكون النتيجة لاغية؟ لتجنب الغموض ، لا يُسمح بالقيمة الخالية في RxJava2. وإذا كنت لا تزال بحاجة لذلك ، فهذه ربما تكون اختيارية. ولكن في Kotlin لا توجد مثل هذه المشاكل. يمكننا القول بأن
Single<User>
و
Single<User?>
أنواع مختلفة ، وكل المشاكل تظهر في مرحلة الترجمة.
التباين والمخالفة
هذه هي سمة مميزة لكوتلين ، وهو شيء يفتقر للغاية في جافا. يمكنك قراءة المزيد عن هذا في
الدليل . سأقدم فقط بضعة أمثلة مثيرة للاهتمام حول المشكلات التي تنشأ عند استخدام RxJava في Kotlin.
التغاير :
fun bar(source: Observable<CharSequence>) { } fun foo(source: Observable<String>) { bar(source)
نظرًا لأن
Observable
عبارة عن واجهة Java ، فلا يتم تجميع هذه التعليمات البرمجية. هذا لأن الأنواع العامة في Java ثابتة. يمكنك بالطبع استخدام ، ولكن بعد ذلك سيؤدي استخدام عوامل التشغيل مثل المسح الضوئي إلى حدوث خطأ في الترجمة:
fun bar(source: Observable<out CharSequence>) { source.scan { a, b -> "$a,$b" }
يختلف بيان المسح من حيث أن نوعه العام "T" هو كلا من المدخلات والمخرجات. إذا كانت Observable هي واجهة Kotlin ، فيمكن حينئذٍ الإشارة إلى النوع T على أنه خارج وسيؤدي ذلك إلى حل المشكلة:
interface Observable<out T> { … }
وهنا مثال على المخالفة:
fun bar(consumer: Consumer<String>) { } fun foo(consumer: Consumer<CharSequence>) { bar(consumer)
للسبب نفسه كما في المثال السابق (الأنواع العامة في Java ثابتة) ، لا يتم تجميع هذا المثال. الإضافة ستحل المشكلة ، لكن مرة أخرى لن تحل المشكلة بنسبة مائة بالمائة:
fun bar(consumer: Consumer<in String>) { if (consumer is Subject) { val value: String = consumer.value
حسنًا ، وفقًا للتقاليد ، يتم حل هذه المشكلة في Kotlin عن طريق استخدام في الواجهة:
interface Consumer<in T> { fun accept(value: T) }
وبالتالي ، فإن التباين ومخالفة الأنواع العامة هي الميزة
الطبيعية الثالثة لمكتبة Reaktive.
Kotlin + التفاعلي = Reaktive
نمر إلى الشيء الرئيسي - وصف مكتبة Reaktive.
فيما يلي بعض ميزاته:
- إنها منصة متعددة ، مما يعني أنه يمكنك أخيرًا كتابة رمز عام. في Badoo ، نعتبر هذا أحد أهم الفوائد.
- هو مكتوب في Kotlin ، والذي يعطينا المزايا الموضحة أعلاه: لا توجد قيود على فارغة ، التباين / المخالفة. هذا يزيد من المرونة ويوفر الأمان أثناء الترجمة.
- لا يوجد أي اعتماد على المكتبات الأخرى ، مثل RxJava ، RxSwift ، وما إلى ذلك ، مما يعني أنه لا توجد حاجة لجلب وظيفة المكتبة إلى قاسم مشترك.
- واجهة برمجة تطبيقات Pure على سبيل المثال ، واجهة ObservableSource في Reaktive تسمى ببساطة Observable ، وجميع المشغلين وظائف امتداد موجودة في ملفات منفصلة. لا توجد فئات الله 15000 خطوط. هذا يجعل من الممكن زيادة الوظائف بسهولة دون إجراء تغييرات على الواجهات والفئات الموجودة.
- دعم
observeOn
(باستخدام observeOn
subscribeOn
و observeOn
).
- متوافق مع RxJava2 (إمكانية التشغيل المتداخل) ، مما يوفر تحويل المصدر بين Reaktive و RxJava2 والقدرة على إعادة استخدام برامج الجدولة من RxJava2.
- ReactiveX الامتثال.
أود أن أتحدث أكثر قليلاً عن الفوائد التي تلقيناها بسبب حقيقة أن المكتبة مكتوبة في Kotlin.
- في Reaktive ، يُسمح بالقيم الخالية ، لأنها آمنة في Kotlin. فيما يلي بعض الأمثلة المثيرة للاهتمام:
observableOf<String>(null) //
val o1: Observable<String?> = observableOf(null)
val o2: Observable<String> = o1 // ,
val o1: Observable<String?> = observableOf(null)
val o2: Observable<String> = o1.notNull() // , null
val o1: Observable<String> = observableOf("Hello")
val o2: Observable<String?> = o1 //
val o1: Observable<String?> = observableOf(null)
val o2: Observable<String> = observableOf("Hello")
val o3: Observable<String?> = merge(o1, o2) //
val o4: Observable<String> = merge(o1, o2) // ,
التغيير هو أيضا ميزة كبيرة. على سبيل المثال ، في الواجهة Observable
، يتم الإعلان عن النوع T باعتباره out
، مما يجعل من الممكن كتابة شيء مثل التالي:
fun foo() { val source: Observable<String> = observableOf("Hello") bar(source)
هذا ما تبدو عليه المكتبة اليوم:- الحالة وقت كتابة هذا التقرير: ألفا (بعض التغييرات في واجهة برمجة التطبيقات العامة ممكنة) ؛
- المنصات المدعومة: JVM و Android ؛
- المصادر المدعومة:
Observable
، Maybe
، Single
وقابلة Completable
؛
- يتم دعم عدد كبير إلى حد ما من المشغلين ، بما في ذلك الخريطة والتصفية و flatMap و concatMap و combineLatest و zip و merge وغيرها (يمكن الاطلاع على القائمة الكاملة على GitHub ) ؛
- ويدعم المجدولين التاليين: حساب ، IO ، الترامبولين والرئيسية.
- الموضوعات: PublishSubject و BehaviorSubject؛
- لم يتم دعم الضغط الخلفي بعد ، لكننا نفكر في ضرورة وتنفيذ هذه الميزة.
ما هي خططنا للمستقبل القريب:- البدء في استخدام Reaktive في منتجاتنا (ندرس حاليًا الخيارات) ؛
- دعم JavaScript (طلب السحب قيد المراجعة بالفعل) ؛
- دعم iOS
- نشر الأعمال الفنية في JCenter (تستخدم حاليًا خدمة JitPack) ؛
- التوثيق؛
- زيادة عدد المشغلين المدعومين ؛
- الاختبارات.
- المزيد من المنصات - طلبات السحب مرحب بها!
يمكنك تجربة المكتبة الآن ، يمكنك أن تجد كل ما تحتاجه على
جيثب . مشاركة تجربتك وطرح الأسئلة. سنكون ممتنين لأية ملاحظات.