Bí quyết sử dụng “Immutability” để code gọn và sạch hơn

2058

Immutability – sự nhất quán là một trong những yếu tố quan trọng nhất của lập trình. Nó cho phép cho bạn viết code gọn và dễ dàng mà lại an toàn hơn. Tôi sẽ chỉ cho bạn cách để ta có được Immutability qua một số ví dụ trong Javascript sau.

Theo nguồn của Wikipedia

Immutable object (object không thay đổi) ám chỉ các object không thể bị đổi state sau khi nó đã được tạo ra. Điều hoàn toàn trái ngược so với mutable object (object có thể thay đổi) vốn cho phép ta được thoải mái thay state của nó. Trong một số trường hợp, object vẫn được cho là Immutable mặc dù một số thuộc tính bên trong đã thay đổi nhưng state của object vẫn không khác gì so với cũ.

Immutable Array

Để hiểu rõ về bản chất hoạt động immutability thì ta nên bắt đầu với Array.

const arrayA = [1, 2, 3];
arrayA.push(4);
 
const arrayB = arrayA;
arrayB.push(5);
 
console.log(arrayA); // [1, 2, 3, 4, 5]
console.log(arrayB); // [1, 2, 3, 4, 5]

Trong ví dụ trên, arrayB được xem là dựa trên arrayA, do đó phương thức “Push” sẽ tự động thêm vào giá trị 5 vào cả 2 variable. Tuy nhiên, lúc đó Code của ta cũng sẽ tự thay đổi các giá trị khác một cách gián tiếp, vốn là điều mà bạn không muốn. Bởi nó hoàn toàn trái ngược với immutability.

Vậy ta có thể biến chúng thành Immutable Array bằng slice function, và lúc này code sẽ hành xử theo một cách khác.

const arrayA = [1, 2, 3];
arrayA.push(4);
 
const arrayB = arrayA.slice(0);
arrayB.push(5);
 
console.log(arrayA); // [1, 2, 3, 4]
console.log(arrayB); // [1, 2, 3, 4, 5]

Đây là điều mà chúng ta muốn. Code không tự ý thay đổi các giá trị khác.

Note: Khi sử dụng Push để thêm một giá trị vào array bất kì, bạn đang làm biến đổi chính array đó và khiến phát sinh ra những hiệu ứng (side effect) mà ta không muốn. Lúc đó, bạn cần sử dụng slice function để trả về một phiên bản copy của đoạn array trên.

Function

Giờ thì bạn đã biết cách tránh việc thay đổi các giá trị ngoài ý muốn. Nhưng làm cách nào để tạo ra một function “pure” – không có bất kì side effect nào cũng như state không bị thay đổi.

Giờ ta thử áp dụng cách thức trên, nhưng thay vì cho array thì giờ là function. Đầu tiên ta cần function có khả năng tự ý gây biến đổi giá trị.

const add = (arrayInput, value) => {
  arrayInput.push(value);
 
  return arrayInput;
};
const array = [1, 2, 3];
 
console.log(add(array, 4)); // [1, 2, 3, 4]
console.log(add(array, 5)); // [1, 2, 3, 4, 5]

 

Một lần nữa, bởi do các giá trị Input bị thay đổi khiến cho funtion mới được tạo ra ngoài ý muốn. Trong lập trình, chúng ta có một qui luật vàng đó là: mỗi lần thêm vào function, nó sẽ làm biến đổi array variable và kết quả tạo ra một thứ hoàn toàn khác.

Vậy thì ta có thể làm như sau

const add = (arrayInput, value) => {
  const copiedArray = arrayInput.slice(0);
  copiedArray.push(value);
 
  return copiedArray;
};
 
const array = [1, 2, 3];
const resultA = add(array, 4);
console.log(resultA); // [1, 2, 3, 4]
const resultB = add(array, 5);
console.log(resultB); // [1, 2, 3, 5]

 

Giờ thì ta có thể call function nhiều lần liên tiếp, và kết quả đưa ra luôn giống nhau nếu input không đổi. Đó là bởi vì array đã không còn bị tự ý biến đổi và kết quả là một function thuần khuyết (pure function).

Bạn có thể dùng spread syntax, trong ES6, để làm ngắn gọn function trên.

const add = (arrayInput, value) => […arrayInput, value];

 

Concurrency

App của NodeJS sử dụng một khái niệm gọi là concurrency (đồng thời). Một concurrent operation có nghĩa là 2 phép tính kết hợp nhưng đều có khả năng tự hoàn thành quá trình được đặt cho chúng. Nói cách khác khi có 2 mục tiêu A và B, thì phép tính cho B không cần đợi phép tính A hoàn thành mà tự chạy luôn.

 

NodeJS khiến concurrency xảy ra là nhờ vào event-loop. Event loop sẽ liên tục lặp lại một event và kích hoạt bất kì các trình xử lí event. Cách thức hoạt động trên cho phép một app của NodeJS giải quyết lượng lớn các yêu cầu đến từ các người dùng. Nếu bạn muốn hiểu thêm thì hãy vào đây.

Nhiều bạn khi đọc đến đây sẽ thắc mắc rằng immutability có liên quan gì concurrency? Đó là do nhiều operation có khả năng thay đổi giá trị nằm ngoài tầm ảnh hưởng của function bằng cách của concurrent. Khiển cho output trở nên thiếu chính xác cũng như kết quả ngoài ý muốn. Vì thế hãy cẩn thận đối với các function có khả năng làm biến đổi giá trị ở ngoài phạm vi của chúng bởi nó khá là nguy hiểm.

Bước tiếp theo

Immutability là một khái niệm quan trọng mà bạn cần phải hiểu để học về lập trình. Vì thế mà tôi khuyến khích bạn đọc thêm bài ImmutableJS, của các delopver tại Facebook, về library chứa cấu trúc immutable data như Map, Set,List

Nguồn: blog.topdev.vn via Medium