7 trở ngại bạn sẽ gặp phải khi triển khai TDD

Bài viết sau dịch từ 1 blog trên trang http://qiita.com/

TDDを行った時にぶつかった7つの壁

Lời nói đầu

Tôi bắt đầu biết đến TDD (Test – Driven Development) vào khoảng năm 2004- 2005 gì đó ( Tôi cũng không nhớ rõ nữa). Khi đó tôi đã nghĩ mình có thể quản lý dự án bằng phương pháp này. Ngay sau đó tôi đã triển khai TDD vào thực tế, và quan sát việc ứng dụng phương pháp này. Kết quả là tôi nhận thấy tôi nên viết chi tiết những mã kiểm thử mà tôi đã hầu như bỏ qua không viết. Và tôi nhận thấy, nếu những người mù quáng tin rằng chất lượng sẽ được nâng cao nếu áp dụng TDD hay những công ty đang dùng hoặc có ý định dùng TDD tìm hiểu TDD một cách kỹ lưỡng thì tốt.

Khi bạn đọc toàn bài thì sẽ hiểu ý của tôi nhưng không có nghĩa là tôi đang phê phán, chỉ trích TDD. Tôi chỉ muốn nói rằng việc áp dụng TDD không liên quan đến giá cả hay chi phí. Vậy TDD là gì?

TDD ( Test driven development)

Nói một cách dễ hiểu thì đây là mã kiểm thử trước khi ta code chức năng của hệ thống. Nếu chỉ có thế thì có thể cho rằng việc viết test trước hay sau có hiệu quả như nhau. Tuy nhiên, việc viết test trước có thể thu được các lợi ích như dưới đây:

Bằng cách viết mã kiểm thử trước, những chương trình (program) cần được tạo sẽ được xác định rõ ràng. Nó là những yêu cầu được viết dưới dạng mã kiểm thử do những người trực tiếp tham gia phát triển hệ thống viết dựa trên những mô tả của những người không tham gia phát triển hệ thống (customer). Điều đó trở thành một lợi ích rất lớn của phương pháp này. Với một lập trình viên chưa có kinh nghiệm, khi họ bắt tay vào xây dựng một chức năng của hệ thống, nếu họ vội vàng viết ngay chương trình, họ có thể đạt được mục tiêu nhất định, tuy nhiên chương trình của họ có nguy cơ trở nên khó kiểm soát. Tuy nhiên, khi bắt đầu viết mã kiểm thử, nếu suy nghĩ kỹ trong đầu trước cần phải làm những gì thì sẽ viết chương trình dễ hơn (Điều này có nghĩa là, nhờ vào việc quyết định giao diện sẽ có những mã kiểm thử khác nhau). Đây cũng là một lợi ích lớn được phát hiện của TDD.

Tuy nhiên, thế mạnh của TDD không chỉ có vậy. Ngay ở giai đoạn ban đầu đã sinh ra những hình ảnh của chương trình sẽ được phát triển nên nó sẽ thúc đẩy việc nhận ra những mâu thuẫn trong tài liệu mô tả. Mặc dù trong trường hợp khi đang code chức năng của hệ thống mà phát hiện ra mâu thuẫn trong tài liệu mô tả và phải làm lại là một vấn đề lớn, nhưng với giai đoạn viết mã kiểm thử trường hợp này không phải vấn đề quá nghiêm trọng. Để đảm bảo hoàn thành mục đích đã nói ban đầu về việc tạo nên một hệ thống bền vững, kiên cố thì cả giai đoạn code chức năng và giai đoạn viết mã kiểm thử phải cùng hoàn thành.

Còn có rất nhiều những điểm lợi thế khác mà không thể kể hết, nhưng tôi xin được phép tóm tắt những lợi ích chủ yếu của TDD đối với tôi

Lợi thế của TDD

  1. Mã kiểm thử bắt buộc phải viết.

  2. Khi member nắm rõ được yêu cầu thì việc phát triển sẽ diễn ra suôn sẻ hơn.

  3. Ở phần mở rộng số 2, vì việc cần làm gì, làm như thế nào thì tốt có thể định nghĩa ở ngay từ giai đoạn đầu nên có thể dễ dàng hơn trong việc xác định được chương trình phù hợp nhất.

  4. Sớm phát hiện những điểm không hợp lý trong tài liệu mô tả.

  5. Vì xác định được những gì cần làm nên việc điều chỉnh task sẽ dễ hơn. (Đặc biệt người viết test không nhất thiết phải viết code)…

Tình huống dẫn đến việc triển khai TDD

Khi tôi biết đến TDD là lúc tôi đang làm việc với mô hình waterfall- mô hình đang tiến dần đến sự thất bại. Mã kiểm thử giống như một điều ngớ ngẩn khi đó, thậm chí tình huống lúc đó là các task không được hiểu rõ và chỉ làm theo các yêu cầu phù hợp được ghi trong file excel.

Đến năm 2009

Khi tôi đã đảm nhiệm việc quản lý rất nhiều dự án, khi kinh nghiệm thực tế tăng lên, tôi nhận thấy giới hạn trong trình độ hiện tại. Từ đó tới nay, tôi đã bắt đầu một dự án để thử nghiệm những gì học được về quá trình phát triển agile. Và tôi nhận ra rằng có vẻ như một phần của quá trình phát triển agile bao gồm cả TDD.

7 trở ngại bạn sẽ gặp phải khi triển khai TDD

Trở ngại đầu tiên

Khi tôi bắt đầu thực hiện TDD mọi thứ diễn ra tốt đẹp, và tôi đã mù quáng tin như vậy. Khi đó, ở dự án được khởi động có sử dụng 2 hệ thống của Rails, tôi nghĩ rằng môi trường test đã sẵn sàng… Tuy nhiên lại xảy ra vấn đề khi kiểm thử có liên quan đến request/ response của HTTP, ếu là unit test thông thường thì có thể sử dụng môi trường đó, nhưng trong tình huống này, thì phải viết thêm một phần nhỏ hỗ trợ mã kiểm thử với môi trường không bền vững (Khi đó tôi chưa được biết đến RSpec). Vì vậy, lúc đó chúng tôi đã phải tốn mốt chút thời gian cho công việc chuẩn bị môi trường. Không đến mức như RSPEC, nhưng để có thể viết được những kịch bản kiểm thử dưới dạng văn bản mà khách hàng có thể đọc được, chúng tôi đã thực sự bỏ nhiều công sức vào nó.

Trở ngại thứ 2

Mã kiểm thử phải đảm bảo lựa chọn được những điều trọng yếu để kiểm thử web application

Tôi đã rất phiền não về vấn đề này. Nếu làm theo như unit test thì sẽ nảy sinh những vấn đề dưới đây:

  1. Để có thể viết được kịch bản test, người viết cần có hiểu biết sâu sắc về hệ thống. Chính vì thế, việc viết test case trở nến rất tốn thời gian và công sức.

  2. Nếu sử dụng kiến trúc của Rails, trong đó lập trình viên không viết code trong model, khi đó sẽ có rất nhiều test case kiểm tra những phần nhỏ trong controller. Trong rất nhiều trường hợp, những test case này thực sự không cần thiết.

Khi bắt đầu viết TDD, việc nhận định vấn đề này khiến tôi rất mất thời gian. (Như dòng đầu tiên có nói, mã kiểm thử cần đảm bảo lựa chọn được những điều trọng yếu của app. Tức là phải biết nên kiểm thử cái gì)

Kết quả là, tôi tập trung vào việc kiểm tra quá trình integration test trong thời kỳ đầu của dự án. (Điều đó không có nghĩa là không viết test case, tôi chỉ bỏ qua việc kiểm tra unit test trong quá trình review code của cả hệ thống). Với lý do trên, một lợi thế của TDD là member sẽ nắm vững được SPEC.

Trở ngại thứ 3

Đây là thời điểm chúng tôi bắt đầu phát triển TDD. Sau khi member viết test case, chúng tôi kiểm tra xem test case đó thực sự dễ thực thi hay không, có thể đóng vai trò tài liệu hay không, trước khi đưa nó vào thực tiễn. Ngay từ đầu, test case cũng chỉ nhắm đến kiểm tra việc chuyển đổi giữa các màn hình hay các thao tác xử lý đơn giản, thế nên ai viết test thì cũng có một kịch bản như nhau. Vấn đề ở thời điểm này, là có những xử lý đơn giản đến mức không cần viết test case, nhưng vẫn bắt buộc phải viết.

Với các thao tác cơ bản của CRUD, thì nhưng dòng code kiểm tra màn hình quản lý user, màn hình quản lý category,... sẽ bị lặp đi lặp lại rất nhiều. Kết quả là những mã kiểm thử được copy paste tăng lên, việc bị bắt làm đi làm lại một công việc khiến cho nhân viên của chung tôi rơi vào trạng thái không còn động lực làm việc.

Trở ngại thứ 4

Phát sinh vấn đề không thể kiểm tra mã kiểm thử

Mặc dù muốn commit, nhưng do trước đó đã có test code rồi, nên không thể commit những dòng mình đã viết (vì test case bị sai). Lý do được nhắc đến nhiều nhất ở đây là do quên, ngoài ra cũng có nguyên nhân là do thực hiện test tốn thời gian. Vì lý do đó, nhưng đoạn test code chưa được kiểm tra đã được commit lên SVN (Thời điểm đó tôi vẫn chưa biết đến Git).

Bằng việc code Ruby, tôi cho rằng thực hiện test là điều bắt buộc (lúc đó tôi nghĩ vậy). Tuy nhiên, các thành viên đã không thực hiện kiểm tra test của họ như tôi mong muốn. Cùng với việc mất đi động lực làm việc, các thành viên không còn kiểm tra test code nữa...

Cuối cùng, tôi chọn cách gửi kết quả kiểm tra test code đến các member thông qua email một cách tự động vào mỗi đêm. Lúc đó các thành viên trong dự án bắt đầu hiểu ra mặt tốt và xấu của TDD.

Ban đầu, bằng việc thực hiện integration test, member sẽ hiểu cơ bản về các yêu cầu request và response. Từ đó bắt tay tiếp tục phát triển hệ thống. Chúng tôi phát huy cách làm vậy để đạt được hiệu quả cao nhất.

Ngược lại, nhưng logic nghiệp vụ có vẻ giống nhau, hay những logic được dùng chung giữa các thành phần hệ thống, dù chỉ được dùng 1 chút thì vẫn cần phải viết test code để kiểm tra. Do vậy, quá trình viết test code trở nên khó chịu đối với lập trình viên.

Phần còn lại của blog sẽ được dịch trong bài viết tiếp theo