Test Driven Development

all-code-is-guilty-until-proven-innocent.jpg

Nếu là một lập trình viên thì hẳn bạn đã nghe tới khái niệm Test Driven Development – TDD. Mặc dù đây là một khái niệm không mới, tuy nhiên không phải ai cũng thực sự hiểu được và có thể vận dụng vào công việc lập trình. Ngay cả những lập trình viên dày dạn kinh nghiệm, khái niệm TDD dường như chỉ là một thuật ngữ giống như bao thuật ngữ khác trong ngành lập trình. Vâng, đúng là chúng ta có thể sống khoẻ mà không cần tới TDD, nhưng một khi bạn đã làm quen với TDD, cuộc đời bạn sẽ sang trang mới, bạn sẽ yêu công việc lập trình hơn, bạn sẽ tự tin hơn đối với mỗi dòng code bạn viết ra, và không ngần ngại chỉnh sửa một đoạn code bất kỳ trong một tập source code lên tới hàng chục nghìn line. Vậy TDD là gì mà hay vậy?
Bình thường quy trình code của bạn có thể như sau:

  1. Bạn nhận được một yêu cầu của khách hàng hay của team lead.
  2. Bạn cắm đầu vào code dựa theo yêu cầu trên
  3. Khi bạn cảm thấy code đã chạy, hoặc xong một phần nào đó, bạn bắt đầu viết test case. Trong một số trường hợp, bạn thậm chí không thèm viết test case, tại sao cần test case chứ? hãy để QA lo việc phát hiện bug!
  4. Sau khi phát hiện bug từ test case hoặc QA, bạn debug để dò ra đoạn code gây lỗi và fix, bạn có thể sửa lại test case nếu cần, và chuyển lại code cho QA.
  5. Lặp lại bước 4 cho đến khi hết bug, hoặc tệ hơn, khi đã đến deadline phải bàn giao sản phẩm >”<.

Có lẽ bạn đã quá quen với cách làm việc này đến nỗi bạn cho nó là rất bình thường, thậm chí một số cty còn đánh giá QA dựa trên số bug mà họ bắt được! Thực tế QA phải không tìm thấy bug nào, và nếu là một lập trình viên chuyên nghiệp, bạn phải chịu trách nhiệm cho đoạn code mà bạn viết ra. Tất nhiên để đảm bảo điều này là một việc không hề đơn giản, lập trình là một nghề phức tạp, đòi hỏi phải đối mặt với những bài toán phức tạp và nhiều chất xám phải bỏ ra. TDD, do vậy, sẽ là một phương pháp hỗ trợ cho bạn rất đắc lực cho việc đạt được điều đó.
Hãy xem ba quy tắc của TDD sau đây:

  1. Bạn không được viết production code trước khi bạn có một test case bị failed.
  2. Bạn không được viết nhiều code cho một unit test hơn số code đủ để test case đó bị failed – và không chạy có nghĩa là failed.
  3. Bạn không được viết nhiều production code hơn cần thiết để pass test case bị failed hiện tại.

 

Ba quy tắc này sẽ ép bạn vào một chu trình làm việc rất ngắn, có thể chỉ ba mươi giây. Bạn sẽ bắt đầu viết một vài dòng code cho một unit test. Nhưng ngay lập tức bạn phải đề cập tới vài class hoặc function mà bạn chưa viết ra, và như vậy unit test sẽ failed. Bạn sẽ viết production code để đoạn code unit test chạy. Bạn không thể viết nhiều code hơn và vì thế bạn sẽ viết nhiều unit test hơn.
Cứ như vậy, bạn thêm một chút code vào unit test, thêm một chút code vào production code. Hai luồng code này tăng lên đồng thời để bổ sung cho nhau. Test code sẽ khớp với production code giống như kháng thể khớp với kháng nguyên vậy!
TDD đem lại những lợi ích rõ ràng sau đây (nhưng cũng có thể có những lợi ích khác nữa mà bạn sẽ tự khám phá ra):

  1. Bạn sẽ chắc chắn hơn về source code của mình. Vì sao? Vì bạn đã có những test case để đảm bảo code của bạn chạy đúng, miễn là unit test của bạn đủ tốt.
  2. Code sẽ ít bị nhiễm bug hơn. Cùng với thời gian, khi tính năng tăng lên, số lượng request phải đáp ứng cũng tăng lên, do đó mà lượng code cũng tăng lên tương ứng, TDD sẽ đảm bảo những dòng code thêm vào sẽ không làm gia tăng số bug một cách đột ngột.
  3. Bạn tự tin hơn. Trước đây, khi nhìn vào những đoạn code sida, bạn sẽ lắc đầu bỏ đi mà không dám sửa, đó là bởi vì bạn sợ rằng sửa những dòng code trong mớ hỗn độn ấy sẽ làm phát sinh bug, và bug đó sẽ là do bạn gây nên! Còn bây giờ bạn đã có một tập test case mà bạn có thể tin tưởng, bạn sẽ lập tức sửa lại, và code sẽ đơn giản hơn, bug phát sinh cũng ít hơn. Bạn sẽ nhàn nhã hơn cùng với thời gian, bạn có nhiều thời gian hơn để tận hưởng cuộc sống.
  4. Bạn có một tài liệu tốt hơn. Thường những framework mà bạn sử dụng sẽ có kèm document rất đẹp, trình bày rõ ràng với nhiều màu sắc hấp dẫn. Đi kèm theo đó là một số đoạn code sample phía sau cùng ở phần phụ lục được trình bày kém hấp dẫn hơn. Nhưng là một lập trình viên, bạn sẽ ngay lập tức xem những đoạn sample code trước, vì bạn biết đó là nơi bạn sẽ tìm thấy câu trả lời thực sự. Những test case bạn viết sẽ là tài liệu mô tả cách hệ thống làm việc. Nếu bạn tuân thủ ba quy tắc nêu trên của TDD, thì bạn có thể tìm thấy cách hoạt động của hệ thống tới từng chi tiết nhỏ nhất. Đó sẽ là tài liệu quý giá ở mức lowest-level tốt nhất mà bạn có thể có.
  5. Bạn có một Design tốt hơn. Khi bạn tuân theo ba quy tắc của TDD, bạn sẽ phải đối mặt với một khó khăn. Thường là bạn biết phải viết code như nào, nhưng TDD lại không cho phép bạn code, mà phải viết unit test bị failed vì code đó chưa tồn tại! Có nghĩa là bạn phải viết test case cho những đoạn code mà bạn sắp viết. Đôi khi viết test code khó vì function bạn test sẽ gọi tới những function khác, do đó bạn cần tìm cách nào đó để tách function này khỏi ảnh hưởng của function khác. Có nghĩa là TDD bắt buộc bạn phải nghĩ đến một Design tốt. Nếu không có một design tốt, bạn sẽ không thể test từng function riêng lẻ. “Nhưng tôi có thể viết test case sau mà!” – Đúng, bạn có thể viết test case sau, và bạn thậm chí có thẻ có một tỉ lệ test coverage rất cao. Nhưng test case viết sau khi code chạy là “sự biện hộ”, test case viết trước mới là “sự tố cáo”. Test case bạn viết sau khi đã biết code chạy như nào thì không bao giờ tốt bằng test case được viết trước.

Mặt khác, TDD không phải là một tôn giáo hay một công thức thần kỳ. TDD có thể không mang lại lợi ích nào, và bạn vẫn có thể biết những đoạn code sida, hay test case lởm. Có một số trường hợp, TDD không thể áp dụng được, mặc dù những trường hợp này rất hiếm hoi.

Bài viết dựa trên chapter 5 – Test Drivent Development, The clean coder, Robert C. Martin.

Leave a comment