Davlat va Davlat aktyor

Kirish

Men Akkadan foydalanishni boshlaganimda, ichkarida biznes mantiqiga ega bo'lgan aktyorlik holatida qolish odatiy hol edi. Keyinchalik men ushbu yondashuvning kamchiliklarini aniqladim, mantiqni qayta ishlatish, yangi funktsiyalarni qo'shish juda qiyin, sinov Akka-dan foydalanishni talab qiladi va men yon ta'sirlarni sinab ko'rmoqdaman. Ushbu muammolarni hal qilish uchun men davlat monadidan foydalanishga harakat qildim. Ushbu blog postida qayta ishlash jarayoni tasvirlangan.

Biznes sohasi

Ushbu namuna loyihasi (github-ga havola) bu Akka yordamida avtomatlashtirishning oddiy bajarilishi. U savdo avtomati bilan foydalanuvchi bilan terminal orqali aloqa qiladigan dastur bilan taqlid qiladi. Foydalanuvchi tanga qo'shish (+1, +5, ...), mahsulotni tanlash (1, 2, ...) yoki pulni olish (-) kabi standart harakatlar boshlashi mumkin.

Savdo avtomati quyidagi funktsiyalarga ega:

  • kredit miqdorini kuzatish
  • mahsulotlar miqdori va yaroqlilik muddatini kuzatib borish
  • mahsulotni sotish
  • foydalanuvchini tanlashda pulni olib qo'yish
  • Savdo avtomati tugagan, mahsulot muddati tugagan yoki pul qutisi deyarli to'lmagan bo'lsa, egasini xabardor qiling

Bu juda uzun xususiyatlarning ro'yxati va umid qilamanki ularda birlik sinovlari mavjud.

https://unsplash.com/photos/5MKCA4STlVM

Bazani amalga oshirish

Arxitektura

Savdo avtomati aktyori avtomat holatini saqlab turish, foydalanuvchidan kirish ma'lumotlarini qayta ishlash va foydalanuvchi chiqishlari va tizim hisobotlariga aktlarni yuborish uchun javobgardir. Masalan, agar foydalanuvchi mahsulotni sotib olsa, savdo avtomati aktyor aktsiyalar miqdorini yangilaydi, mahsulotni chiqarish va o'zgarishlarni ta'minlash uchun foydalanuvchi chiqishlariga xabar yuboradi, agar mahsulot sotilgan bo'lsa, tizim hisobotiga xabar yuborishi mumkin.

Qayta tiklashdan oldin arxitektura

Savdo avtomati aktyorining holatini saqlash uchun bir nechta varaq mavjud. Vardan tashqari, juda ko'p mantiqqa ega bo'lgan qabul qilish bloki mavjud. Quyida parcha muhim narsalarni ko'rsatib beradi. Shunisi e'tiborga loyiqki, aralash mantiq (14-19 chiziqlar) va yon ta'sirni bajarish (21-23-qatorlar ichki holatni yangilash, 27-31-xabarlar xabarlarni yuborish).

Sinov

Sinovni ko'rib chiqaylik. Ko'rib turganingizdek, men Akka Testkit-dan foydalanyapman. Quyidagi kod, foydalanuvchilar mahsulotni "1" dan tortib olganda baxtli yo'l stsenariysini tasdiqlaydi.

Ushbu kod bir nechta kamchiliklarga ega. Birinchidan, biz biznes kodni sinash uchun Akkadan foydalanishimiz kerak. Bu aktyorlik tizimini boshlashni talab qiladi va bu testni sekinlashtiradi. Ikkinchidan, xabarlarni yuborish (UnderTest! Kredit (10)) va xabarlar qayta ishlanganligiga ishonch hosil qilish orqali aktyorning ichki holatini sozlashimiz kerak (userOutput.expectMsg (CreditInfo (10)). Uchinchidan, biz yon ta'sirlarni sinovdan o'tkazamiz. Ushbu testda tasdiqlash VendingMachineActor foydalanuvchi tomonidan taqdim etilganOndputsActor-ga GiveProductAndChange (pivo, 7) xabarini yuborganligini tasdiqlamoqda. Bundan tashqari, agar aktyorning ichki holatini tekshirmoqchi bo'lsak, GetState-ning maxsus xabari bilan ishlashimiz kerak.

Sinovlarning bir qismida, shuningdek, "nojo'ya ta'sirlar bajarilmaydi" degan muammo mavjud. Bunday holda biz AkkaTestkit-dan kutishNoMessage () dan foydalanamiz. Odatiy bo'lib, qo'ng'iroq hech qanday xabar yuborilmaganligiga ishonch hosil qilish uchun 3 soniya kutadi. Bu bizning qurilishimizni sekinlashtiradi. Biz bu vaqtni qisqartirishimiz mumkin, ammo bu sinovlarni noto'g'ri qilishi mumkin.

VendingMachineActor ichida amalga oshiriladigan biznes mantig'i Akka bog'liq. Bu aktyor katta qabul qilish blokiga ega va shtatni saqlab qolish uchun bir nechta var. Kodni qo'shish yoki o'zgartirish butun aktyor sinfi to'g'risida mulohaza yuritishni talab qiladi.

Shtat monadiga qaytarish

Davlat monad nima

Shtat monad - bu holatlarni qabul qiladigan va yangi holatlar va effektlarning juftlarini qaytaradigan funktsiya:

Davlat -> (Shtat, Effekt)

Shtat monad - bu monad, shuning uchun u flatMap usulini ta'minlaydi. Buning yordamida biz quyidagi davlat monadlarini yaratamiz:

Tushunish uchun yangi davlat monad qurilgan (lekin hali ishlamaydi). StateMonad1-da boshlang'ich holatning qo'llanilishi effekt1 va yangi holatni keltirib chiqaradi (buni holat1 deylik). Effekt effekt1 ga beriladi. Keyinchalik, stateMonad2 argument sifatida state1 bilan chaqiriladi va effekt effekt2 ga tayinlanadi. Hosildorlik qismida quyida keltirilgan amallar natijalari yordamida yakuniy natijani yaratishimiz mumkin.

Endi biz NewMonad-ni initialState-da argument sifatida ishlatishimiz mumkin. Natijada biz yangi holat va effektlarni olamiz.

Mushuklarda davlat monadini amalga oshirish tafsilotlarini "Mushuklar bilan skala" kitobida topishingiz mumkin (bu erda mavjud).

Eskisi bilan bir qatorda yangi mantiqni qayta to'ldirish

Men mavjud aktyorni almashtirish o'rniga yangi aktyor yaratishga qaror qildim (bu ikki dasturni taqqoslash imkoniyatiga ega bo'lish uchun). Yangi tatbiq aktyorlar (SmActor) dan qo'ng'iroqlar, aloqa va qo'ng'iroq holati monadlari o'rtasidagi holatni saqlash uchun foydalanadi. Men davlat monad sifatida amalga oshirmoqchi bo'lgan barcha biznes mantiqlarini. SmActor-da bir xil API bo'ladi, shuning uchun men mavjud testlarni qayta ishlatishga qodirman. Shu tarzda, ikkala amalga oshirish bir xil yoki yo'qligini tekshirishim mumkin. Keyinchalik men davlat monadlari uchun testlar yozaman.

Qayta tiklashdan keyin arxitektura

Ushbu yondashuvda aktyor faqat bitta o'zgaruvchini - holatni saqlaydi. Ushbu holat davlat monad tomonidan qayta ishlash uchun zarur bo'lgan barcha ma'lumotlarni o'z ichiga oladi. Quyida davlat sinfining ta'rifi:

SmActor-da men shunchaki bitta holat bilan belgiladim:

Endi men qabul qilish blokidagi ishlarni qisqartirishim mumkin:

Barcha biznes tadbirlari uchun bitta holat mavjud. Aktyor shuningdek, GetState-ni sinovlarga muvofiqligi uchun vaziyatni ham o'z ichiga oladi.

VendingMachineSm usuli bilan kompozitsion ob'ekti mavjud emas. Amalga oshirishni boshlaylik. Yuqorida ko'rsatib o'tilganidek, biz bir nechta davlat monadlari sifatida mantiqni amalga oshirishimiz va ularni kompozitsion usulda birlashtirishimiz mumkin. Avval men qaytish turini aniqlamoqchiman:

Mantiqni amalga oshirishni kichik monadlarga bo'lish va keyinchalik birlashtirish mumkin. Birinchi usul - bu kimdir tanga kiritganda yoki uni olib qo'yganda kreditni yangilash:

Tangalarni (Kredit (qiymat)) kiritgandan so'ng, kredit hajmi oshiriladi va foydalanuvchiga joriy kredit to'g'risida xabar chiqadi. Ta'kidlash joizki, hozirgi paytda hech qanday nojo'ya ta'sir ko'rsatilmaydi (boshqa aktyorlarga xabar yuborish).

Agar foydalanuvchilar pulni olishga qaror qilsalar, davlat nol kredit bilan yangilanadi va foydalanuvchiga xabar yaratiladi. Boshqa barcha harakatlar uchun biz holatni o'zgartirmasdan va natijasiz qaytarishimiz mumkin.

Endi biz sinovni amalga oshirish bilan tasdiqlashimiz mumkin:

Ko'rib turganingizdek, kreditni yangilash uchun mantiq ajratilgan.

Qolgan mantiqlarni bir xil uslubda amalga oshirish mumkin (mantiq va testlarni tekshiring). Butun jarayonni yaratish uchun barcha kichik davlat monadlaridan foydalanishimiz mumkin. Buning uchun biz tushunish uchun foydalanmoqdamiz. Shtat o'zgartirildi va keyingi shtat monadiga o'tdi. Olingan natijalar yig'ib olinadi va hosilning qismiga qo'shiladi. Shunday bo'lsa-da, davlat monadining ijrosi yo'q edi. Biz kattarog'ini qurdik.

FP usulida sinov

Buning yordamida biz "kichik davlat monadalari" va tuzilgan mantiqlarini sinab ko'rishimiz mumkin. Ushbu testlar yon ta'sirlarni amalga oshirmaydi. Qaytgan barcha effektlar davlat monad tomonidan qaytariladi. Shunday qilib, tasdiqlash usuli barcha ma'lumotlarga ega, biz mock yoki TestActorRef-ni yon ta'sirlarni tekshirish haqida tashvishlanmaymiz. Aktyor testlarida biz ma'lum vaqt davomida nojo'ya ta'sirlar amalga oshirilmaganligini sinab ko'rdik, FPda esa natijaning qaytarilishini tekshirishimiz kerak. Bundan tashqari, sinov uchun aktyorlik tizimlarini ishga tushirishimiz shart emas. Buni birlashtirgan holda, test tezroq.

Shuningdek, biz bir nechta amallarni osongina bajarishimiz va oraliq natijalarni tekshirishimiz mumkin:

Aktyor sinovida, qabul qilish usuli sinov ostida. qabul qilish - har qanday => birlik uchun taxallus. Bu noma'lum yon ta'siri bajarilishi mumkinligini anglatadi. Sof FPdan foydalangan holda butun natija sinov usulida qaytariladi. Bizning holatimizda bu bajarilishi kerak bo'lgan yangi holat va effektlar (Davlat => (Holat, Effekt)). Bunday holda, agar qaytarilgan qiymat kutilgan natijalarga mos kelsa, tekshirish oson.

Mantiq va davlatni ajratish sinov uchun foyda keltiradi. Biz ichki holatni (sinov ob'ektidagi ob'ektni) uning usullarini chaqirish (yoki xabar yuborish) orqali sozlashimiz shart emas. Agar bizda ushlab qolish stsenariysini sinab ko'rishni istasak, savdo avtomatiga tanga kiritishimiz kerak. Murakkab stsenariyda ichki holatni tayyorlash uchun ko'proq qadamlar talab qilinishi mumkin. Mantiqiy ob'ekt fuqaroligi bo'lmaganida, biz shunchaki dalillardan biri sifatida holatni o'tishimiz mumkin.

Foyda

Yuqorida aytib o'tganimdek, FP-dan foydalanib, biz o'zimizning dasturimizni kichikroq qismlardan iborat tarkibiy qismlarga bo'lishimiz mumkin. Murakkab mantiqni yaratish uchun faqat ma'lum funktsional imkoniyatlarga qaratilgan davlat monadlarini bir-biriga bog'lash mumkin.

Mantiqni kichik qismlarga bo'lish biz uchun sodda funktsiyalarni sinashga imkon beradi. Bundan tashqari, kichik qismlardan qurilgan murakkab mantiqni sinab ko'rishimiz mumkin. Ish mantig'i Akka va iplar kabi ramkalarga bog'liq emas. Uni osonlikcha sinab ko'rish mumkin.

Mantiqning kichik qismlari dasturning turli qismlarida qayta ishlatilishi mumkin. Ushbu kichik qismlardan foydalangan holda murakkab mantiqni qurish mumkin. Agar bizning vazifalarimiz toza bo'lsa (nojo'ya ta'sirlar va mutatsion holat bo'lmaydi), biz ushbu funktsiyalarni birlashtirish kutilmagan xatti-harakatlarga olib kelmasligiga aminmiz.

Yuqorida aytib o'tganimdek, bizning biznes mantig'imiz hech qanday yon ta'sirga ega bo'lmasligi kerak. Amalga oshiriladigan barcha effektlar usul bilan qaytariladi va biz muhim tafsilotlarni yo'qotish xavfisiz natijani tasdiqlashimiz mumkin.

Bundan tashqari, bizning sinovlarimiz ancha tezlashadi, chunki biz Aktor tizimini ishga tushirishimiz yoki yon ta'siri bajarilmaganligiga ishonch hosil qilishimiz shart emas.

Xulosa

Biz biznes mantig'ini aktyordan alohida ob'ektga o'tkazdik. Aktyor faqat qo'ng'iroqlar va iplarni sinxronlashtirish o'rtasidagi holatlarni saqlash uchun javobgardir. Davlat monad tufayli biznes mantig'i kichik qismlarga bo'lindi. Ushbu kichik qismlar murakkab mantiqni qurish uchun ishlatiladi. Sinovlar tezkor yoritilmoqda.

Havolalar:

  • Github-dagi loyiha https://github.com/otrebski/state-monad
  • Mushuklar kitobi bilan skala https://underscore.io/books/scala-with-cats/