Clean Code with Exception

Không biết anh em lúc mới làm quen thế nào chứ lúc mình học Java thì cái làm mình cảm thấy khó chịu nhất là Exception. Cứ hở một chút là bắt try/catch (sẽ có một bài viết chi tiết hơn về vấn đề này) và làm cho code mình trở nên cực kỳ kinh khủng. Nhưng sau thời gian tìm hiểu thì mình nhận thấy đây là một thứ khá hay ho trong lập trình.

Vì sao à? Đọc tiếp nhé :v

Giả sử team mình nhận được một yêu cầu từ síp lớn là viết chương trình tính và chuyển lương cho nhân viên công ty. Từ yêu cầu này síp mình phân tích cần làm 3 việc sau:

  1. Tính lương cho nhân viên -> mình làm
  2. Chuyển lương tới nhân viên -> bạn ngồi kế bên làm
  3. Điều phối việc tính và chuyển lương -> síp làm

Thông số truyền vào số ngày làm việc trong tháng và tiền lương trong một ngày. Quá đơn giản phải k ;)

1
2
3
pubic int calcSalary(int workingDay, int salaryPerDay) {
    return workingDay * salaryPerDay;
}

Sau khi đưa síp review thì bị la! workingDaysalaryPerDay âm thì như thế nào?

Mình nhanh nhẩu trả lời: Thì cái thằng gọi bên ngoài phải handle chứ!
Ổng phản damage: Tao là thằng gọi nè, chú phải tự validate chứ! Đừng quá tin anh. Vừa nói ổng vừa mỉm một nụ cười bí ẩn :~

Thế là hậm hụi ngồi viết lại :(.

Từ yêu cầu của síp ta cần trả về thông tin để síp có thể biết lúc nào thông tin nhập bị lỗi, lỗi cụ thể là gì và kết quả lương nếu không có lỗi. Vấn đề bắt đầu từ đây. Từ signature của hàm dễ hiểu nhìn vào là hiểu ngay. Giờ phải thêm thông tin để hàm gọi biết param truyền vào đúng valid không nên mình trả về là một class chứa lương và mã lỗi, mã lỗi là 0 tương ứng không có lỗi

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class SalaryResult {
    private int salary = 0;
    private int errorCode = 0;

    // getters and settters
}

pubic SalaryResult calcSalary(int workingDay, int salaryPerDay) {
    SalaryResult res = new SalaryResult();
    
    if(workingDay < 0) {
        res.setErrorCode(1)
    }

    if(salaryPerDay < 0) {
        res.setErrorCode(2)
    }

    res.setSalary(workingDay * salaryPerDay)
    
    return res;
}

Síp review thì lại bắt sửa tiếp. Lý do vì ổng phải điều phối việc tính lương và chuyển lương. Handle mã lỗi thôi thì ổng phải map mấy cái mã lỗi trả về để show cho user. Việc này thì ổng nói không phải là việc của ổng, “It not my business”. WTF x2 ;))

Như vậy mình cần làm cách nào đó để thỏa các yêu cầu sau:

  1. Signature của hàm phải tưởng minh. Nhìn cái hiểu liền
  2. Trả về cho thằng gọi chi tiết về lỗi nhất có thể
  3. Break flow khi có lỗi xảy ra

Sau thời gian tìm hiểu thì cái vấn đề của mình gặp thì cũng đã có rất nhiều người gặp và nó đã được giải quyết với một cách đơn giản là Exception như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public int calcSalary(int workingDay, int salaryPerDay) throws Exception {

    if(workingDay < 0)
        throw new Exception("WorkingDay less than zero");

    if(salaryPerDay < 0)
       throw new Exception("SalaryPerDay less than zero");

 return workingDay * salaryPerDay;
}

Như vậy chỉ cần thêm khai báo throws Exception và khi throw exception mình truyền thêm message thì mọi chuyện trở nên rất đơn giản.

Demo chương trình bây giờ như sau:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Salary {
    public static void main(String[] args) {

        try {
            int salary = calcSalary(21, 1_000_000);
            System.out.println("Salary: " + salary);

            // bla bla ble...
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static int calcSalary(int workingDay, int salaryPerDay) throws Exception {

        if (workingDay < 0)
            throw new Exception("WorkingDay less than zero");

        if (salaryPerDay < 0)
            throw new Exception("SalaryPerDay less than zero");

        return workingDay * salaryPerDay;
    }
}

Các bạn có thể thay thế thay thế workingDay hoặc salaryPerDay nhỏ hơn 0 để xem kết quả nhé

Kết luận: bằng việc sử dụng Exception ta có thể:

  • Làm cho method signature dễ hiểu
  • Trả về thêm thông tin lỗi (nếu có) bằng cách sử dụng custom Exception, mình sẽ có bài nói rõ hơn về cái này nhé.
  • Code control bên ngoài dễ hiểu hơn khi tách biệt code bussiness và handle lỗi, mình cũng sẽ có bài về phần này
updatedupdated2020-10-222020-10-22
Load Comments?