Tại sao nên sử dụng Test Driven Development (TDD)
Bài đăng này đã không được cập nhật trong 7 năm
Bài viết này mục đích chủ yếu là phân tích tính ưu việt của TDD với hi vọng giành được sự đồng tình của các nhà quản lý, người dạy và người học. Quy trình được giới thiệu sau đây không quá phức tạp, tuy nhiên nó đòi hỏi phải hiểu đúng và thực hiện nghiêm túc. Tuy nhiên, thực tế trong ngành CNTT của chúng ta: việc kiểm thử (nghĩa hẹp mà từ “test” đang được hiểu) chỉ được thực hiện sau khi chương trình viết hoàn chỉnh!
Phát triển hướng kiểm thử TDD (Test-Driven Development) là một phương pháp tiếp cận cải tiến để phát triển phần mềm trong đó kết hợp phương pháp Phát triển kiểm thử trước (Test First Development) và phương pháp Điều chỉnh lại mã nguồn (Refactoring). Mục tiêu quan trọng nhất của TDD là hãy nghĩ về thiết kế của bạn trước khi viết mã nguồn cho chức năng.
TDD là gì?
TDD (Test Driven Development) là một phương thức làm việc, hay một quy trình viết mã hiện đại. Lập trình viên sẽ thực hiện thông qua các bước nhỏ (BabyStep) và tiến độ được đảm bảo liên tục bằng cách viết và chạy các bài test tự động (automated tests). Quá trình lập trình trong TDD cực kỳ chú trọng vào các bước liên tục sau:
- Viết 1 test cho hàm mới. Đảm bảo rằng test sẽ fail.
- Chuyển qua viết code sơ khai nhất cho hàm đó để test có thể pass.
- Tối ưu hóa đoạn code của hàm vừa viết sao cho đảm bảo test vẫn pass và tối ưu nhất cho việc lập trình kế tiếp
- Lặp lại cho các hàm khác từ bước 1 Thực tế, nên sử dụng UnitTestFramework cho TDD (như JUnit trong Java), chúng ta có thể có được môi trường hiệu quả vì các test được thông báo rõ rang thông qua màu sắc:
- Đỏ: test fail, chuyển sang viết function cho test pass
- Xanh lá: viết một test mới hoặc tối ưu code đã viết trong màu đỏ.
Có một cách làm khác!
Test trước hay test sau?
“Test trước” là dấu hiệu quan trọng của TDD. Quy trình đầy đủ sẽ là “test trước, trong và sau”. Mô hình “ba test” này gọi là Test-Driven Development (TDD).
TDD = TFD + Refactor
-
Trong thực tiễn phát triển phần mềm, test dần thể hiện được vai trò của nó. Năm 1994, Kent Beck viết test framework đầu tiên cho môi trường ngôn ngữ SmallTalk. Với ưu thế rõ rệt, TDD nhanh chóng được tiếp thu và hầu như các ngôn ngữ lớn trên thế giới đều đã có test framework của mình. Ngày nay, TDD đã trở thành một chuẩn mực trong việc phát triển phần mềm.
-
TDD được hiểu là việc phát triển phần mềm có sự tham gia ( đóng vai trò định hướng) chặt chẽ của test. Về mặt triển khai, TDD là mô thức phát triển phần mềm đã được quy trình hoá.
So sánh Test Driven Development với tư duy cũ
Trước khi bắt đầu, hãy nhớ khái niệm test trong TDD đã được mở rộng hơn so với lập trình truyền thống.
Phân biệt test với dò lỗi (bug)
- Công đoạn test trong “test sau” (lập trình truyền thống) là việc sau khi viết xong toàn bộ, người ta đưa chương trình vào môi trường production (môi trường làm việc thật) hoặc mô phỏng để chạy thử xem có phát sinh lỗi hay không.
- “Test trước”: khi bạn viết xong phần tử test đầu tiên (nó sẽ fail!) là khi bạn hiểu và trình bày được yêu cầu của bài toán.
- TDD (TFD + Refactor) chính là việc viết nháp với những dấu chấm lửng. Trong quá trình bạn viết test, bạn sẽ “nháp” và “xoá nháp” đi nhiều lần. Chỉ sau vài lượt như vậy, bài toán và thiết kế lời giải của bạn tiến rất gần đến mức thực tế!
Tư duy giải quyết vấn đề
Hiểu “test” theo nghĩa rộng của nó trong TDD, bạn sẽ không còn thấy nó ngược đời nữa. Trái lại, TDD còn rất tự nhiên, vì đó là quy trình được thiết kế cho con người:
- Khi gặp một bài toán, tư duy thông thường để giải quyết sẽ lần lượt qua các bước:
- Bước 1: Phân tích vấn đề và đưa ra yêu cầu (tức kết quả muốn đạt được)
- Bước 2: Phương hướng giải chung nhất (Trong lập trình: thường được thể hiện lại trên các sơ đồ UML)
- Bước 3: Cho ra lời giải cụ thể bằng ngôn ngữ tự nhiên hay trừu tượng (Concept)
- Bước 4: Thao tác (Trong lập trình: thể hiện lại lời giải trên bằng ngôn ngữ máy tính)
- Hầu hết mọi người sẽ đồng tình với các bước trên, nhưng đến khi bắt tay vào việc thì không phải ai cũng làm như vậy. Bước thao tác luôn là bước tốn nhiều thời gian nhất. Chính vì thế nhiều người bị sa đà vào bước này.
- Với các bài toán nhỏ, chẳng hạn như việc giao tiếp hàng ngày, 3 bước đầu diễn ra ngay trong vô thức. Khi các bài toán lớn hơn, nhất là khi nó trở thành một dự án tốn nhiều tháng thậm chí nhiều năm triển khai, thời gian cho 3 bước đầu lại không được nhân lên với tỉ lệ tương xứng!
- Hãy nhớ: Nếu chỉ cốt là giết được nhiều thời gian, bước 4 không cần đến kết quả của 3 bước trước Thiếu đi chúng, nhà phát triển có xu hướng làm “thứ mình có (thể)” thay vì “thứ họ/mình cần”.
- Không có mục tiêu, chúng ta luẩn quẩn trong “giới hạn kỹ thuật” mà mình tự đặt ra, hoặc mải mê “đột phá sáng tạo” ở một nơi không cần thiết. Theo đó, sản phẩm cuối cùng rất có thể sẽ là một con quái vật.
Tiết kiệm thời gian?
Sẽ có người cho rằng: Với TDD thì phải viết thêm cả test nữa, làm sao nói là tiết kiệm thời gian hơn được?
Việc viết “test trước” như đã nói, đóng vai trò như viết nháp. Khi không làm như vậy, bạn vẫn mất thời gian cho việc suy nghĩ trong đầu, chỉ là chi phí thời gian này đã không được tính vào tổng chi phí thôi. Quá trình thể hiện ra ngôn ngữ máy tính chắc chắn phải đi qua những “non-computable functions” trong đó có những thành phần phức tạp. Biết rõ tổng quan (3 bước đầu) giúp chúng ta có thể lựa chọn một trong các phương án:
-
Tìm kiếm các thư viện sẵn có (thế mạnh của nguồn mở là đây!)
-
Thuê một bên thứ ba triển khai
-
Thành lập đội chuyên trách
-
Các ví dụ điển hình hơn cho “non-computable functions” thường là các đoạn chương trình cần một thuật toán để xử lý. Chẳng hạn “tự động in ra danh sách các bài viết có liên quan” sẽ đòi hỏi phải xây dựng một thuật toán phân tích nội dung của các bài viết. Nhưng nếu như nguồn lực có hạn thì thuật toán có thể chỉ là tính toán số thuộc tính từ khoá chung. Khẩu hiệu của ngành CNTT là “Nothing is impossible!”, nhưng chọn cái impossible nào để hiện thực hoá thì cần phải thực tế.
Phòng bệnh hơn chữa bệnh
Với việc sử dụng TDD kết hợp với functional programming style, dev có thể tránh được hầu hết lỗi khi chương trình được viết xong! Lập trình viên tuân thủ quy trình TDD sẽ không mất phần lớn thời gian cho việc dò lỗi giống như cách làm trước đó.
- Để hiểu giá trị của việc làm rõ yêu cầu, hãy hỏi những người đã đầu tư cả triệu USD vào một mặt hàng không bán được.
- Để hiểu giá trị của việc vạch ra hướng giải chung, hãy hỏi những người hàng ngày tham gia giao thông Hà Nội về quy hoạch đô thị.
- Để hiểu giá trị của việc refactor, hãy hỏi người đã bỏ tiền ra mua những “chung cư cao cấp” về sự hợp tác của chủ đầu tư!
Tài liệu cho nhà phát triển
Các nhà phát triển thường khoái đọc code và những ví dụ hơn là gặm nhấm tập tài liệu giải thích các vấn đề kỹ thuật bằng ngôn ngữ phi kỹ thuật (như bài viết này đang làm ^^). TDD làm chính xác công việc đó! Thêm một vài comment trước mỗi test nếu cần, bạn đã có tài liệu hướng dẫn cho các nhà phát triển khác (và cho chính bạn!). Quả là “nhất cử lưỡng tiện”. Tất nhiên cần phân biệt tài liệu cho nhà phát triển và cho người sử dụng. Tài liệu cho nhà phát triển cũng cần có hướng dẫn tổng quan, phương pháp luận, quy ước...
Kết luận
Tóm tắt
- TDD là công cụ cho nhà phát triển chuyên nghiệp, giúp nâng cao năng suất thông qua:
- Hiểu đúng bài toán
- Hướng vào mục tiêu rõ ràng, tránh được việc viết những đoạn chương trình thừa
- Các thành phần của chương trình làm đến đâu chắc chắn đến đấy -> khả năng bảo trì, mở rộng và kế thừa cao.
- Các lợi ích khác:
- Làm ví dụ minh hoạ cho nhà phát triển
- Phối hợp tốt với Agile, functional programming style, hệ thống Quản lí phiên bản.
Thực hành
- Để hướng tới sự chuyên nghiệp, người học CNTT nên biết TDD càng sớm càng tốt.
- Đọc thêm tài liệu về TDD và tài liệu một test framework nào đó của ngôn ngữ lập trình bạn đang học/dùng bằng tiếng Anh.
- Tìm hiểu thêm về TDD trên các trang video và presentation:
- tdd
- tdd examples + <your programming language>
- Tham gia một dự án nguồn mở có sử dụng TDD mà bạn thích nhưng cần xem kĩ hướng dẫn (guideline) và trao đổi với những developer có kinh nghiệm trong dự án. (Bạn không cần chuẩn bị gì nhiều, ngoại trừ tinh thần học hỏi!)
Nếu bạn chưa thành công, đừng ngần ngại!
- Với TDD chúng ta không nên nóng vội:
- Ngay cả Microsoft cũng từng có hướng dẫn về TDD cho lập trình viên hết sức lệch lạc (2004)!
- Trong điều kiện thực tế ở Việt Nam, tổ chức của bạn có thể chưa có đủ điều kiện về mặt nhân sự để triển khai TDD hoặc công việc hàng ngày khiến bạn chưa đủ thời gian để đi đến tận cùng của TDD. Trong trường hợp đó, xin vui lòng không để trải nghiệm cá nhân của bạn (nhất là đừng nói dối rằng bạn/tổ chức của bạn đang tiến hành TDD rất tốt!) ảnh hưởng đến quyền được biết và lựa chọn của những người có cơ hội học tập.
- Tài liệu này không nên đơn giản là đọc từ trên xuống, hay lướt qua để tìm quy trình. Hãy thoải mái “nhảy cóc” giữa các phần và thậm chí là đọc lại nhiều hơn một lượt để hiểu được các thành phần.
http://agiledata.org/essays/tdd.html http://programmable.banphim.net/test-driven-development-tdd-why/ http://www.testingvn.com/viewtopic.php?f=20&t=304 https://msdn.microsoft.com/en-us/library/aa730844(v=vs.80).aspx
All rights reserved