Có phải thiết kế đã chết?

[TCLT] Martin Fowler là diễn giả, nhà tư vấn và tác giả của rất nhiều sách có ảnh hưởng về phát triển phần mềm, thiết kế và phân tích hướng đối tượng, UML, mẫu thiết kế, các phương pháp phát triển phần mềm linh hoạt, và cả XP. Thấy được những băn khoăn của nhiều người mới bắt đầu thực hành XP và Agile về vai trò của thiết kế nên chúng tôi quyết định dịch một bài viết rất quan trọng của ông có tên “Có phải thiết kế đã chết?”

Nhiều người mới tiếp xúc với Extreme Programming (XP) cho rằng XP muốn giết chết thiết kế phần mềm. XP không chỉ chế nhạo việc thiết kế là “Big Up Front Design”(thiết kế hoàn hảo trước, viết mã chương trình sau) mà cả những kỹ thuật như UML, khung làm việc (framework) linh hoạt, mẫu thiết kế (pattern) cũng không được nhấn mạnh, thậm chí gần như là bỏ qua. Thực tế XP chứa rất nhiều thiết kế, nhưng ở một cách khác so với quy trình phát triển phần mềm đã xác lập. XP làm trẻ lại ý niệm về thiết kế tiến hóa bằng những kỹ thuật để chiến thuật thiết kế tiến hóa có thể thành công. XP cũng đưa ra những thử thách và kỹ năng mới mà một nhà thiết kế phải học đó là cách làm theo thiết kế đơn giản, cách dùng tái cấu trúc để giữ cho thiết kế trong sáng và cách dùng mẫu theo cách tiến hóa.

Tháng 5, 2004.


XP thách thức nhiều giả định phổ biến trong phát triển phần mềm. Một trong những tranh cãi lớn nhất trong số này là sự phủ nhận của thiết kế up – front, và thay vào đó là thiết kế tiến hóa. Đối với những người dèm pha thì đó là lối phát triển “lập trình và sửa” của kiểu tấn công hệ thống. Người hâm mộ thiết kế tiến hóa thì phủ nhận các kỹ thuật thiết kế (như UML), nguyên lý và mẫu thiết kế. Đừng lo lắng về thiết kế, nếu bạn lắng nghe mã nguồn của mình, một thiết kế tốt sẽ xuất hiện.

Cuộc tranh luận này diễn ra không ngừng trong tôi. Một thời gian dài tôi đã làm việc với UML, các tiền thân của UML và cả mẫu thiết kế. Thực tế tôi đã viết sách về cả UML và mẫu thiết kế. Liệu sự gắn kết của tôi với XP có nghĩa là sự công khai chối bỏ tất cả những gì đã viết về những chủ đề trên, làm sạch tâm trí tôi với những ý niệm tiến hóa? Tôi cũng không kỳ vọng có thể giúp bạn thoát khỏi tình trạng băn khoăn. Câu trả lời ngắn gọn là không. Câu trả lời dài hơn chính là phần còn lại của tài liệu này.

 

Thiết kế có kế hoạch và thiết kế tiến hóa

Trong tài liệu này tôi sẽ giới thiệu hai phong cách thiết kế trong phát triển phần mềm. Có lẽ phong cách phổ biến nhất là thiết kế tiến hóa. Bản chất, thiết kế tiến hóa được xây dựng cùng với cài đặt hệ thống. Thiết kế là một phần của quy trình lập trình, cũng như khi thay đổi thiết kế của chương trình .

Trong những áp dụng thường gặp, thiết kế tiến hóa là thảm họa. Thiết kế cuối là một mớ các thiết kế rời rạc của những quyết định cục bộ, những thiết kế gây khó khăn cho lập trình viên khi thay đổi. Bằng nhiều cách bạn có thể kết luận đây không phải là thiết kế, và điều này thường cho ta một thiết kế tồi. Như Kent nói, thiết kế cho phép ta thay đổi phần mềm một cách dễ dàng trong thời gian dài. Khi thiết kế hỏng, bạn sẽ có một phần mềm ở trạng thái hỗn loạn. Càng ngày thiết kế càng tệ hơn, bạn không chỉ khó thay đổi phần mềm mà còn khó tìm và xử lý lỗi ở một phần mềm dễ phát sinh lỗi. Đó là cơn ác mộng “viết mã và sửa lỗi”, ở đó việc sửa lỗi trở nên tốn kém theo cấp số mũ nếu dự án tiếp tục.

Thiết kế có kế hoạch được sinh ra từ đây, nó chứa một quan điểm ở một nhánh khác của kỹ thuật. Nếu bạn xây một cái chuồng chó, bạn chỉ cần ghép một vài mảnh gỗ lại theo mô hình thô nào đó. Tuy nhiên khi xây một tòa nhà chọc trời bạn không thể làm theo cách đó. Tòa nhà sẽ đổ trước khi bạn hoàn thành một nửa. Do đó bạn bắt đầu với bản vẽ kỹ thuật, bản vẽ được hoàn thành ở một phòng kỹ thuật như của của vợ tôi ở trung tâm Boston. Khi thiết kế, vợ tôi phác ra tất cả mọi vấn đề, một phần từ các phân tích toán học, còn hầu hết từ các quy tắc xây dựng. Bộ quy tắc này trình bày cách thiết kế cấu trúc dựa trên kinh nghiệm (một số dựa trên toán học). Khi hoàn thành thiết kế, công ty của cô giao cho một công ty khác để xây dựng tòa nhà.

Thiết kế có kế hoạch trong phần mềm cũng tương tự. Nhà thiết kế tìm ra những vấn đề lớn sẽ xảy ra. Họ không cần viết mã bởi họ không xây phần mềm mà họ thiết kế. Bởi thế họ có thể dùng những kỹ thuật như UML để không phải làm việc với những chi tiết của lập trình và cho phép nhà thiết kế làm việc ở mức độ trừu tượng cao hơn. Một khi hoàn thành thiết kế, họ sẽ giao cho một nhóm khác (cũng có thể là một công ty khác) để xây. Bởi nhà thiết kế nhìn ở mức cao nên tránh được những quyết định mang tính cục bộ có thể dẫn tới một phần mềm hỗn loạn. Lập trình viên có thể làm theo hướng của thiết kế để có một hệ thống được xây dựng tốt.

Cách tiếp cận thiết kế có kế hoạch xuất hiện từ những năm 70 và đã được rất nhiều người sử dụng. Theo nhiều mặt thì cách tiếp cận này tốt hơn thiết kế tiến hóa viết mã và sửa. Nhưng nó cũng có một số vấn đề. Vấn đề thứ nhất là không thể nghĩ ra hết mọi vấn đề mà bạn phải đối mặt khi lập trình. Nên không thể tránh được những vấn đề làm bạn nghi ngờ thiết kế khi lập trình. Tuy nhiên nếu nhà thiết kế đã hoàn thành và chuyển sang dự án khác thì điều gì xảy ra? Lập trình viên bắt đầu lập trình xoay quanh thiết kế và sự hỗn loạn bắt đầu. Ngay cả khi nhà thiết kế chưa đi thì việc sắp xếp lại các vấn đề, thay đổi thiết kế và mã nguồn cũng mất thời gian. Thông thường có một cách sửa nhanh hơn với áp lực thời gian. Khi đó sự hỗn loạn lại xuất hiện.

Xa hơn là vấn đề về văn hóa. Nhà thiết kế được làm việc như nhà thiết kế vì kỹ năng và kinh nghiệm, nhưng họ cũng bận rộn thiết kế và không có nhiều thời gian để viết mã nữa. Hơn nữa công cụ và tài nguyên của phát triển phần mềm thay đổi với nhịp độ nhanh. Khi không viết mã nữa thì  bạn có thể bỏ sót những thay đổi công nghệ, bạn sẽ mất đi sự tôn trọng trọng của những người viết mã.

Có căng thẳng giữa người xây dựng và thiết kế xảy ra trong xây dựng, tuy nhiên những căng thẳng này còn lớn hơn trong phần mềm. Sự căng thẳng này do một sự khác biệt cơ bản. Có sự khác biệt rõ ràng về kỹ năng giữa người thiết kế và người xây dựng trong xây dựng, nhưng không có nhiều sự khác biệt nay trong phần mềm. Bất cứ lập trình viên làm việc ở môi trường thiết kế bậc cao đều phải rất thành thục. Họ phải đủ thành thục để có thể chất vấn thiết kế của nhà thiết kế đặc biệt khi nhà thiết kế ít hiểu biết hơn về thực tại của các nền tảng phát triển.

Hiện tại ta có thể giải quyết những vấn đề này. Có lẽ chúng ta có thể giải quyết căng thẳng về mặt con người. Có thể chúng ta tìm những nhà thiết kế đủ kỹ năng để giải quyết hầu hết các vấn đề và có một quy trình đủ chặt để thay đổi thiết kế. Tuy nhiên vẫn còn một vấn đề khác: yêu cầu thay đổi. Yêu cầu thay đổi là một trong những vấn đề đau đầu nhất trong những dự án phần mềm tôi tham gia.

Một cách để thích ứng với thay đổi yêu cầu là đưa tính mềm dẻo vào thiết kế, do đó bạn có thể dễ dàng thay đổi. Tuy nhiên việc này cần có sự hiểu biết về những loại của thay đổi mà bạn mong muốn. Thiết kế có thể được hoạch định để đối phó với những loại thay đổi nhất định, nhưng khi thiết kế hỗ trợ những thay đổi tiên đoán được thì sẽ không hỗ trợ (và có thể tổn hại) cho những thay đổi không biết trước. Bởi thế bạn phải hiểu yêu cầu đủ tốt để tách những vùng thay đổi, với những quan sát của tôi điều đó là rất khó.

Bây giờ có một số vấn đề là không hiểu đủ rõ yêu cầu. Nên nhiều người tập trung vào các quy trình kỹ thuật để lấy yêu cầu tốt hơn với hy vọng sẽ tránh được việc phải thay đổi thiết kế về sau. Tuy nhiên hướng này cũng có thể không dẫn tới một liệu pháp đúng. Rất nhiều sự thay đổi trong yêu cầu xảy ra do những thay đổi trong kinh doanh. Điều này thì không thể phòng được dù quy trình xử lý yêu cầu có rất cẩn thận.

Tất cả những điều này làm cho thiết kế có kế hoạch có vẻ là không khả thi. Chắc chắn đó là thử thách lớn. Nhưng tôi không có ý là thiết kế có kế hoạch tệ hơn thiết kế tiến hóa khi nó được sử dụng theo cách “viết mã và sửa”. Thực sự tôi thích thiết kế có kế hoạch hơn là “viết mã và sửa”. Tuy nhiên tôi cũng ý thức được những vấn đề của thiết kế có kế hoạch và cũng đang tìm một hướng mới.

 

Triển khai những kỹ thuật của XP

XP gây tranh cãi vì một số lý do, trong đó có việc XP ủng hộ thiết kế tiến hóa hơn thiết kế có kế hoạch. Như chúng ta biết, có thể không dùng được thiết kế tiến hóa vì nó tạo ra từ những quyết định cục bộ và phần mềm hỗn loạn. 

Cốt lõi của nhận định trên là đường cong thay đổi trong phần mềm (change curve). Đường cong nói rằng khi dự án đang tiến hành, cái giá của thay đổi tăng theo cấp số mũ. Đường cong thay đổi thường thể hiện trong câu nói “thay đổi trong phân tích tốn 1 đô la có thể sẽ tốn hàng nghìn đô la để sửa trong sản xuất”. Điều khá hài ước là nhiều dự án vẫn chạy với quy trình cục bộ mà không có công đoạn phân tích, nhưng số mũ đã đề cập vẫn còn đó. Điều này giải thích tại sao thiết kế tiến hóa không thể hoạt động và giải thích tại sao thiết kế có kế hoạch phải được làm cẩn thận vì mọi sai sót cũng đối mặt với vấn đề cấp số mũ.

Giả định cơ bản của XP là có thể “làm phẳng” đường cong thay đổi đủ để cho thiết kế tiến hóa hoạt động. Việc làm phẳng này được hỗ trợ và khai thác triệt để trong XP. Đó chính là một chuỗi các kỹ thuật của XP, và đặc biệt bạn không thể làm phẳng đường cong thay đổi mà không áp dụng các kỹ thuật này. Nguyên nhân phổ biến của các tranh cãi về XP từ đây. Thường những lời phê bình xuất phát từ kinh nghiệm của người chỉ trích khi họ không áp dụng và khai thác các kỹ thuật này. Kết quả khiến họ phát hỏa và khi nhìn thấy XP họ nhớ về các “đám cháy”.

Có rất nhiều kỹ thuật sử dụng trong XP. Ở trung tâm là kỹ thuật Kiểm thử (testing) và Tích hợp liên tục (continuous integration). Nếu không có sự an toàn được cung cấp bởi Kiểm thử, phần còn lại của XP là không thể. Tích hợp liên tục để giữ cho nhóm đồng bộ, để khi bạn thực hiện thay đổi, bạn không phải lo lắng về việc tích hợp với người khác. Hai kỹ thuật này đi cùng nhau có thể có tác động lớn đến đường cong thay đổi. Tôi được nhắc lại điều này khi ở ThoughtWorks. Sử dụng hai kỹ thuật này đánh dấu sự cải tiến trong nỗ lực phát triển. Hiển nhiên giả thiết của XP là bạn nên áp dụng tất cả các kỹ thuật để có sự đột phá.

Tái cấu trúc (Refactoring) cũng đem lại kết quả tương tự. Người tái cấu trúc theo cách được gợi ý trong XP sẽ thấy khác biệt đáng kể trong hiệu quả so với tái cấu trúc truyền thống. Đó là kinh nghiệm của tôi khi được Kent dạy cách tái cấu trúc. Sự thay đổi mạnh mẽ này đã thúc đẩy tôi viết cả một quyển sách về nó.

Jim Highsmith, trong bản tóm tắt về XP đã sử dụng hình ảnh của một cái cân đĩa, một bên là thiết kế có kế hoạch, một bên là tái cấu trúc. Theo cách tiếp cận truyền thống , thiết kế có kế hoạch thống trị với giả thiết bạn không thay đổi sau này. Khi cái giá của sự thay đổi thấp bạn có thể làm nhiều việc với thiết kế sau khi tái cấu trúc. Thiết kế có kế hoạch không biến mất hoàn toàn, nhưng có sự thay đổi trong cán cân của hai cách tiếp cận. Tôi cảm thấy rằng trước khi tái cấu trúc, tôi luôn làm thiết kế với chỉ một tay.

Các kỹ thuật Tích hợp liên tục, Kiểm thử, Tái cấu trúc cung cấp môi trường làm cho thiết kế tiến hóa trở nên tin cậy. Tuy nhiên có một điều mà chúng ta vẫn chưa xác định, đó là vị trí của điểm cân bằng. Tôi chắc chắn rằng, ngoài lớp vỏ bọc ấn tượng, XP không chỉ có kiểm thử, viết mã và tái cấu trúc. Vẫn có chỗ cho thiết kế trước khi lập trình. Hầu hết nằm ở các phân đoạn trước khi lập trình một tác vụ cụ thể. Nhưng có một điểm cân bằng mới giữa thiết kế up- front và tái cấu trúc.

 

Giá trị của sự Đơn giản

Hai trong những lời kêu gọi lớn nhất trong XP là khẩu hiệu “Hãy làm đơn giản nhất mà có thể hoạt động” và “Bạn sẽ không cần nó”(YAGNI – You Aren’t Going to Need It). Cả hai khẩu hiệu đều nằm trong cương lĩnh của kỹ thuật Thiết kế Đơn giản (Simple Design) trong XP.

Thông thường YAGNI được môt tả là: hôm nay bạn không nên thêm đoạn mã nếu mã đó chỉ được dùng bởi các tính năng ngày mai mới cần. Bề ngoài khẩu hiệu này tưởng rất đơn giản. Vấn đề phát sinh với những thứ như khung làm việc, bộ phận tái sử dụng, và thiết kế linh hoạt. Xây dựng chúng rất phức tạp. Ban đầu bạn trả thêm phí để xây dựng chúng với kỳ vọng bạn sẽ lấy lại được về sau. Ý tưởng của việc xây dựng những thiết kế ban đầu và từ trên xuống có vẻ như là chia khóa để có thiết kế hiệu quả.

Tuy nhiên XP lại khuyên bạn không nên xây dựng thành phần linh động và khung làm việc cho lần đầu cần chức năng đó. Hãy để cho những cấu trúc này phát triển khi cần. Nếu hôm nay tôi cần lớp Money để thực hiện phép cộng mà không có phép nhân thì tôi chỉ cần xây dựng phép cộng. Dù nếu tôi có chắc chắn mình sẽ cần phép nhân cho phân đoạn tiếp theo, biết rất dễ để làm nó, và nghĩ sẽ hoàn thành rất nhanh, thì tôi vẫn để dành cho phân đoạn tiếp theo.

Một lý do để làm như thế là vấn đề kinh tế. Nếu tôi phải một việc mà chỉ dùng cho một tính năng ngày mai mới cần, điều đó có nghĩa tôi phải bỏ công sức mà đáng lý dành để phát triển những tính năng của phân đoạn này. Kế hoạch phát hành cho thấy những việc cần làm ngay, và nếu làm những việc cho tương lai có nghĩa là đi ngược lại thỏa thuận của lập trình viên với khách hàng. Có rủi ro là không hoàn thành những yêu cầu (story) của phân đoạn này. Ngay cả khi không có rủi ro đó thì cũng phụ thuộc vào việc khách hàng quyết định những tính năng thêm, và có thể vẫn chưa có phép nhân.

Vướng mắc kinh tế này bao gồm khả năng chúng ta hoàn thành đúng yêu cầu. Ngay cả khi biết chức năng này làm việc như thế nào thì vẫn có khả năng chúng ta làm sai, đặc biệt khi chưa có yêu cầu chi tiết. Làm những giải pháp sai từ sớm còn lãng phí hơn làm ra những giải pháp đúng từ sớm. Và những người thực hành XP thường cho rằng sai nhiều hơn đúng (và tôi đồng ý với cảm nghĩ này.)

Lý dó thứ hai cho thiết kế đơn giản là một thiết kế phức tạp khó hiểu hơn một thiết kế đơn giản. Do đó sự thay đổi trong những hệ thống phức tạp như thế là khó khăn hơn. Điều này tăng thêm chi phí trong khoảng thời gian bạn thêm vào một thiết kế phức tạp hơn cho tới khi bạn thực sự cần.

Lời khuyên này bây giờ không có giá trị với nhiều người, họ đúng khi nghĩ như vậy.

Điều này cho phép bạn thấy trong thế giới phát triển phần mềm thông thường các kỹ thuật của XP không được dùng. Tuy nhiên khi sự cân bằng giữa thiết kế có kế hoạch và thiết kế tiến hóa thay đổi thì YAGNI lại là một kỹ thuật tốt (và chỉ khi đó).

Tổng kết lại. Bạn không muốn mất nhiều công sức để thêm một tính năng chưa cần tới trước một phân đoạn trong tương lai. Và ngay cả khi nó không tốn kém gì, bạn cũng chưa muốn thêm vào bởi việc thêm đó sẽ tăng chi phí thay đổi. Tuy nhiên bạn chỉ có thể làm như thế một cách hợp lý khi bạn dùng XP hoặc một kỹ thuật tương tự với chi phí thay đổi nhỏ hơn.

 

Dẫu sao mọi thứ trên Trái đất đều đơn giản

Do đó chúng ta muốn mã của mình đơn giản nhất có thể. Điều này có vẻ không quá khó để tranh luận, sau tất cả thì ai muốn phức tạp? Nhưng điều này tất nhiên sẽ đặt ra câu hỏi “đơn giản là gì?”

Trong XPE đưa ra bốn tiêu chí của một hệ thống đơn giản. Theo thứ tự (quan trọng trước):

  • Mọi kiểm thử phải chạy
  • Mọi ý định đều rõ ràng
  • Không lặp
  • Ít số lớp và phương thức nhất

Chạy mọi kiểm thử là tiêu chí đơn giản. Không lặp cũng rõ ràng, dù để đạt được nó thì nhiều nhà phát triển cần được hướng dẫn. Tiêu chí phức tạp là mọi mục địch phải rõ ràng. Ý nghĩa chính xác là gì? Ý nghĩa cơ bản ở đây là mã phải rõ ràng. XP đánh giá cao tính dễ đọc của mã. Trong XP “mã thông minh” là thuật ngữ chỉ sự lạm dụng. Những mã rõ ràng của người này lại là thông minh đối với người khác.

Tài liệu XP 2000 của Josh Kerievsky đưa ra một ví dụ hay. Ông xem xét mã phổ biến nhất có thể của cộng đồng XP – JUnit. JUnit sử dụng mẫu thiết kế decorator để thêm tính năng cho trường hợp kiểm thử như đồng bộ hóa xử lý song song và mã khởi tạo một lô. Việc phân tách mã nguồn này trong decorator cho phép mã rõ ràng hơn.

Nhưng bạn thử hỏi mình xem mã kết quả có thực sự đơn giản. Với tôi thì đơn giản, bởi tôi quen với mẫu thiết kế decorator. Nhưng với những người không biết thì tương đối phức tạp. Tương tự JUnit dùng phương thức có thể cắm được, điều tôi nhận thấy là hầu hết mọi người ban đầu tìm thấy gì đó nhưng rõ ràng. Từ đó chúng tôi kết luận là thiết kế của JUnit đơn giản hơn cho nhà thiết kế có kinh nghiệm nhưng phức tạp hơn cho người ít kinh nghiệm?

Tôi nghĩ việc tập trung vào xóa lặp trong cả “một lần và chỉ một lần” của XP và “không lặp lại chính mình” (DRY -Don’t Repeat Yourself) của Pragmatic Programmer là một trong những lời khuyên hiển nhiên, tuyệt vời và mạnh mẽ nhất. Chỉ cần làm theo, bạn có thể đi được đường dài. Nhưng đó chưa phải là tất cả, và sự đơn giản còn một điều phức tạp nữa để tìm.

Gần đây tôi có tham gia vào một vài thứ chắc là có thiết kế tổng quan tốt. Nó được tái cấu trúc và loại bỏ một vài tính mềm dẻo. Nhưng như một lập trình viên nói “để tái cấu trúc thiết kế tổng quan dễ hơn là tái cấu trúc không có thiết kế.” Tốt nhất là đơn giản hơn một chút bạn cần có, nhưng cũng không phải là thảm họa nếu phức tạp hơn một chút.

Lời khuyên tốt nhất tôi từng được nghe là của Uncle Bob (Robert Martin). Lời khuyên là không cần phải quá cố gắng với thiết kế đơn giản nhất. Sau cùng bạn có thể, nên và sẽ tái cấu trúc lại. Cuối cùng thì sự sẵn lòng để tái cấu trúc quan trọng hơn là biết đâu là thứ đơn giản nhất.

 

Tái cấu trúc có vi phạm YAGNI?

Chủ đề này mới xuất hiện trên diễn đàn email (mailing list), và đáng để mang ra xem xét như vai trò thiết kế trong XP.

Đầu tiên câu hỏi bắt đầu với quan điểm cho rằng tái cấu trúc tốn thời gian mà không thêm chức năng nào. Từ quan điểm của YAGNI bạn có cho rằng bạn thiết kế cho hiện thời không cho tương lai, đó có phải là sự vi phạm?
Quan điểm của YAGNI là bạn không thêm sự phức tạp nếu không cần thiết cho yêu cầu hiện thời. Đây là một phần của kỹ thuật thiết kế đơn giản. Tái cấu trúc để giữ cho thiết đơn giản theo khả năng của bạn, bạn nên tái cấu trúc khi bạn có thể làm cho mã đơn giản hơn.

Thiết kế đơn giản vừa giúp bạn khai phá các kỹ thuật của XP, vừa là một kỹ thuật. Chỉ khi bạn có kiểm thử, tích hợp liên tục, và tái cấu trúc thì bạn mới có triển khai thiết kế đơn giản một cách hiệu quả. Nhưng giữ cho thiết kế đơn giản là bước căn bản để làm phẳng đường cong thay đổi. Bất kỳ sự phức tạp không cần thiết nào đều làm cho hệ thống khó thay đổi theo mọi hướng ngoại trừ trường hợp bạn dự đoán được khi thêm tính linh động phức tạp vào. Tuy nhiên mọi người thường không có được thứ đơn giản nhất ban đầu, nên bạn cần tái cấu trúc để tiến gần tới đích.

 

Mẫu thiết kế và XP

Ví dụ về JUnit đã cho tôi thấy một mô hình lai với mẫu thiết kế. Mỗi quan hệ giữa mẫu thiết kế và XP thật sự thú vị và là một câu hỏi thường gặp. Joshua Kerievsky bằng lập luận hùng hồn cho rằng XP đã không đánh giá đúng vai trò của mẫu thiết kế, nên ở đây tôi không muốn nhắc lại nữa. Nhưng đáng để lo ngại khi nhiều người cho rằng mẫu thiết kế mâu thuẫn với XP.

Cốt lõi của luận điểm này là mẫu thiết kế được sử dụng rất thường xuyên. Thế giới đầy ắp những lập trình viên huyền thoại, họ thấy choáng ngợp ngay lần đầu đọc GOF, và sẽ dùng tới mười sáu mẫu thiết kế khác nhau trong 32 dòng mã. Nhớ một tối được tiếp sức bởi một chai Single Malt, tôi đọc bài viết “Không Mẫu Thiết kế: 23 thủ thuật giá rẻ” (Not Design Patterns: 23 cheap tricks) với Kent. Chúng tôi nghĩ về những thứ như dùng lệnh if thay cho mẫu strategy. Vấn đề nằm ở chỗ bạn thường lạm dụng mẫu thiết kế, nhưng việc dùng nó lại không phải là ý tồi. Câu hỏi đặt ra là cách sử dụng chúng.

Một lý thuyết về điều này là việc dùng thiết kế đơn giản sẽ đưa bạn tới mẫu thiết kế.

Rất nhiều tái cấu trúc làm việc này một cách tường minh, nhưng dù bạn không dùng tài cấu trúc thì việc tuân thủ các quy tắc của thiết kế đơn giản cũng đưa bạn tới mẫu thiết kế dù bạn không biết về chúng. Điều này có thể đúng, nhưng có phải là cách tốt nhất để làm? Chắc chẵn sẽ tốt hơn nếu bạn biết cơ bản về nơi bạn đang đi và có một cuốn sách giúp bạn giải quyết vấn đề thay vì phải phát minh ra chúng. Chắc chắn tôi vẫn dùng GOF khi cảm thấy cần sẽ có một mẫu thiết kế. Với tôi để có một mẫu thiết kế hiệu quả thì chúng ta phải biết được liệu giá phải trả cho mẫu thiết kế có đáng không – đó là kỹ năng của riêng tôi. Tương tự như Joshua gợi ý, chúng ta cần phải biết dùng mẫu thiết kế tương đối thành thục. Như thế trong XP cách chúng ta dùng mẫu thiết kế là khác nhau, nhưng không thể loại bỏ chúng được.

Nhưng khi đọc những danh sách thư này (mailing list), tôi thấy một cách nhìn khác của nhiều người về XP, họ nghĩ XP phản đối mẫu thiết kế bất chấp một thực tế trớ trêu là hầu hết những người khởi xướng XP đều là những thủ lĩnh của mẫu thiết kế. Lý do có thể là mẫu thiết kế quá khó hoặc đã nằm sâu trong suy nghĩ nên họ không nhận ra? Tôi không biết câu trả lời của người khác, nhưng với tôi mẫu thiết kế vẫn rất quan trọng. XP có thể là một quy trình phát triển, nhưng mẫu thiết kế là kiến thức xương sống của thiết kế, kiến thức này có giá trị dù quy trình của bạn là gì đi chăng nữa. Những quy trình khác nhau có cách sử dụng mẫu thiết kế khác nhau. XP nhấn mạnh vào cả việc không dùng mẫu thiết kế tới khi thực sự cần và áp dụng một mẫu thiết kế theo một cài đặt đơn giản. Nhưng mẫu thiết kế vẫn là một kiến thức then chốt.

Lời khuyên của tôi khi sử dụng mẫu thiết kế cho XPer là:

  • Đầu tư thời gian học mẫu thiết kế
  • Tập trung vào thời điểm áp dụng mẫu thiết kế (không quá sớm)
  • Tập trung vào cách cài đặt mẫu thiết kế đơn giản nhất trước tiên, sau đó tăng sự phức tạp lên
  • Nếu bạn dùng một mẫu thiết kế, và sau đó nhận ra nó đang không hỗ trợ gì thì đừng e ngại loại bỏ

Tôi nghĩ XP cần phải tập trung vào việc học mẫu thiết kế nhiều hơn. Tôi không chắc mình có thể đưa điều này vào trong các kỹ thuật của XP, nhưng tôi chắc chắn rằng Kent có thể tìm ra một cách.

 

Nuôi lớn một kiến trúc

Đối với chúng ta kiến trúc phần mềm là gì? Với tôi kiến trúc bao gồm ý tưởng về những phần nòng cốt của hệ thống, những bộ phận khó thay đổi. Đó là nền tảng để từ đó xây phần còn lại.

Vai trò của kiến trúc là gì khi chúng ta sử dụng thiết kế tiến hóa? Những người chống XP lại nói XP bỏ qua kiến trúc, rằng đường đi của XP là viết mã nhanh và tin tưởng vào việc tái cấu trúc sẽ giải quyết mọi vấn đề của thiết kế. Thật thú vị, họ đã đúng, đó có thể là điểm yếu. Chắc chắn là những người thần tượng XP nhất – Kent Beck, Ron Jeffries, và Bob Martin đang tốn rất nhiều năng lượng để tránh up front design. Đừng dùng cơ sở dữ liệu tới khi bạn thực sự biết bạn cần. Hãy làm việc với tệp tin trước và tái cấu trúc cơ sở dữ liệu ở một phân đoạn sau.

Tôi được biết đến như một XPer hèn nhát bởi nhưng điều tôi không đồng ý với XP. Tôi nghĩ kiến trúc khởi điểm có một vai trò nhất định. Đó là những thứ ở tầng ứng dụng, cách tương tác với cơ sở dữ liệu (nếu bạn cần), cách để làm việc với web server.

Thực tế, chúng ta đã học qua nhiều năm các linh vực đó của mẫu thiết kế. Khi kiến thức về mẫu thiết kế của bạn tăng lên, bạn nên biết cách áp dụng chúng một cách hợp lý. Tuy nhiên sự khác biệt chính là những quyết định về kiến trúc ban đầu không phù hợp, hoặc đội biết rằng họ đã mắc lỗi trong những quyết định sớm của mình và nên dũng cảm để sửa. Một số đã kể câu chuyện ở một dự án rằng: gần tới thời điểm cài đặt, họ quyết định không cần EJB nữa và xóa chúng khỏi hệ thống. Đó là một tái cấu trúc đáng kể, được triển khai muộn, nhưng việc tiến hành những kỹ thuật này không chỉ có thể mà còn đáng làm.

Cách làm việc này lại theo cách ngược lại. Nếu bạn quyết định không dùng EJB, thì sau này có khó khăn hơn để thêm vào? Vậy bạn có nên bắt đầu và không dùng EJB tới khi thử một giải pháp không dùng EJB và thấy cần thiết? Câu hỏi này bao gồm nhiều yếu tố. Chắc chắn làm việc mà không có những thành phần phức tạp sẽ đơn giản hơn và làm mọi thứ nhanh hơn. Tuy nhiên đôi khi dễ để bỏ một thứ như thế hơn là cho nó vào.

Nên lời khuyên của tôi là hãy bắt đầu đánh giá xem kiến trúc sẽ như thế nào. Nếu bạn thấy một lượng lớn dữ liệu với nhiều người dùng thì hãy dùng cơ sở dữ liệu ngay từ ngày đầu. Nếu bạn thấy nghiệp vụ phức tạp, thì hãy cho vào trong một miền nghiệp vụ (model). Tuy nhiên với sự tôn kính tới các vị thần của YAGNI, khi bạn gặp vấn đề với đơn giản hóa, hãy sẵn sàng đơn giản hóa kiến trúc ngay khi thấy phần của kiến trúc đó không tăng thêm gì cả.

 

UML và XP

Một trong những câu hỏi lớn nhất trong tất cả những câu hỏi tôi có vì sự gia nhập XP, xoay quanh sự kết hợp giữa XP với UML của tôi. Chúng không tương thích với nhau?

Có một số điểm không tương thích. Chắc chắn XP không nhấn mạnh rằng sơ đồ là tốt trong phạm vi lớn. Mặc dù chính thức XP viết “hãy dùng chúng nếu thấy hữu ích”, nhưng trong những tài liệu con quan trọng có phát biểu “thực sự XPer không cần sơ đồ”. Điều này được củng cố bởi thực tế có nhiều người như Kent không bao giờ thấy thoải mái với sơđồ, thực ra tôi chưa bao giờ thấy Kent tự nguyện vẽ một sơ đồ phần mềm dùng những ký hiệu cố định.

Tôi nghĩ vấn đề này có hai nguyên nhân. Một là có một số người thấy sơ đồ phần mềm có ích trong khi người khác thì không. Sự nguy hiểm nằm ở chỗ những người thấy sơ đồ có ích thì không dùng và ngược lại. Thay vào đó chúng ta hãy chấp nhận rằng một số sẽ dùng sơ đồ và một số không.

Vấn đề khác là sơ đồ phần mềm có xu hướng đi kèm với những quy trình nặng nề. Những quy trình này dành nhiều thời gian vẽ sơ đồ, những sơ đồ không hỗ trợ mà thực tế còn làm hại. Do đó tôi nghĩ nên khuyên những người này cách dùng sơ đồ tốt và tránh những cạm bẫy của thông điệp “chỉ khi bạn phải” của XPer.

Đây là lời khuyên của tôi để dùng sơ đồ hiệu quả.

Hãy lưu ý mục đích của lưu đồ mà bạn đang vẽ. Giá trị chính là giao tiếp. Để giao tiếp hiệu quả thì hãy chọn những thứ quan trọng và bỏ qua những thứ ít quan trọng. Việc lựa chọn này là chìa khóa để dùng UML hiệu quả. Đừng vẽ tất cả các lớp – chỉ những lớp quan trọng. Chỉ vẻ những thuộc tính và phương thức quan trọng trong các lớp đó. Đừng vẽ sơ đồ tuần tự cho tất cả mọi trường hợp sử dụng (use case) – mà chỉ … bạn sẽ có bức tranh. Một vấn đề phổ biến khi vẽ sơ đồ trường hợp sử dụng là mọi người cố gắng vẽ đầy đủ. Mã là đầy đủ nhất, dễ nhất để đồng bộ với mã. Sơ đồ đầy đủ là kẻ thù của tính có thể hiểu được.

Cách dùng sơ đồ phổ biến là xem xét thiết kế trước khi viết mã. Thường bạn có ấn tượng là việc này không đúng với XP, nhưng đó không phải sự thật. Nhiều người nói rằng khi bạn có một nhiệm vụ, bạn nên để mọi thứ với nhau để tiến hành một phiên thiết kế nhanh trước tiên. Khi bạn tiến hành phiên làm việc này:

  • Giữ cho phiên làm việc ngắn
  • Không liệt kê mọi chi tiết (chỉ chi tiết quan trọng)
  • Chỉ coi bản thiết kế là khung chứ không phải bản thiết kế cuối cùng

Điểm đáng mở rộng cuối cùng. Khi tiến hành thiết kế up-front, bạn sẽ không tránh được sai sót, và bạn chỉ phát hiện ra chúng khi viết mã. Sẽ không là vấn đề nếu bạn thay đổi thiết kế. Vấn đề nằm ở chỗ khi bạn nghĩ thiết kế đã hoàn thành và không nhận ra những sai sót khi viết mà để sửa lại ở thiết kế.

Khi thay đổi thiết kế không nhất thiết phải thay đổi sơ đồ. Hoàn toàn có lý khi cho rằng vẽ sơ đồ để giúp bạn hiểu thiết kế và sau đó bỏ chúng đi. Vẽ sơ đồ là tốt, và là đủ khi làm chúng đáng giá. Chúng không nhất thiết là một tạo tác (artifact) cố định. Tốt nhất sơ đồ UML không phải là tạo tác.

Rất nhiều XPer dùng thẻ CRC. Điều đó không xung đột gì với UML. Tôi luôn dùng kết hợp UML và CRC, dùng kỹ thuật nào hữu ích nhất cho công việc một cách thủ công.

Một cách dùng sơ đồ UML khác là như một tài liệu trong tiến trình. Cách dùng phổ biến là dùng công cụ đảm bảo kỹ thuật phân mềm (CASE tool – Computer Aided Software Engineering tool). Ý tưởng là để tài liệu này giúp mọi người làm việc với hệ thống. Trong thực tế nó thường không hỗ trợ gì cả.

  • Mất quá nhiều thời gian để cập nhật sơ đồ, nên thường chúng không đồng bộ với mã.
  • Sơ đồ thường được giấu trong các công cụ CASE hoặc các tập tài liệu, nên không ai xem chúng.

Xuất phát từ những vấn đề quan sát được, tôi có lời khuyên cho tài liệu trong tiến trình:

  • Chỉ dùng những sơ đồ mà bạn có thể cập nhật với công sức không đáng kể
  • Để sơ đồ nơi mà mọi người có thể dễ dàng nhìn thấy. Tôi thích để chúng trên tường. Khuyến khích mọi người dùng bút để thay chỉnh sửa bản vẽ trên tường với những thay đổi đơn giản
  • Hãy để ý xem liệu mọi người có dùng chúng, nếu không thì hãy bỏ chúng đi.

Cuối cùng là dùng UML như tài liệu trong tình huống chuyển giao, như khi một nhóm bàn giao cho nhóm khác. Trong trường hợp với XP thì làm tài liệu là một yêu cầu như những yêu cầu khác, và giá trị của nó được xác định bởi khách hàng. Một lần nữa UML lại có ích để cung cấp sơ đồ được chọn để giúp cho giao tiếp. Hay nhớ rằng mã chứa tất cả thông tin chi tiết, sơ đồ có vai trò tóm tắt và nhấn mạnh những vấn đề quan trọng.

 

Metaphor

Tôi phải công khai công nhận là vẫn chưa dùng được metaphor. Tôi đã xem metaphor hoạt động và hoạt động tốt với dự án C3, nhưng điều đó không có nghĩa là tôi có ý tưởng về cách dùng nó, và tự giải thích cách nó hoạt động.

Metaphor của XP dựa trên cách tiếp cận của Ward Cunninghams là một hệ thống những tên. Việc hiểu tốt từ vựng của một nghiệp vụ là rất quan trọng để bàn về nghiệp vụ đó. Hệ thống này giúp bạn đặt tên lớp và phương thức.

Tôi xây dựng mô hình ý niệm của nghiệp vụ để xây dựng hệ thống tên đó. Tôi làm việc này với chuyên gia của nghiệp vụ đó dùng UML hoặc các hậu duệ của UML. Tôi thấy rằng bạn phải rất cẩn thận khi làm việc này. Bạn cần giữ cho tập hợp các ký hiệu này nhỏ, và tránh để những vấn đề kỹ thuật xuất hiện ở mô hình. Tôi nhận thấy nếu bạn triển khai hệ thống này thì cần xây dựng từ vựng của nghiệp vụ mà những chuyên gia của nghiệp vụ đó có thể hiểu và dùng để giao tiếp với nhà phát triển. Mô hình này không khớp hoàn toàn với thiết kế lớp, nhưng đủ để cung cấp một lượng từ vựng chung cho toàn bộ nghiệp vụ.

Hiện tại tôi không có bất cứ lý do nào để phản đối hệ thống từ vựng này, như metaphor của C3 đã khớp với một dây chuyền lắp ráp. Nhưng tôi cũng không có lý do nào để nói hệ thống tên nghiệp vụ là ý tưởng tồi. Tôi cũng không có xu hướng từ bỏ một kỹ thuật đã giúp tôi có được một hệ thống tên tốt.

Mọi người thường chỉ trích XP với lý do là bạn cần có ít nhất một thiết kế khung của hệ thống. XPer thường trả lời “đó là metaphor”. Nhưng tôi vẫn chưa thấy rằng metaphor là lời giải thích thuyết phục. Đây là một lỗ hổng thực sự trong XP, và XPer cần giải quyết.

 

Bạn có muốn trở thành một Kiến trúc sư khi lớn lên?

Một thời gian dài ở thập kỷ này, thuật ngữ “kiến trúc sư phần mềm” đã trở nên thông dụng. Với tôi đó là một thuật ngữ khó dùng. Vợ tôi là một kỹ sư cấu trúc. Mối quan hệ giữa kỹ sư và kiến trúc sư là … thú vị. Cách nói yêu thích của tôi là “kiến trúc sư giỏi ở ba chữ B: bulbs (bóng đèn), bushes (cây bụi), birds (chim)”. Nghĩa là kiến trúc sư sẽ làm tất cả những hình vẽ đẹp, nhưng kỹ sư phải chắc chắn rằng chúng có thể đứng được. Và kết quả là tôi tránh thuật ngữ kiến trúc sư phần mềm, nhưng sau tất cả nếu ngay cả vợ tôi cũng thể đối xử với tôi bằng sự tôn trọng chuyên nghiệp, thì tôi có cơ hội nào với người khác.

Trong phần mềm, thuật ngữ kiến trúc mang nhiều ý nghĩa. (Trong phần mềm bất cứ thuật ngữ nào cũng mang nhiều ý nghĩa.). Mặc dù vậy thì một cách tổng quan thuật ngữ này truyền tải ý nghĩa nhất định, như trong “tôi không chỉ thuần là một lập trình viên – tôi là một kiến trúc sư”. Có thể dịch câu này thành “Bây giờ tôi là một kiến trúc sư – tôi quá quan trọng để làm bất cứ việc lập trình nào”. Câu hỏi là nếu tách bạn khỏi những nỗ lực lập trình nhàm chán thì khi muốn thực hành lãnh đạo kỹ thuật thì bạn sẽ làm gì.

Câu hỏi này tạo ra cảm xúc ghê gớm. Tôi đã thấy những người rất giận dữ khi nghĩ rằng họ không còn có vai trò như kiến trúc sư nữa. “Không có chỗ cho những kiến trúc sư kinh nghiệm trong XP” là lời kêu ca mà tôi thường nghe. Bởi tầm quan trọng của thiết kế, tôi không cho rằng XP không coi trọng kinh nghiệm hay kỹ năng thiết kế giỏi. Thực ra tôi học được rất nhiều về thiết kế từ rất nhiều người đề xướng XP – Kent Beck, Bod Martin và dĩ nhiên Ward Cunninghan. Tuy nhiên điều đó nghĩa là vai trò của họ đã thay đổi từ lãnh đạo kỹ thuật.

Để minh họa, tôi sẽ dẫn ra một trong những lãnh đạo kỹ thuật của chúng tôi ở ThoughWork: Dave Rice. Dave đã trải qua một số vòng-đời và nhận vai trò không chính thức là lãnh đạo kỹ thuật trong một dự án năm mươi người. Vai trò của anh là lãnh đạo có nghĩa anh dành rất nhiều thời gian với các lập trình viên. Anh sẽ làm việc với một lập trình viên khi lập trình viên cần giúp đỡ, anh quan sát xem ai cần giúp đỡ. Một tín hiệu quan trọng là nơi anh ngồi. Như là một nhân viên dài hạn của ThoughWork, anh có thể lấy bất cứ văn phòng nào anh muốn. Anh chia sẻ văn phòng với Cara, một nhà quản lý phát hành. Tuy nhiên trong vài tháng cuối anh đã chuyển vào khoang mở nơi lập trình viên làm việc (dùng phong cách “phòng chiến tranh” mở mà XP khuyến khích.) Điều này rất quan trọng với anh bởi như thế anh có thể biết được điều gì đang diễn ra, và sẵn sàng giúp một tay khi các lập trình viên cần.

Những ai đã biết XP sẽ nhận ra tôi rõ ràng đang mô tả vai trò của một huấn luyên viên trong XP. Thực ra một trong những cách dùng từ nói rằng XP đã gọi lãnh đạo kỹ thuật trong hình ảnh của một “huấn luyện viên”. Ý nghĩa rất rõ ràng: trong XP, lãnh đạo kỹ thuật là dạy cho lập trình viên và giúp họ ra quyết định. Đó là người phải có kỹ năng với con người tốt và kỹ thuật tốt. Jack Bolles ở XP 2000 đã bình luận rằng bây giờ mỗi phòng nhỏ cho một người thầy duy nhất. Cộng tác và dạy là chìa khóa để thành công.

Vào hội nghị buổi tối, tôi và Dave nói với một người chống đối XP. Chúng tôi thảo luận về những gì chúng tôi làm, sự tương đồng trong cách tiếp cận là khá rõ ràng. Cả hai chúng tôi đều thích phát triển có tính thích nghi và lặp. Kiểm thử rất quan trọng. Do đó chúng tôi rất ngạc nhiên về sự dữ dội của đối phương. Ông nói “điều cuối cùng tôi muốn lập trình viên của mình làm là tái cấu trúc và đùa nghịch với thiết kế”. Bây giờ tất cả đã rõ. Dave đã giải thích được cho tôi khái niệm khó khăn với câu “nếu anh không tin lập trình viên của mình thì tại sao anh thuê họ?”. Điều quan trọng nhất trong XP là những lập trình viên kinh nghiệm truyền được càng nhiều kỹ năng tới các lập trình viên ít kinh nghiệm hơn. Thay vì một kiến trúc sư quyết định mọi thứ thì bạn có một huấn luyện viên để dạy các lập trình viên ra quyết định. Như Ward Cunningham đã chỉ ra, thì bằng cách này ông có thể mở rộng kỹ năng và đóng góp nhiều vào dự án hơn là chỉ anh hùng có thể làm.

 

Tính có khả năng đảo ngược

Ở XP 2002 Enrico Zaninotto đã có buổi nói chuyện thú vị về mối quan hệ giữa phương pháp linh hoạt và sản xuất tinh gọn. Theo ông, một trong những khía cạnh quan trọng nhất của cả hai cách tiếp cận là giải quyết tính phức tạp thông qua giảm những quyết định không thể đảo ngược được trong quy trình.

Theo ông thì một trong những nguồn chính của sự phức tạp là tính không đảo ngược của quyết định. Nếu bạn có thể dễ dàng thay đổi quyết định, thì việc làm đúng sẽ ít quan trọng hơn – điều này làm cho cuộc sống của bạn đơn giản đi rất nhiều. Hệ quả là trong thiết kế tiến hóa, nhà thiết kế cần nghĩ về cách để tránh tính không đảo ngược trong quyết định. Thay vì cố gắng để có quyết định ngay, hãy tìm một cách để ra quyết định muộn hơn (khi bạn có nhiều thông tin hơn) hoặc ra quyết định để sau đó bạn có thể làm lại mà không quá khó.

Tính cấp thiết của việc hỗ trợ khả năng đảo ngược là một trong những lý do để các phương pháp linh hoạt nhấn mạnh rất nhiều vào những hệ quản lý mã nguồn, và để mọi thứ trong một hệ thống. Khi điều này không đảm bảo khả năng đảo ngược, đặc biệt cho những quyết định tồn tại lâu, thì cũng là cơ sở để tạo sự tin tưởng cho đội, mặc dù hiếm khi sử dụng.

Thiết kế để có tính đảo ngược cũng tạo ra một quy trình có khả năng phát hiện lỗi nhanh. Một trong những giá trị của phát triển lặp là những phân đoạn nhanh cho phép khách hàng thấy được sự lớn lên của hệ thống, và nếu có lỗi trong yêu cầu thì có thể tìm và sửa trước khi giá để sửa trở nên không thể. Và sự phát hiện nhanh này cũng quan trọng trong thiết kế. Điều này có nghĩa là bạn phải làm cho mọi thứ nổi lên để những vùng có vấn đề được kiểm tra, từ đó tìm được vấn đề. Điều đó cũng có nghĩa là đáng làm thử nghiệm để biết sự khó khăn để thay đổi trong tương lai, ngay cả khi bạn không thay đổi ngay. Một việc làm hiệu quả là bỏ đi một nguyên mẫu trên một nhánh của hệ thống. Vài đội báo cáo việc thử những thay đổi của tương lai gần theo mô thức nguyên mẫu để thấy được mức độ khó khăn.

 

Ý chí để thiết kế

Trong khi tôi tập trung vào rất nhiều các phương pháp kỹ thuật trong bài viết này, thì một điều rất dễ bỏ qua là khía cạnh con người.

Để hoạt động được, thiết kế tiến hóa cần một lực để hội tụ. Lực này chỉ có thể từ con người – một vài người trong đội có trách nhiệm đảm bảo thiết kế có chất lượng cao.

Điều này không thể có từ tất cả mọi người (mặc dù nếu có thể thì rất tuyệt), thông thường một hoặc hai người trong đội phải có trách nhiệm đảm bảo thiết kế tổng thể. Đây là một trong những công việc của “kiến trúc sư”.

Trách nhiệm của họ là quan sát bộ mã, phát hiện những vùng đang trở nên lộn xộn, và nhanh chóng hành động để sửa chữa trước khi chúng vượt khỏi tầm kiểm soát. Người giữ thiết kế không nhất thiết phải sửa – nhưng phải đảm bảo có ai đó sửa vấn đề.

Thiếu ý chí để thiết kế có vẻ như là nguyên nhân lớn để thiết kế tiến hóa thất bại. Ngay cả khi mọi người quen thuộc với những thứ tôi nói ở bài viết này thì thiết kế cũng sẽ không đạt khi thiếu quyết tâm đó.

 

Những thứ khó tái cấu trúc

Chúng ta có thể dùng tái cấu trúc để giải quyết mọi quyết định thiết kế, hoặc liệu có vấn đề quá ăn sâu mà việc thêm vào sao trở nên khó khăn? Hiện thời XP chính thống cho rằng có thể thêm mọi thứ một cách dễ dàng khi cần, nên luôn áp dùng YAGNI. Tôi muốn biết liệu có ngoại lệ. Một ví dụ tốt để tranh luận là quốc tế hóa (i18n). Đây có phải là thứ tốn kém để thêm vào sau và bạn có nên bắt đầu đưa nó vào ngay?

Tôi đã hình dung là có một số thứ thuộc danh mục này. Nhưng thực tế là chúng tôi có quá ít dữ liệu. Nếu bạn phải thêm một số thứ, như quốc tế hóa, thì về sau bạn ý thức rất rõ về công sức phải bỏ ra để thêm vào. Bạn sẽ ý thức được ít hơn về công sức mình đang bỏ ra, từ tuần này tới tuần khác, để thêm vào và bảo trì nó trước khi thực sự cần. Bạn cũng ý thức được ít hơn thực tế là có thể bạn đã sai, nên cần tái cấu trúc. Một phần của sự biện minh YAGNI là rất nhiều trong số những nhu cầu tiềm năng sẽ không cần hoặc ít nhất không phải theo ý bạn muốn. Vậy khi không thực hiện chúng, bạn sẽ tiết kiệm được lượng đáng kể sức lực.

Mặc dù cũng sẽ tốn sức lực đáng kể để tái cấu trúc giải pháp đơn giản hiện thời thành giải pháp bạn thực sự cần, nhưng có vẻ như việc tái cấu trúc ít tốn kém hơn là xây dựng một tính năng còn nghi ngờ.

Một vấn đề khác cần phải bận tâm là liệu bạn thực sự biết cách làm. Nếu bạn đã làm quốc tế hóa vài lần, thì bạn sẽ biết mẫu thiết kế cần áp dụng. Như thế bạn thường làm đúng. Dùng cấu trúc tiên liệu trước có lẽ tốt hơn nếu bạn chưa quen với vấn đề. Nên lời khuyên của tôi nếu bạn đã biết cách làm thì bạn nên đánh giá chi phí để làm nó ngay bây giờ và thêm vào sau. Tuy nhiên nếu bạn chưa làm bao giờ, bạn không chỉ không đánh giá tốt được chi phí mà còn thường không làm tốt. Trong trường hợp này bạn nên thêm vào sau. Nếu bạn thêm vào sau và thấy đau đớn vì việc này, như thế thì tốt hơn là bạn thêm vào từ trước. Đội của bạn có nhiều kinh nghiệm hơn, hiểu vấn đề và yêu cầu hơn. Thông thường ở hoàn cảnh này bạn sẽ nhìn thấy cách dễ dàng để hoàn thiện nó với những gì đã trải qua. Và có thể khó hơn rất nhiều so với bạn nghĩ nếu thêm vào trước đó.

Điều này cũng gắn chặt với câu hỏi về thứ tự các yêu cầu. Trong Lập kế hoạch XP, tôi và Kent đã công khai chỉ ra những bất đồng của chúng tôi. Kent ủng hộ giá trị kinh doanh là yếu tố duy nhất để sắp xếp các yêu cầu. Sau bất đồng ban đầu thì Ron Jeffries cũng đồng ý với điều này. Tôi vẫn chưa chắc chắn. Tôi tin rằng đó là sự cân bằng giữa giá trị kinh doanh và rủi ro kỹ thuật. Điều này dẫn tôi tới việc thực hiện một số quốc tế hóa sớm để giảm nhẹ rủi ro này. Tuy nhiên điều này chỉ đúng khi bản phát hành đầu tiên cần quốc tế hóa. Phát hành nhanh nhất có thể là tối quan trọng. Bất cứ sự phức tạp cộng thêm nào đều đáng nếu bản phát hành đầu tiên không cần. Sức mạnh của mã chuyển giao và chạy được là ghê gớm. Nó tập trung sự chú ý của khách hàng, tăng uy tín, và là nguồn lớn để học tập. Hãy làm tất cả mọi thứ để làm cho ngày phát hành gần hơn. Ngay cả khi cần nhiều nguồn lực hơn để thêm một số thứ sau lần phát hành đầu, thì phát hành sớm vẫn tốt hơn.

Rất tự nhiên khi những người ủng hộ kỹ thuật mới không chắc chắn về điều kiện ranh giới. Hầu hết XPer đều nói không thể áp dụng thiết kế tiến hóa cho những vấn đề xác định, mà chỉ để khám phá rằng nó thực sự có thể. Sự chinh phục những tình huống “không thể” mang tới niềm tin rằng có thể vượt qua mọi tình huống như thế. Dĩ nhiên bạn không thể khái quát theo cách này, nhưng trước khi cộng đồng XP chạm phải giới hạn đó và thất bại, thì chúng ta không thể chắc chắn về vị trí của những giới hạn này, và rõ ràng là chúng ta phải thử và vượt qua những ranh giới mà người khác có thể thấy.

(Bài viết mới của Jim Shore thảo luận một số tình huống bao gồm quốc tế hoá. Sau tất cả ranh giới tiềm năng không phải là rào cản)

 

Thiết kế đang xảy ra?

Một trong những khó khăn của thiết kế tiến hóa là rất khó để nói liệu thiết kế có đang xảy ra. Sự nguy hiểm của thiết kế trộn lẫn lập trình là việc lập trình xảy ra mà có thể không có thiết kế – đó là tình huống Thiết kế Tiến hóa phân kỳ và thất bại.

Nếu bạn trong một đội phát triển, thì có thể cảm nhận được liệu đang có thiết kế dựa vào chất lượng của mã. Nếu mã càng trở nên phức tạp và khó để làm việc, thì chưa làm đủ thiết kế. Nhưng thật buồn vì đây là cách nhìn chủ quan. Chúng ta không có thước đo tin cậy để đưa ra một cái nhìn khách quan về chất lượng của thiết kế.

Sự thiếu tầm nhìn là khó khăn với người làm kỹ thuật, và còn đáng báo động hơn cho thành viên phi kỹ thuật của đội. Nếu bạn là quản lý hoặc khách hàng, bằng cách nào bạn có thể nói là phần mềm được thiết kế tốt? Đây là vấn đề của bạn vì nếu thiết kế của phần mềm tồi thì sẽ tốn kém hơn để sửa đổi trong tương lai. Không có câu trả lời dễ dàng cho vấn đề này, nhưng đây là một số gợi ý.

  • Lắng nghe người làm kỹ thuật. Nếu họ phàn về sự khó khăn để thay đổi, thì hãy quan tâm tới phàn nàn này một cách nghiêm túc và cho họ thời gian để sửa.
  • Quan tâm tới lượng mã bị bỏ đi. Một dự án thực hiện tái cấu trúc tốt sẽ dần loại bỏ mã xấu. Nếu không có gì được xóa đi thì đó gần như chắc chắn là một dấu hiệu của việc đang không thực hiện đủ tái cấu trúc – điều này sẽ dẫn tới suy thoái thiết kế. Tuy nhiên như bất kỳ thước đo nào khác, điều này có thể bị lạm dụng, ý kiến của những nhân viên kỹ thuật giỏi hơn hẳn bất kỳ số liệu nào mặc dù nó là chủ quan.

 

Vậy thiết kế đã chết?

Không bởi một ý nghĩa nào, nhưng bản chất của thiết kế đã thay đổi. Thiết kế trong XP cần những kỹ năng sau:

  • Mong muốn giữ mã rõ ràng và đơn giản nhất có thể.
  • Kỹ năng tái cấu trúc để bạn có thể tự tin thực hiện bất cứ cải tiến nào khi thấy cần thiết
  • Kiến thức tốt về mẫu thiết kế: không chỉ là giải pháp mà còn đánh giá cao thời điểm sử dụng và cách tiến hóa thành mẫu thiết kế.
  • Thiết kế có quan tâm tới những thay đổi trong tương lai, biết rằng quyết định hiện thời sẽ bị thay đổi trong tương lai.
  • Biết cách giao tiếp của thiết kế và người cần hiểu thiết kế bằng cách sử dụng mã, sơ đồ và trên tất cả: sự đàm thoại chuyện.

Đó là sự lựa chọn một cách kiêm tốn các kỹ năng, nhưng để trở thành một nhà thiết kế tốt luôn rất khó. Thực tế XP không làm nó đơn giản hơn, ít nhất là với tôi. Nhưng tôi nghĩ XP cho chúng ta một cách suy nghĩ mới về thiết kế hiệu quả bởi nó tạo ra thiết kế tiến hóa, một chiến lược hợp lý. Tôi là một người rất hâm mộ tiến hóa – nếu khác thì ai biết tôi có thể là gì?

 

Lời cảm ơn

Trong một vài năm trở lại đây, tôi đã chọn và “ăn cắp” nhiều ý tưởng tốt từ nhiều người giỏi. Hầu hết đã mất trong trí nhớ không tốt của tôi. Nhưng tôi nhớ rõ ý tưởng của Joshua Kerievsky. Tôi cũng nhớ rất nhiều bình luận của Fred George và Ron Jeffries. Tôi cũng không thể quên được bao nhiêu ý tưởng tốt từ Ward và Kent. Tôi luôn luôn biết ơn những ai đã hỏi và chỉnh lỗi chính tả. Tôi đã chểnh mảng trong việc giữ danh sách những người này để cảm ơn, nhưng họ gồm Craig Jones, Nigel Thorne, Sven Gorts, Hilary Nelson, Terry Camerlengo.

 

Người dịch: Phạm Anh Đới và Nguyễn Ngọc Anh | Nguồn: Tạp chí Lập trình