0

Helper Trong Laravel: Đừng Biến Nó Thành "Thùng Rác" Chứa Code

Chào anh em Viblo!

Trong quá trình chinh chiến qua các dự án từ monolith đến microservices, có một "người bạn cũ" mà mình tin chắc 100% anh em đều đã từng gặp: Helper Class.

Chúng ta tạo ra chúng với ý định tốt đẹp là để tái sử dụng code. Nhưng hỡi ôi, chỉ sau vài tháng, file CommonHelper.java hay utils.py bỗng biến thành một "con quái vật" nghìn dòng, chứa đủ thứ từ format ngày tháng đến validate email, thậm chí là cả logic nghiệp vụ phức tạp.

Hôm nay, mình muốn chia sẻ một chút góc nhìn về cách chúng ta nên đối xử với Helper sao cho đúng chuẩn "trai tài gái sắc" trong lập trình.

1. Helper Class thực sự là gì?

Về bản chất, Helper là một lớp chứa các phương thức (thường là static) để thực hiện các tác vụ lặp đi lặp lại, mang tính chất bổ trợ và không giữ trạng thái (stateless).

Đặc điểm nhận dạng của một Helper "ngoan":

  • Các method là static.
  • Không phụ thuộc vào các đối tượng cụ thể của domain.
  • Chỉ nhận đầu vào, xử lý và trả về kết quả (Pure Functions).

2. Những sai lầm "chí mạng" thường gặp

A. Biến Helper thành "thùng rác" (The Junk Drawer)

Sai lầm lớn nhất là gom tất cả mọi thứ vào một class duy nhất mang tên GlobalHelper. Khi bạn cần tìm một hàm format tiền tệ, bạn phải lặn ngụp trong một đống hàm xử lý String, Array và Date.

B. Đưa Business Logic vào Helper

Helper sinh ra để trợ giúp về kỹ thuật, không phải để giải quyết nghiệp vụ. Nếu bạn thấy mình đang viết Helper.calculateDiscountForVIP(), hãy dừng lại! Đó là việc của Service hoặc Domain Model.

C. Lạm dụng Static dẫn đến khó Unit Test

Vì các method là static, việc mock chúng trong Unit Test đôi khi trở thành cơn ác mộng (đặc biệt là với các ngôn ngữ cứng nhắc).

3. Viết Helper sao cho "ngon"?

Để bài viết có giá trị thực tiễn, mình đề xuất quy tắc 3S:

1. Specific (Cụ thể)

Thay vì một file Utils.js khổng lồ, hãy chia nhỏ theo trách nhiệm:

DateHelper: Chỉ xử lý thời gian.

StringHelper: Chỉ xử lý chuỗi.

FileHelper: Chỉ xử lý đọc/ghi file.

2. Stateless (Không trạng thái)

Một Helper không nên ghi nhớ bất cứ điều gì. Kết quả của hàm chỉ phụ thuộc vào tham số truyền vào.

f(x)=yf(x) = y

(Truyền xx vào thì 100 lần vẫn phải ra yy, không được thay đổi dựa trên biến global nào cả).

3. Static-Only (Ngăn chặn khởi tạo)

Để tránh việc anh em khác new một Helper class vô nghĩa, hãy chặn nó lại:

public class StringHelper {
    private StringHelper() { // Private constructor để chặn khởi tạo
        throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
    }
    
    public static String toSlug(String input) {
        // logic ở đây
    }
}

4. Khi nào nên "chia tay" Helper?

Nếu một Helper Class bắt đầu cần inject các dependency khác (như Repository hay Database), đó là lúc nó nên được chuyển hóa thành một Service hoặc một Component. Đừng cố chấp giữ nó ở dạng static.

Kết luận

Helper Class giống như một con dao đa năng. Nếu biết cách sắp xếp, nó sẽ giúp workflow của bạn cực kỳ mượt mà. Ngược lại, nó sẽ trở thành một mớ hỗn độn khiến người đến sau (hoặc chính bạn sau 3 tháng) phải thốt lên kinh hãi.

Hy vọng chút chia sẻ này giúp ích cho anh em trong việc refactor code sạch đẹp hơn. Đừng quên để lại comment về cách mà anh em đang quản lý các lớp trợ giúp trong dự án của mình nhé!

Happy Coding! 🚀


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí