Trong bài trước, tôi đã viết về cách lập trình không sử dụng IF sẽ có thể giúp bạn khám phá ra các giải pháp tốt hơn. Trong bài này, tôi sẽ tiếp tục viết về thử thách lập trình mà không dùng vòng lặp. Vòng lặp ở đây có nghĩa là for, for...in, for...of, while, and do...while. Tất cả đều tương tự nhau.
Imperative vs Declarative
Đây là những khái niệm lớn. Cách đơn giản nhất để giải thích về chúng là:
- Imperative đại diện cho HOW
- Declarative đại diện cho WHAT
What? How? Và tại sao chúng ta nên quan tâm đến nó?
Cách tiếp cận imperative đại diện cho một list các bước. Làm cái này trước, rồi làm cái kia sau, và sau cùng làm một cái khác. Ví dụ: Duyệt qua một danh sách các con số từng cái một rồi cộng giá trị của nó vào một biến tổng
Cách tiếp cận declarative đại diện cho cái gì chúng ta có và chúng ta cần cái gì. Ví dụ: Chúng ta có một danh sách các con số và chúng ta cần tổng giá trị của chúng
Ngôn ngữ của imperative gần giống với ngôn ngữ của máy tính ngày nay bởi vì chúng chỉ biết cách làm thế nào để thực thi theo cấu trúc. Còn ngôn ngữ của declarative gần giống với cách chúng ta nghĩ và ra lệnh.
Tin tốt lành là ngôn ngữ máy tính vẫn cho phép chúng ta declarative để thực thi imperative! Bài viết này tập trung vào việc thay thế declarative cho vòng lặp imperative.
Tính toàn vẹn
Trành dùng vòng lặp không chỉ nằm ở việc áp dụng declarative. Nó còn giúp toàn vẹn dữ liệu
Tính toàn vẹn dữ liệu lại là một chủ đề lớn khác nữa, nhưng tổng thể là không được modify data trong các biến và instance properties để trình diễn trạng thái của ứng dụng. Thay vào đó, trạng thái được lưu trữ trong các giai đoạn gọi các function. Các function gọi lẫn nhau một cách tuần tự để phát triển điểm bắt đầu ban đầu sang các dạng dữ liệu khác. Không có biến nào bị biến đổi khi chạy
Thay vì lạm dụng trạng thái để thực hiện các hoạt động đơn giản, giữ cho toàn vẹn sẽ an toàn hơn nhiều và cũng clean hơn. Tuy nhiên, lợi ích lớn của toàn vẹn chính là cách nó làm cho code dễ maintain và mở rộng hơn. Ví dụ, khi quản lý bất kỳ một trạng thái ứng dụng nào đó theo cách toàn vẹn, chúng ta có thể kiểm tra tình trạng bất kỳ lúc nào, undo lại sự thay đổi trạng thái, hoặc kể cả trở về quá khứ của trạng thái trước đó để kiểm tra ứng dụng lúc đó. Khi trạng thái không thay đổi, chúng ta luôn làm cho ứng dụng phải nhớ các giai đoạn phát triển của nó
Code dễ hiểu và performance có thể bị ảnh hường khi chúng ta lập trình theo cách toàn vẹn. Tuy nhiên, có nhiều chiến lược để có thể có cả 2 lợi ích là toàn vẹn và vừa performace tốt, code vừa dễ hiểu. Nhưng tôi sẽ viết nó trong tương lai.
Đệ Quy
Một cách khác để tránh vòng lặp imperative là thông qua đệ quy.
Đệ quy rất đơn giản. Làm một function gọi chính nó(tạo nên 1 vòng lặp) và thiết kế một điều kiện exit ra khỏi vòng lặp. Tôi không chắc đệ quy có thể được xếp vào loại declarative, nhưng nó chắc chắn là một sự thay thế cho việc sử dụng vòng lặp imperative. Tuy nhiên, hãy cẩn thận khi sử dụng đệ quy vì nó không hoạt động như là một vòng lặp thông thường. Tôi cũng không nghĩ rằng đệ quy sẽ giúp code của bạn dễ đọc trong đa số trường hợp.
Đôi khi, đệ quy là cách dễ nhất để hoàn thành thử thách này. Không có đệ quy, chúng ta sẽ cần maintain và sử dụng cấu trúc Stack của chúng ta(nhưng cũng không quá khó)