Imperative-Reactive در مقابل Functional-Reactive: آیا می توانید تفاوت را تشخیص دهید؟

اگر با فریمورکهایی مانند Angular، React، Vue، SOLID، Svelte کار کردهاید، از قبل با پارادایم Imperative-Reactive آشنا هستید، زیرا همه آنها از آن پشتیبانی میکنند.
گاهی اوقات ممکن است به این باور رسیده باشید که برنامه نویسی Functional-Reactive انجام می دهید، اما به احتمال زیاد این کار را نکرده اید.
می توانید تفاوت را بگویید؟ آیا این مهم است؟
بیایید با یک مثال برای کمک به درک شروع کنیم.
const
// react.js with hooks
const component = () => {
const [value, setValue] = useState(0);
return (
<div>
<span>{value}</span>
<button onClick={()=>setValue(()=>value +1)}</span>
</div>
);
}
و در ادامه ما یک همتای عملکردی- واکنشی داریم.
// rimmel.js with rxjs streams
const component = () => {
const count = new BehaviorSubject(0).pipe(
scan(x=>x+1)
);
return rml`
<div>
count: <span>${count}</span>
<button onClick=${count}</span>
</div>
`;
}
بنابراین، تفاوت چیست و چرا اهمیت دارد؟
اول از همه، با توجه به اینکه این مثال بی اهمیت و بیش از حد ساده است، تفاوت تقریباً ناچیز است.
همانطور که در مورد دوم شما دارید BehaviorSubject
و scan
به عنوان موجودیتهای بالقوه ناآشنا، مورد اول ممکن است به راحتی سادهتر یا آشناتر به نظر برسد. onclick
رویداد و شما مقداری حالت را تنظیم می کنید setValue(new value)
.
این جوهر برنامه نویسی ضروری است، الگویی که در آن کد فعلی ارزش چیزی را در جای دیگری تعیین می کند.
اما در مورد دوم، برعکس است.
اگر تا به حال از Excel یا Google Sheets استفاده کرده اید، تا حدودی با برنامه نویسی تابعی آشنا هستید: برای هر سلول فرمول را تعریف می کنید، مانند =SUM(A1:A10) +AVG(B1:B10) +C1 *D2
.
با Rimmel.js می توانید همین کار را انجام دهید: به نوعی فرمولی برای هر قطعه HTML تعریف می کنید. مقدار از کجا باید محاسبه شود.
innerHTML، کلاسها، سبکها، ویژگیهای داده از کجا باید بیایند؟ یک جعبه متن دیگر؟ یک کرکره؟ آخرین موقعیت ماوس؟ آخرین پیام از یک وب سوکت؟
پاسخ از یک جریان است
یک جریان فقط دنباله ای از رویدادهای تکراری در طول زمان است، مانند کلیک های ماوس، حرکت های ماوس، ضربه های کلید، پیام های یک وب سوکت و غیره.
زیبایی و قدرت جریان های قابل مشاهده این است که می توانید آنها را در سطح بسیار بالایی با استفاده از عملگرهای RxJS مانند نقشه، کاهش، فیلتر، takeUntil، combinationLatest و بسیاری دیگر تغییر دهید. آنها تقریباً مانند یک زبان پردازش جریان هستند که برای ترکیب و تبدیل جریان ها به روشی بسیار کارآمد طراحی شده اند.
خوب، جالب است، اما چرا؟
چند دلیل قانع کننده برای برنامه نویسی تابعی-reacvite وجود دارد و یکی از آنها تست پذیری است.
آزمایش کد واکنشی-عملکردی بسیار ساده تر از کد ضروری است.
با نوشتن تعداد کمتری تست واحد کوچکتر می توانید به همان سطح پوشش دست پیدا کنید.
مورد دیگر کد مختصرتر است، به این معنی که کد کمتری برای نوشتن وجود دارد، شانس بسیار کمتری برای معرفی اشکالات (کد طولانی تر ====== اشکالات بیشتر) و اندازه های بسته به شدت کوچکتر است.
این به این دلیل است که در برنامه نویسی امری شما به جریان فکر نمی کنید. شما یک متغیر اینجا دارید، یک متغیر در آنجا، یک شی به بالا، دیگری پایین، یکی عدد است، یکی تاریخ و غیره.
شما میتوانید هر کاری که میخواهید با آنها انجام دهید، که نه تنها به شما قدرت بیشتری میدهد، بلکه به شما این قدرت را میدهد که به خودتان آسیب برسانید و یک پایگاه کد غیرقابل مدیریت بنویسید.
همه چیز به عنوان یک جریان
وقتی همه چیز را به عنوان یک جریان در نظر می گیرید، همه مشکلات خود را به مشکلات تبدیل جریان تقسیم می کنید. وقتی مقداری داده وارد می شود، آن را تغییر می دهید و نتیجه از بین می رود. هیچ تمسخر، خرد، جاسوس یا سایر ابزارهای سوئیسی برای تغییر مصنوعی کد شما و انجام آن برای تست واحد شما بدون خرید سهام گران قیمت در بورس یا ارسال هزاران ایمیل آزمایشی وجود ندارد.
ویژگی کلیدی استریم ها
ویژگی کلیدی، اپراتورهای جریانی است که توسط RxJS و کتابخانه های مشابه استفاده می شود که به شما کمک می کند همه چیز را به عنوان یک جریان در نظر بگیرید، بنابراین عملگرهای مشابه، روش ترکیب آنها با هم، همان روش منتظر ماندن برای رویدادهای دیگر و غیره.
در نهایت، هرگز لازم نیست این قابلیت دستکاری جریان سطح بالا را آزمایش کنید. شما نقشه، کاهش، با LatestFrom، takeUntil و غیره را تست نمی کنید. در برنامه نویسی ضروری، شما اساساً باید هر یک از اینها را به نحوی در میانه منطق کسب و کار خود دوباره پیاده سازی کنید. بنابراین کد شما به احتمال زیاد ترکیبی از منطق تجاری و منطق دستکاری جریان با هم خواهد بود و احتمال معرفی باگ ها مرتبه ای بزرگتر خواهد بود.
جنبه های منفی؟
اوه، بله، هیچ ناهار، صبحانه، یا میان وعده رایگان وجود ندارد.
شما باید مدتی را صرف یادگیری نحوه استفاده از این اپراتورهای مدیریت جریان، Observables، RxJS کنید.
این کمی شبیه یادگیری یک شبه زبان جدید یا DSL است.
فرض کنید بزرگ شده اید و همه چیز را در اسمبلی می نویسید و مجبور شده اید متنی را چاپ کنید. شما باید حافظه را اختصاص دهید،
نشانگرهای یک رشته را دریافت کنید، روی بلوک حافظه حلقه بزنید تا مقداری صفر پیدا کنید، تعدادی ثبات CPU را تنظیم کنید، برخی از وقفه ها را در طول مسیر فراخوانی کنید و غیره. سپس به جاوا اسکریپت سوئیچ می کنید و ناگهان فقط تماس می گیرید. console.log('Hello, world')
.
تغییر به RxJS مزایای مشابهی را به همراه خواهد داشت. شما فقط باید یاد بگیرید که عملکردهای سطح بالا خاصی مانند وجود دارد console.log
که شما از آن برای چاپ مقداری متن استفاده می کنید، نه اینکه با ثبات های CPU، تخصیص حافظه و وقفه های تماس را به هم بزنید.
آیا این یک نقطه ضعف است؟ در ابتدا کمی
در زندگی واقعی، شما مشترک یک جریان می شوید، مقدار منتشر شده را به جریان جدیدی تبدیل می کنید که از جای دیگری می آید تا زمانی که رویداد دیگری اتفاق بیفتد و ارزش نهایی را بگیرید (لل، به این ترتیب drag’n’drop، btw را انجام می دهید).
بنابراین، همیشه آنقدر بی اهمیت نیست console.log
اما هنوز خیلی بهتر از اجرای مجدد این همه منطق است.
Rimmel.js چگونه به صحنه می آید؟
این تنها کتابخانه UI در اطراف است که به طور خاص طراحی شده است تا همه چیز را به عنوان یک جریان قابل مشاهده در نظر بگیرد.
با کتابخانههای دیگر، به آداپتورهای شخص ثالث نیاز دارید و در نهایت کارهای زیادی را کپی و پیچیده میکنید، که احتمالاً مزایایی مانند عملکرد بهتر، آزمایشپذیری، کیفیت کد را قربانی میکنید.
استفاده از جریانهای قابل مشاهده با Rimmel به شما تضمین میکند که اندازه کد، اندازه بستهها، تعداد باگها را کاهش دهید، و همچنین در طول مسیر عملکرد را افزایش خواهید داد.
کد نویسی مبارک!