Lưu ý: Bài viết dưới đây là những quan điểm cá nhân của tôi về vấn đề xử lý dữ liệu. Điều đó cũng bao gồm những kinh nghiệm của tôi trong các dự án thực tế. Các bạn đọc có thể mang tính chất tham khảo hoặc cũng có thể để lại những ý kiến để mọi người cùng thảo luận nhé.
Ở bài viết trước tôi có giới thiệu cho các bạn một vài cách xử lý dữ liệu thì bài viết ngày hôm nay tôi sẽ tập trung hơn vào việc tôi đã xử lý dữ liệu trong Javascript như thế nào, cũng như cách viết code dễ đọc hơn cho việc bảo trì dự án sau này.
Viết code để chạy được thì nhanh nhưng viết để dễ dàng trong bảo trì sau này đòi hỏi người viết phải có được những kinh nghiệm nhất định, đồng thời việc tổ chức mã, luồng cũng sẽ tốn nhiều thời gian hơn một chút. Thời gian để bảo trì một dự án thường sẽ lớn hơn nhiều so với thời gian để phát hành sản phẩm lần đầu tiên, chưa kể sẽ có những người mới tham gia vào dự án. Vì thế nếu tổ chức mã của bạn tốt sẽ tiết kiệm được kha khá thời gian sau này.
Xử lý dữ liệu là điều thường xuyên trong các chức năng của dự án, các bạn có thể hiểu nó bao gồm các hành động như lọc, ánh xạ, biến đổi dữ liệu trong các tập dữ liệu Array hay Object. 4 kĩ thuật tôi thường hay sử dụng dưới đây góp phần giữ cho code của tôi được rõ ràng hơn.
Bất biến có nghĩa là một khi đã khai báo biến rồi thì tuyệt đối không được thay đổi biến đó nữa. Nếu muốn sửa đổi dữ liệu thì hãy sao chép chúng sang một biến khác. Mới nghe thì có vẻ điều này không hợp lý cho lắm bởi biến trong các ngôn ngữ lập trình được phép thay đổi, gán đi gán lại một cách bình thường. Điều này cũng làm tăng hiệu năng, tiết kiệm bộ nhớ hơn so với việc phải tạo thêm nhiều biến nữa.
Trong Javascript không có định nghĩa kiểu của dữ liệu, việc khai báo một biến với từ khóa var
hoặc let
giúp cho chúng ta có thể dễ dàng thay đổi dữ liệu hoặc thâm chí là kiểu dữ liệu của nó sau này. Điều này tạo nên sự linh hoạt nhưng tác hại đằng sau sự linh hoạt đó có vẻ là nhiều hơn.
Trong một đoạn mã với hàng chục, hàng trăm dòng code thì việc thay đổi dữ liệu của một biến đôi khi sẽ gây khó khăn trong theo dõi giá trị của biến, bạn sẽ phải phân vân việc liệu giá trị của biến bị thay đổi ở đâu không hay thay đổi những gì... Để giải quyết vấn đề này hãy cố gắng sử dụng khai báo const
nhiều nhất có thể, khi sử dụng const
bạn sẽ không gán lại giá trị cho biến đó được nữa.
Nhưng mình const
là chưa đủ, trong Javascript các kiểu dữ liệu không nguyên thủy như Array, Object... có tính tham chiếu. Dữ liệu đó khi được gán vẫn có thể thay đổi được giá trị của các phần tử, thuộc tính bên trong nó. Vì thế đôi khi chẳng may bạn sửa dữ liệu tham chiếu, các biến khác cũng vô tình bị thay đổi theo. Để tìm hiểu kĩ hơn, các bạn có thể đọc bài viết Đôi điều về Object Reference trong Javascript. Nhiều lúc quên thật phiền toái! của tôi trên estacks.
Thay vì update trực tiếp vào dữ liệu tham chiếu, chúng ta nên sao chép "sâu" (deep copy) dữ liệu có tính chất tham chiếu sang một biến khác để xử lý. Tránh việc thay đổi gây ra những lỗi tiềm ẩn sau này.
Để giải thích cho điều này, tôi sẽ lấy một ví dụ về một hàm lấy ra thuộc tính name trong một mảng dữ liệu:
const users = [
{
name: "A",
age: 18
},
{
name: "B",
age: 19
},
{
name: "C",
age: 20
},
];
// cách thứ nhất viết một hàm dùng map để lấy ra name
function usersWithName(users) {
return users.map(function(user) {
return {
name: user.name,
};
});
};
// cách thứ hai, vẫn dùng map nhưng ứng dụng curry function
const get = (attribute) => (data) => data[attribute];
const usersWithName = users.map(get("name"));
Trong ví dụ tôi có sử dung Curry function, nếu bạn chưa biết về curry function cũng như ứng dụng của nó thì có thể đọc thêm tại Curry function là gì? Một món "cà ri" ngon và làm sao để thưởng thức nó?.
Trở lại với ví dụ trên, tôi có hai cách viết để cùng đạt được kết quả.
Cách thứ nhất là cách viết thông thường, tôi viết theo dòng suy nghĩ cần phải làm từng bước để có kết quả.
Cách thứ hai, thay vì viết theo dòng suy nghĩ thì tôi tạo ra một hàm get
dùng để lấy dữ liệu của thuộc tính trong một object, sau đó đưa nó vào hàm map.
Bằng cách thứ hai, nếu chúng ta tạo thói quen định nghĩa những hàm như get
sẽ giúp tạo sự thống nhất trong toàn dự án mặt khác người đọc khi thấy get
họ cũng hiểu được đoạn mã đó đang làm gì.
Hãy cố gắng tạo ra những đoạn mã chỉ tập trung vào một chức năng nào đó sẽ giúp cho mã của bạn có thể tái sử dụng lại. Đồng thời nó cũng tạo sự thống nhất trong toàn dự án, điều đó cũng đồng nghĩa với việc khi bạn thấy nó, bạn có thể biết được nó đang làm gì.
Nhìn vào ví trụ trên ở cách thứ hai, hàm get có thể tái sử dụng nhiều lần, thay vì get("name") tôi có thể get("age")... Hơn nữa mỗi khi nhìn thấy hàm get
chúng ta có thể biết ngay là nó "lấy giá trị của thuộc tính" thay vì phải đọc một đoạn code dài như cách một để hiểu được người viết đang muốn làm gì.
Những lợi ích của việc tạo ra những đoạn mã có thể tái sử dụng được nhiều lần đã được cộng đồng phát hiện từ rất lâu về trước. Họ đã tạo ra những thư viện gồm có tập hợp của các hàm giúp chúng ta trong việc xử lý dữ liệu. Một trong số đó có thể kể đến như underscore, lodash, ramda... Chúng cũng được sử dụng rộng rãi trong các dự án trên github, cũng như có số lượng commit và collaborators rất lớn.
Một ví dụ như trong lodash, có đến gần 50 hàm tiện ích để xử lý dữ liệu là Object. Trong đó có cả những hàm tương tự như get
ở trong ví dụ trên của tôi và hầu như bạn muốn làm gì cũng có hàm có thể đáp ứng.
Ví dụ tôi sẽ kết hợp các hàm trong lodash để giải quyết ví dụ ban đầu, hơn nữa còn thêm một điều kiện là thứ tự name
được lấy ra sắp xếp theo mức độ giảm dần của age
:
_.chain(users).orderBy("age", "desc").map("name").value();
5 bài học sâu sắc
Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!
Đăng ký nhận thông báo bài viết mới
Bình luận (0)