Kể từ sau loạt bài về Apple Watch + CI, tôi muốn chuyển sang các chủ đề khác nói về các món ăn chơi nhảy múa mà không phải là về code, công việc. Nhưng nói thật là các món ăn chơi thì nhiều, cũng lắm sự kỳ công đòi hỏi người chơi phải có niềm yêu thích thực sự, thời gian tìm hiểu nhất định. Thêm nữa là khi viết những bài như vậy cần phải có kiến thức rộng, bao quát cũng như khá khó để tạo được cảm hứng cho người đọc. Thế nên thôi, lại quay về với cái máng lợn là: CODE…
Chắc hẳn trong công việc, mọi người đều có những mục tiêu riêng, đích đến nhất định qua các quãng thời gian dài ngắn khác nhau. Là 1 một lập trình viên iOS đơn thuần, mục tiêu trong năm nay của tôi là học 1 ngôn ngữ lập trình mới, vốn đang rất hot trong cộng đồng cũng như nội bộ công ty: Swift của Apple. Nhưng lần mò, vâng vẫn là cái trò lần mò, tôi được biết tới Functional Programming. Nhưng nghe lạ tai quá, tìm hiểu mãi thì mới đi đến ngọn nguồn của vấn đề: Declarative Programming.
Mới đầu đọc thì tôi chỉ biết đến nó như là 1 lĩnh vực nhỏ trong thế giới Computer Science bao la và cao siêu khó lường. Nhưng các kết quả tìm kiếm thường có cụm từ: Declarative Programming vs Imperative Programming. Imperative Programming (IP) thường gắn liền với lập trình hướng đối tượng OOP mà lâu nay tôi và các bạn(xin lỗi nếu có vơ đũa cả nắm) vẫn nghĩ là tối ưu, là phương pháp hay nhất khi phát triển phần mềm. Imperative Programming là cách mà bao lâu nay tôi vẫn lập trình, từ thời học cấp 3, Đại học và cả khi đi làm. Và nó có 1 thế giới đối nghịch Declarative Programming (DP). Vậy là ngoài kia, ngoài cái thế giới mà tôi đang sống có 1 thế giới khác mà bao lâu nay tôi không hề hay biết. Trên đường đi khám phá thế giới mới tôi gặp rất nhiều lời ca ngợi về nó, càng thôi thúc sự tò mò, khát khao khám phá của bản thân.
1.Định nghĩa
Hai mô hình trên vốn khá rộng, nhưng để định nghĩa thì có thể gói gọn 1 cách tương phản rõ ràng như sau:
- Imperative programming: telling the “machine” how to do something, and as a result what you want to happen will happen.
- Declarative programming: telling the “machine” what you would like to happen, and let the computer figure out how to do it.
Tôi chọn để nguyên văn tiếng Anh vì nó vốn quá súc tích, ngắn gọn và rất dễ để nhận ra sự khác bọt ở đây. Tuy nhiên hẳn các bạn cũng sẽ thấy mơ hồ với từ khóa “what”, “how” được dùng ở đây. Vậy hãy để tôi lấy ví dụ cho dễ hiểu.
Ví dụ 1: Nhân đôi các phần tử có trong mảng cho sẵn.
- Imperative: Xời, đơn giản! Đây là cách bạn sẽ nghĩ ra ngay trong đầu:
Cách thức giải quyết bài toán:
- Khai báo 1 mảng doubled mới để lưu dữ liệu
- Duyệt qua các phần tử của mảng.
- Thực hiện phép nhân đôi các phần tử trong mảng
- Lần lượt lưu kết quả vào mảng doubled
- Declarative:
Ở đây sẽ khác hơn 1 chút, chúng ta không thấy việc duyệt mảng mà chỉ thấy câu lệnh map cùng phép tính nhân với *2.
Lệnh map ở đây thực hiện việc tạo 1 mảng doubled mới từ mảng đã cho với các phần tử đã được nhân *2 qua function (n) {return n*2)} (ở đây function (n) được khai báo trực tiếp thay vì được tách ra ngoài).
“Dùng hàm có sẵn, thư viện bên ngoài thì nói làm gì. Hư cấu!”. Nhưng xin các bạn hãy nhìn lại. Cùng 1 bài toán sẽ có nhiều cách giải, về nguyên lý cơ bản là giống nhau nhưng cú pháp khác nhau, điều đó giải thích tại sao lại có cách giải này hay hơn cách giải bt khác. Xin nhấn mạnh sự khác biệt ở đây là khả năng đọc hiểu code (readability). Dùng mô hình Imperative chúng ta sẽ cần chỉ ra các bước tuần tự cần thực hiện trong khi Declarative sẽ cho thấy ngay cái ta cần xảy ra mà không bận tâm phải duyệt mảng, lưu kết quả vào mảng như thế nào. Bài toán yếu cần nhân đôi cá giá trị và code của bạn tập trung vào việc nhân đôi *2.
function(n) ở trên được gọi là pure function: nó không hề thay đổi bất kì giá trị nào (side effects) mà chỉ nhận vào input, trả ra output sau khi thực hiện tính toán.
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Ví dụ 2: Tính tổng tất các phần tử trong mảng.
- Imperative: tạo 1 biến mới, duyệt qua các phần tử và thực hiện cộng dồn vào biến đã tạo (How to do)
- Declarative: