Reactive Programming

Pitchayut CheeseJa
odds.team
Published in
3 min readMay 22, 2024

เมื่อคุณฟอล ig สาว คุณกำลัง Observe สาว

Reactive Programming คือแนวคิดในการเขียนโปรแกรมที่เน้นการทำงานกับข้อมูลที่ส่งมาแบบ asynchronousโดยสร้างระบบที่ตอบสนองต่อ changes หรือ events ที่เกิดขึ้น

changes หรือ events ที่เกิดขึ้นในระบบ จะเกิด side effect เสมอ

Key Concepts

  • Observables: เป็นแหล่งกำเนิดของการไหลของข้อมูล (data streams) หรือเหตุการณ์ต่าง ๆ
  • Observers: subscribe ไปที่ Observables เพื่อรับข้อมูลและตอบสนองต่อการเปลี่ยนแปลง
  • Operators: ใช้ในการประมวลผลและเปลี่ยนแปลงข้อมูลใน data streams ก่อนที่จะส่งไปยัง Observers
  • Schedulers: จัดการบริบทของการดำเนินงานของ Observables และ Observers เพื่อกำหนดว่าข้อมูลจะถูกประมวลผลอย่างไรและเมื่อใด
https://www.linkedin.com/pulse/reactive-programming-principles-explained-luis-soares-m-sc-/

อธิบายเพิ่มเพื่อให้เข้าใจความสัมพันธ์ระหว่าง Key Concepts แต่ละตัว

1. Observables

Observables เป็นตัวแทนของการไหลของข้อมูลหรือเหตุการณ์ที่สามารถถูก observe ได้ โดยข้อมูลหรือเหตุการณ์เหล่านี้สามารถเป็นได้ทั้งแบบ synchronous และ asynchronous

Observables ยังทำหน้าที่เป็นแหล่งกำเนิดของข้อมูลที่สามารถส่งค่าต่าง ๆ ไปยัง Observers

ตัวอย่างเช่น

• การคลิกเมาส์ (mouse clicks)

• การอัปเดตข้อมูลแบบเรียลไทม์ (real-time data updates)

• การอ่านค่าจากเซ็นเซอร์ (sensor readings)

2. Observers

Observers คือผู้ที่ทำการตอบสนองต่อการเปลี่ยนแปลงใน Observables โดยจะทำการ subscribe ไปที่ Observables และรอรับข้อมูลหรือเหตุการณ์ที่ถูกส่งมา
เมื่อ Observables มีการเปลี่ยนแปลงหรือต้องการส่งข้อมูล Observers จะทำการประมวลผลหรือตอบสนองต่อข้อมูลเหล่านั้น

ตัวอย่างเช่น

• การอัปเดต UI เมื่อมีการคลิกเมาส์

• การแสดงข้อมูล real-time

• การแจ้งเตือนผู้ใช้เมื่อมีเหตุการณ์เกิดขึ้น

3. Operators

Operators คือฟังก์ชันที่สามารถใช้ในการ manipulate และ transform data streams (การไหลของข้อมูล) ใน Observables
Operators ทำให้สามารถประมวลผลข้อมูลได้หลายรูปแบบ เช่น filtering, mapping, reducing เป็นต้น
Operators จะถูกใช้ในลำดับการทำงานของ Observables ก่อนที่ข้อมูลจะถูกส่งไปยัง Observers

ตัวอย่างเช่น

• filter เพื่อกรองข้อมูลที่ไม่ต้องการออก

• map เพื่อเปลี่ยนแปลงค่าของข้อมูล

• merge เพื่อรวมข้อมูลจากหลาย Observables

4. Schedulers

Schedulers ทำหน้าที่จัดการการไหลของข้อมูล (data streams) และการทำงานของ Observers โดยการกำหนดบริบทของการดำเนินงาน Schedulers จะควบคุมว่าเมื่อใดและอย่างไรที่ Observables และ Observers จะทำงาน เช่น การกำหนดว่า Observables จะทำงานใน thread ไหน หรือจะทำงานในลักษณะ synchronous หรือ asynchronous

ตัวอย่างเช่น

• กำหนดให้ Observables ทำงานใน thread background เพื่อไม่ให้ block UI

• การทำงานของ Observers ใน context ที่กำหนด

When to use Reactive Programming
การเขียนโปรแกรมแบบ Reactive เหมาะสมกับงานหลายประเภทที่ต้องจัดการกับข้อมูลหรือเหตุการณ์แบบ asynchronous อย่างมีประสิทธิภาพ ซึ่งรวมถึงงานต่าง ๆ เช่น :

1. งานที่เกี่ยวข้องกับ User Interfaces
การสร้าง UI ที่ตอบสนองต่อการกระทำของผู้ใช้ในทันที เช่น:

• การอัปเดตส่วนต่าง ๆ ของหน้าเว็บหรือแอปพลิเคชันเมื่อผู้ใช้ทำการคลิก, กรอกข้อมูล หรือเลื่อนหน้า

• การสร้างแบบฟอร์มที่สามารถตรวจสอบข้อมูลได้ในขณะกรอก

• การทำงานของแอปพลิเคชันที่ต้องมีการโหลดข้อมูลแบบเรียลไทม์ เช่น การแสดงข้อมูลในแอปพลิเคชันตารางเวลา

2. งานที่ต้องการข้อมูลเรียลไทม์ (Real-Time Data)
งานที่ต้องการการอัปเดตข้อมูลอย่างต่อเนื่องและทันที เช่น:

• ระบบแชทและการส่งข้อความที่ต้องการการตอบสนองทันที

• การติดตามหุ้นหรือราคาสินทรัพย์ที่เปลี่ยนแปลงตลอดเวลา

• การแสดงข้อมูลสภาพอากาศแบบเรียลไทม์

3. Event-Driven Architectures
การสร้างระบบที่ตอบสนองต่อ events ต่าง ๆ เช่น:

• การแจ้งเตือนผู้ใช้เมื่อเกิดเหตุการณ์สำคัญ

• การจัดการเซ็นเซอร์และการอ่านค่าจากอุปกรณ์ IoT

• การจัดการการอัปเดตข้อมูลและการแจ้งเตือนในแอปพลิเคชันมือถือ

4. งานที่ต้องการการประมวลผลข้อมูลขนาดใหญ่และซับซ้อน
การรวมและประมวลผลข้อมูลจากแหล่งข้อมูลหลาย ๆ แห่ง เช่น:

• การรวมข้อมูลจาก API หลายตัวและทำการประมวลผลเพื่อแสดงผลในหน้าเดียวกัน

• การประมวลผลข้อมูลจากระบบแบ็คเอนด์ที่มีหลายแหล่งข้อมูล

• การวิเคราะห์ข้อมูลจากหลายแหล่งเพื่อสรุปผลในเวลาจริง

เปรียบเทียบระหว่าง Reactive และ Imperative Programming

เพื่อทำความเข้าใจความแตกต่างระหว่างการเขียนโปรแกรมแบบ Reactive และแบบ Imperative เราจะใช้ตัวอย่างใน Angular ที่แสดงการจัดการกับข้อมูล asynchronous โดยเปรียบเทียบการเขียนโปรแกรมทั้งสองแบบ

import { Component, OnInit } from '@angular/core';
import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';

@Component({
selector: 'app-reactive-example',
template: `
<ul>
<li *ngFor="let number of numbers">{{ number }}</li>
</ul>
`
})
export class ReactiveExampleComponent implements OnInit {
numbers: number[] = [];

ngOnInit() {
const observable = of(1, 2, 3, 4, 5);

observable.pipe(
filter(num => num % 2 === 0),
map(num => num * 2)
).subscribe(result => {
this.numbers.push(result);
});
}
}
  • Observable ถูกสร้างขึ้นด้วย of ซึ่งสร้างสตรีมของตัวเลข
  • Operators เช่น filter และ map ถูกใช้ในการเปลี่ยนแปลงข้อมูลในสตรีม
  • Subscription ถูกใช้เพื่ออัปเดต numbers ใน component เมื่อข้อมูลถูกประมวลผล
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'app-imperative-example',
template: `
<ul>
<li *ngFor="let number of numbers">{{ number }}</li>
</ul>
`
})
export class ImperativeExampleComponent implements OnInit {
numbers: number[] = [];

ngOnInit() {
const data = [1, 2, 3, 4, 5];
const filteredData = this.filterEvenNumbers(data);
const transformedData = this.doubleNumbers(filteredData);
this.numbers = transformedData;
}

filterEvenNumbers(data: number[]): number[] {
const result = [];
for (let num of data) {
if (num % 2 === 0) {
result.push(num);
}
}
return result;
}

doubleNumbers(data: number[]): number[] {
const result = [];
for (let num of data) {
result.push(num * 2);
}
return result;
}
}
  • ใช้การประมวลผลข้อมูลแบบขั้นตอน (procedural) โดยการกรองและเปลี่ยนแปลงข้อมูลในลำดับ
  • filterEvenNumbers และ doubleNumbers ถูกเรียกเพื่อกรองและเปลี่ยนแปลงข้อมูล
  • ผลลัพธ์สุดท้ายถูกเก็บใน numbers ซึ่งจะใช้ใน template

ข้อดีของการเขียนโปรแกรมแบบ Reactive

  1. การจัดการอะซิงโครนัสง่ายขึ้น: การใช้ Observables และ Operators ทำให้การจัดการกับข้อมูลที่มาจากหลายแหล่งและการตอบสนองต่อเหตุการณ์ทำได้ง่ายและเป็นธรรมชาติ
  2. การอ่านและบำรุงรักษาโค้ด: การเขียนโปรแกรมแบบ Declarative ทำให้โค้ดมีความชัดเจนและอ่านง่าย โดยเฉพาะในระบบที่ซับซ้อน
  3. ความสามารถในการขยายตัว: การจัดการข้อมูลและการตอบสนองต่อเหตุการณ์ทำได้ดีในระบบขนาดใหญ่และซับซ้อน

ข้อเสียของการเขียนโปรแกรมแบบ Reactive

  1. การเรียนรู้ที่ยากลำบาก: แนวคิดและวิธีการเขียนโค้ดแบบ Reactive อาจยากต่อการเข้าใจสำหรับผู้ที่ไม่มีประสบการณ์
  2. การ debug ที่ซับซ้อน: เนื่องจากการไหลของข้อมูลอาจมีความซับซ้อน ทำให้การดีบักและติดตามข้อผิดพลาดเป็นเรื่องยาก
  3. ประสิทธิภาพในบางกรณี: อาจมี overhead ในการใช้งาน Operators และ Observables เมื่อเทียบกับวิธีการแบบขั้นตอนที่ง่ายกว่า

ข้อดีของการเขียนโปรแกรมแบบ Imperative

  1. ความเรียบง่าย: ง่ายต่อการเริ่มต้นและเข้าใจ เนื่องจากการทำงานเป็นขั้นตอนที่ชัดเจน
  2. การ debug ที่ง่าย: การติดตามข้อผิดพลาดทำได้ง่ายกว่า เนื่องจากลำดับการทำงานเป็นขั้นตอนที่ชัดเจน
  3. ประสิทธิภาพ: มีประสิทธิภาพดีสำหรับงานที่ไม่ซับซ้อน และไม่ต้องการการจัดการข้อมูลอะซิงโครนัสจำนวนมาก

ข้อเสียของการเขียนโปรแกรมแบบ Imperative

  1. การจัดการอะซิงโครนัสที่ยากขึ้น: ต้องใช้ callback หรือ promises ซึ่งอาจทำให้โค้ดยุ่งเหยิง (callback hell)
  2. การบำรุงรักษาในระบบขนาดใหญ่: เมื่อระบบมีความซับซ้อนมากขึ้น การบำรุงรักษาโค้ดจะยากขึ้นและอาจมีข้อผิดพลาดมากขึ้น
  3. ความสามารถในการขยายตัว: อาจยากในการขยายระบบที่ซับซ้อนและต้องจัดการข้อมูลจำนวนมาก

การเลือกใช้ระหว่างการเขียนโปรแกรมแบบ Reactive และ Imperative ขึ้นอยู่กับลักษณะของงานและความต้องการของระบบ หากระบบมีการจัดการกับข้อมูล asynchronous และมีความซับซ้อนสูง การเขียนโปรแกรมแบบ Reactive อาจเป็นตัวเลือกที่ดีกว่า แต่หากเป็นงานที่ไม่ซับซ้อนและต้องการความง่ายในการเขียนและดีบัก การเขียนโปรแกรมแบบ Imperative อาจเหมาะสมกว่า

Conclusion

การเขียนโปรแกรมแบบ Reactive เป็นแนวคิดที่มีประสิทธิภาพในการจัดการกับข้อมูลและ events แบบ asynchronous โดยใช้ Observables, Observers, Operators และ Schedulers เป็นเครื่องมือหลักในการสร้างระบบที่ตอบสนองต่อการเปลี่ยนแปลงของข้อมูลได้อย่างทันทีและมีประสิทธิภาพ

--

--