Wednesday, 13 March 2013

Kinh Nghiệm Trong Quản Lý Và Học Tập Phát Triển Phần Mềm (Bài 3)

copyright from: cmu.duytan.edu.vn

Một người bạn của tôi, là chủ một công ty phần mềm tuần trước có nói với tôi về tình hình anh hiện đang phải đối mặt. Công ty anh ta cần tuyển 50 nhân viên phát triển phần mềm và thế là anh đã quảng cáo những vị trí tuyển dụng đó trên báo chí, websites, và ở các trường đại học. Sau nhiều tuần, công ty của anh nhận được hơn 300 hồ sơ. Anh đã cẩn thận đánh giá tất cả các hồ sơ xin việc và chọn ra 100 người để phỏng vấn. Anh đã yêu cầu họ viết một chương trình “đơn giản” để kiểm tra khả năng của họ, hy vọng sẽ tuyển được 50 trong số 100 ứng viên đó cho công ty của mình. Mặc dù yêu cầu của chương trình đó khá là đơn giản, 75 ứng viên đã không thể làm xong trong khoảng thời cho phép. Anh cũng đã nhận thấy những khác biệt lớn giữa những lập trình viên đã viết xong được chương trình đó. Anh ta nói: “Điều gì sẽ xảy ra khi nhân viên phát triển không thể làm xong việc trong thời gian yêu cầu? Hoặc là (tôi) phải cho họ thêm thời gian hoặc (tôi) phải làm thay cho họ.” Từ góc độ quản lý, điều này là không thể chấp nhận được. Tuy nhiên, vấn đề không phải với những người không làm được việc vì dù gì thì tôi cũng sẽ chẳng thuê họ. Vấn đề là với 25 người làm được việc, dù đúng trong thời gian cho phép nhưng họ lại mắc quá nhiều lỗi.

Anh nói: “Đây là vấn đề năng suất và chất lượng.” Là ông chủ một công ty (phần mềm), anh đã từng gặp nhiều người làm phần mềm là “sản phẩm” của “những chương trình huấn luyện và đào tạo tồi.” Anh bảo tôi: “Họ được dạy cách lập trình nhưng không theo chuẩn lập trình nào cả. Họ học được nhiều ‘mánh và thủ thuật’ để làm bài được trong quá trình học nhưng lại không được dạy làm thế nào để chữa lỗi trong mã của họ trước khi tích hợp mã với người khác. Vì thế, sản phẩm cuối cùng của họ thường có nhiều lỗi và hạn chế, đòi hỏi nhiều thời gian hơn nữa để sửa chữa. Họ không biết cách tính toán công việc của mình vì họ không biết khi nào họ sẽ làm xong việc tại chẳng ai dạy họ cách lượng hóa hay lập kế hoạch.” Là một nhà quản lý, anh ta luôn tự hỏi sẽ phải làm gì với những nhân viên làm phần mềm được huấn luyện quá tồi này vì nếu anh ta không có hành động kịp thời, các thành viên phát triển khác trong nhóm sẽ đặt ra chính câu hỏi đó. Do công việc phát triển phần mềm liên quan đến làm việc nhóm và mọi người phải dựa vào kết quả công việc của nhau (trong phát triển phần mềm), nên các thành viên trong nhóm sẽ không vui nếu người giám đốc dự án không sẵn lòng giải quyết vấn đề một cách hiệu quả và trực tiếp với các nhân viên phát triển tồi đó. Anh giải thích: “Tôi đã gởi họ đi học để cải thiện kỹ năng nhưng nhiều người đã cố che cái dở của mình hơn là tiếp nhận cơ hội phát triển kỹ năng. Thái độ tiêu cực này xuất phát từ quan niệm là họ cũng có bằng cấp (như ai) và không cần phải đi học lại nữa. Họ cũng không thích người khác giúp họ xem xét lại kết quả công việc của họ. Họ phàn nàn về làm việc nhóm, các quyết định của nhóm, và luôn có cớ ngụy biện cho việc làm của họ. Một số bảo với tôi rằng họ quá bận không có thời gian chữa lỗi, nhưng sẽ cố chữa sau, và rồi (chủ yếu) bỏ thời gian thử mã có chạy được không hơn là thật sự chữa chúng. Họ còn tìm kiếm thêm các ‘mánh’ mới từ các ‘chat-room,’ và thay vì hỏi các thành viên khác trong nhóm, họ nhờ ai đó trên mạng giúp đỡ họ vì chẳng ai sẽ biết được họ là ai cả.” Là một ông chủ và là một doanh nhân, anh bạn của tôi chẳng có mấy lựa chọn hơn là sa thải những nhân viên như vậy vì họ đã có những thái độ và thói quen xấu, khó mà thay đổi được gì.

 
 "Mánh và thủ thuật" không bao giờ là giải pháp căn bản trong phát triển phần mềm.

Anh bạn tôi nói: “Sau nhiều năm trong nghề, tôi đã học được cách làm thế nào để nhanh chóng phát hiện ra những người có ‘các thái độ xấu’ như vậy. Hàng tuần, tôi ra yêu cầu đánh giá lại thiết kế và mã lập trình trong từng dự án ở công ty. Rồi tôi cố tìm ra những đối tượng không muốn cho người khác xem việc mình làm, không tiếp thu đề nghị của người khác, không bỏ thời gian đánh giá phần việc của người khác, và thiếu hợp tác hay không sẵn lòng làm việc chung trong nhóm. Khi xem xét những gì các đối tượng này làm, tôi thường chẳng hiểu được thiết kế hay mã của họ vì chúng rất không logic, lộn xộn, và đầy những “mánh và thủ thuật” (chắp vá với nhau) hơn là dễ nhìn hay có chút logic gì. Nếu tôi làm lơ trước những thái độ như vậy, vô hình chung sẽ khuyến khích hơn nữa những thái độ xấu đó và rồi sẽ làm hại đến năng suất của các thành viên khác trong nhóm. Tôi không hiểu vì sao nhà trường lại không dạy gì về làm việc nhóm cho sinh viên vì đó là một thành tố cực kỳ quan trọng trong phát triển phần mềm, và tôi cũng chẳng hiệu tại sao trường học lại đào tạo ra những loại người như vậy?”

Tôi bảo với anh ta rằng: “Lý do chính vì sao nhiều người làm phần mềm mắc phải những thói quen xấu như vậy không phải vì làm phần mềm là khó mà là vì việc thiếu giảng dạy những nguyên tắc cơ bản về Công nghệ Phần mềm (cho họ).” Thậm chí đến ngày nay, có rất ít chương trình đào tạo tập trung vào thiết kế, kiến trúc, phương pháp lập trình, đảm bảo chất lượng, làm việc nhóm, và quản lý dự án. Hầu hết các trường đều vẫn chỉ dạy chủ yếu là lập trình, vì thế sinh viên chỉ có thể lập trình cho những dự án nhỏ và không làm được gì nhiều hơn thế. Nhiều sinh viên khác học đủ các “mánh và thủ thuật” trong quá trình học để có thể làm cho xong bài tập. Điều họ lại không học được trong quá trình đó là tính kỹ luật trong kiến thức, vốn cực kỳ quan trọng cho nghề nghiệp tương lai của họ, dù ngay trước mặt nó có thể chẳng mang lại lợi ích trực tiếp gì cả. Ngày nay, hầu hết các chương trình đào tạo (phần mềm) đều là từ ba đến bốn năm học lập trình (chay), và suốt thời gian đó sinh viên chỉ học cách viết các chương trình nhỏ để thỏa mãn các yêu cầu học tập của nhà trường. Đối với những người mới bắt đầu học máy tính, lập trình dường như là khó nhưng trong ngành phần mềm, lập trình (thực ra) chỉ là một phần nhỏ của cả dự án. Những sinh viên mới chỉ viết được vài ba chương trình nhỏ ở trường lại nghĩ rằng chuyển sang viết những chương trình lớn hay phức tạp hơn cũng tương tự như vậy, chỉ là viết nhiều hơn và tốn nhiều thời gian hơn. Thật sự thì KHÔNG PHẢI như vậy. Xây một túp lều (như tôi đã từng nói) khác xa việc xây dựng một tòa nhà 10 tầng. Việc xây dựng một tòa nhà lớn đòi hỏi đủ thứ kiến thức và kỹ năng khác nhau, mà thường là với yêu cầu chuyên môn cao hơn nhiều. Bạn chẳng thể nào xây dựng xong một tòa nhà lớn mà không cần có kiến trúc sư. Bạn không thể xây được một tòa nhà lớn nếu không có thiết kế. Đơn thuần chỉ bỏ gạch và xi măng lại với nhau không thể tạo ra được một tòa nhà lớn vì nó sẽ bị sập. Sự khác biệt về tính phức tạp giữa những gì sinh viên học (ở trường) và những gì ngành phần mềm thực sự làm cũng tương tự như vậy, và những ai chỉ biết học các “mánh và thủ thuật” thì sẽ không thể nào hiểu được khác biệt này. Vì thế, nhiều người đến trường học các thứ như email, Excel, PowerPoint, và web để “Google” tìm kiếm thông tin hay download nhạc, những người này có thể làm được các bài trình bày hay các bảng tính đơn giản, nhưng như vậy thì chỉ cần học trong vài tuần chứ cần gì cả năm học. Họ cũng có thể học cách lập trình C++ hay Java chỉ cần trong một hai năm chứ cần gì đến cả bốn năm. Thế nên, cái sinh viên thật sự cần học (trong bốn năm đó) là một kiến thức vững chắc về việc làm thế nào để viết được các chương trình tốt, làm thế nào để giải quyết các bài toán kinh doanh, làm thế nào để tạo ra các sản phẩm có chất lượng, và làm thế nào để làm việc được trong nhóm. Những kỹ năng này vượt ra khỏi phạm vi của việc lập trình; và thật sự đó mới là cái mà ngành phần mềm gọi là “phát triển phần mềm” hay “Công nghệ Phần mềm.” Và đó cũng là những gì mà ngành phần mềm ngày nay đang cần đến.

Thời Gian, Chất Lượng Và XP (Lập Trình Cực Độ) (Bài 1)

copyright from: http://cmu.duytan.edu.vn


Theo nghiên cứu của Tiến sĩ Barry Boehm của Đại học Nam Calif. (USC), năng lực của nhân công (bao gồm kỹ năng và kiến thức) là thành tố quan trọng nhất đối với năng suất trong phát triển phần mềm. Một người làm phần mềm được huấn luyện tốt có thể có năng suất 353% cao hơn một người làm phần mềm không có kỹ năng cao. Một nghiên cứu nữa của Tiến sĩ Capers Jones đã phát hiện ra là kinh nghiệm của đội ngũ quản lý và hỗ trợ đóng góp 120% vào năng suất trong khi công cụ chỉ góp chừng 35%. Tiến sĩ Jones còn nghiên cứu tiếp và phát hiện ra những tác động ngược: sự thiếu kinh nghiệm của đội ngũ sẽ làm năng suất giảm 177% trong khi các phương pháp và công cụ không hữu ích sẽ làm giảm 41%. Nói cách khác, sự thành công của dự án trực tiếp tùy thuộc vào kỹ năng và kiến thức của đội ngũ và cách thức họ làm việc với nhau.
 
Dựa vào những kết quả nghiên cứu này, năng lực (bao gồm kỹ năng và kiến thức) phải là điểm nhấn trong mọi chương trình đào tạo phần mềm ở bậc đại học. Theo phương pháp “Học qua Làm”, cách tốt nhất để cải thiện kỹ năng lập trình là “Viết code và học từ những lỗi mắc phải!”, và sinh viên phải học mọi thứ ít nhất là ba lần. Lần đầu tiên, sinh viên học cách áp dụng những khái niệm đã học bằng cách cố gắng mô phỏng sản phẩm phần mềm vì nếu không có việc mô phỏng này, thì sinh viên sẽ không biết được các ứng dụng của họ chạy tốt đến mức độ nào và họ biết được bao nhiêu (kiến thức). Trong lần học đầu tiên, sinh viên sẽ thí nghiệm với (các) khái niệm lý thuyết và tự học từ các hiểu biết của mình liệu họ đã đúng hay sai. Lần thứ hai, (trước tiên,) họ cần hiệu chỉnh lại các hiểu biết trên của họ bằng cách tự hỏi: “Chúng ta đã học được gì? Cái gì được và cái gì chưa được? Tại sao mọi chuyện lại diễn ra như hiện nay?” Chỉ khi trả lời được những câu hỏi này thì họ mới (bắt đầu) làm lại (sản phẩm) lần thứ hai. Họ sẽ sửa được nhiều lỗi và chương trình thường hoạt động tốt hơn sau lần thứ hai. Họ vẫn phải làm lại một lần nữa bằng cách tự hỏi: “Có giải pháp nào tốt hơn không? Chúng ta có thể làm gì tốt hơn?” Sau khi trả lời được những câu hỏi này, sinh viên sẽ có thể cải thiện cách làm việc của họ để có chất lượng tốt hơn. Nói cách khác, trong lần đầu tiên, họ học các khái niệm và lý thuyết; lần thứ nhì họ học áp dụng kiến thức đúng cách; và lần thứ ba họ học cách cải thiện chất lượng làm việc của chính họ. Đây là lý do vì sao những nhân công có tay nghề cao giỏi hơn và có năng suất cao hơn những nhân công không có tay nghề cao vì những nhân công giỏi này không chỉ tập trung làm cho đúng việc mà còn tập trung cho một chất lượng cao hơn.
 
 
 Hãy làm việc theo cặp trong phát triển phần mềm!
 
Ken Beck, người tạo ra phương pháp Lập trình Cực độ (XP) đã áp dụng cách nghĩ trên cho XP và gọi nó là “Lập trình theo Cặp”: theo XP, hai lập trình viên cùng làm việc với nhau bằng cách liên tục tráo các vai trò (trong phát triển phần mềm) với nhau. Khi một người lập trình thì người kia kiểm tra lại code của họ. Thực tế cho thấy hai người thì sẽ tốt hơn là một, thay vì để một người làm mọi việc cả ba lần, có thêm một người nữa sẽ giúp rút ngắn thời gian. Một người thực hiện việc phát triển (gồm thiết kế, code, và kiểm thử) trong khi người kia suy nghĩ và quan sát xem cách tiếp cận đang được sử dụng có đúng hay không. Khi kiểm tra lại (chương trình phần mềm), người giữ vai trò quan sát kiểm tra lỗi và đề xướng những ý tưởng giúp cải thiện chất lượng chương trình. Sau đó họ tráo vai trò cho nhau, người lập trình chuyển sang thành người quan sát và người quan sát chuyển sang cải thiện chương trình bằng cách viết lại một số code và cải thiện nó. Bằng cách cùng làm việc với nhau, họ chia sẻ thông tin, giải pháp và cùng hợp tác để cải thiện chất lượng phần mềm. Kỹ thuật này có tác động to lớn lên sản phẩm cuối cùng, giúp giảm thiểu các thiếu sót và lỗi cũng như chi phí phát triển. Nó còn giúp cải thiện việc học và huấn luyện (trong nhóm) vì kiến thức được chia sẻ (thoải mái) giữa các lập trình viên. Những người mới (vào nghề) sẽ nhanh chóng học được từ cách làm của những người có nhiều kinh nghiệm hơn qua quan sát và làm theo. Ken từng viết trong quyển “Lập trình Cực độ” của ông như sau: “Nếu việc kiểm tra lại code là cần thiết (cho chất lượng sản phẩm), thì hãy tiến hành việc kiểm tra lại code nhiều lần bằng cách phân cho một người khác cùng làm việc với bạn và kiểm lại phần việc bạn làm ra. Nếu kiểm thử là cần thiết, thì viết kế hoạch kiểm thử trước và rồi kiểm thử mỗi khi bạn triển khai một chức năng mới, và nếu việc tích hợp là cần thiết, thì hãy liên tục tích hợp để hệ thống luôn hoạt động tốt.” Hình thức cộng tác làm việc nhóm này còn có thể áp dụng vào những mảng khác: Một người hỏi khách hàng về những yêu cầu chức năng cụ thể trong khi một người khác đánh giá phần trả lời của khách hàng và lập ra kế hoạch. Tương tự, một cặp (cùng phát triển phần mềm) thì sẽ luôn năng động tìm kiếm thông tin, có óc phân tích, và dễ có sáng tạo trong phân tích và tìm hiểu các vấn đề của khách hàng, và rồi đoàn kết lại thành một tổ áp dụng những phân tích đó để tạo ra phần mềm đáp ứng được các nhu cầu cao về chất lượng của khách hàng.
 
Phương pháp XP gồm có 5 giá trị: Liên lạcPhản hồiĐơn giảnTáo bạo và Tôn trọng. Từ 5 giá trị này, Ken chi tiết hóa chúng thành 14 nguyên lý và 24 phương thức hay kỹ năng. Ý tưởng là các phương thức và kỹ năng là những điều cụ thể mà nhóm phát triển làm hàng ngày trong khi giá trị (và nguyên lý) là các kiến thức nền tảng. Khi kết hợp kiến thức và kỹ năng với nhau, bạn có được năng lực của một Kỹ sư Phần mềm. Tiến sĩ Laurie Williams của Đại học Utah ở thành phố Salt Lake đã nêu lên rằng hai lập trình viên làm chung theo cặp làm chậm hơn 15% so với hai lập trình viên làm việc độc lập với nhau vì (cặp lập trình viên) mất nhiều thời gian (cho liên lạc và trao đổi qua lại), nhưng kết quả công việc thì lại có ít hơn đến 50% số lượng lỗi. Vì việc kiểm thử và gỡ lỗi thường tốn nhiều thời gian và tiền bạc hơn, nên sau hết, XP là một phương pháp tốt, cho kết quả đáng ấn tượng trong việc cải thiện chất lượng và thời gian phát triển.
 
Ngày nay, hầu hết các phát triển phần mềm đòi hỏi người ta phải làm việc trong nhóm nhưng câu hỏi đặt ra là: “Khi nào thì các đại học sẽ dạy về làm việc nhóm và ủng hộ việc sinh viên cùng hợp tác và trao đổi với nhau?”

Quy trình SCRUM: Thành công mới trong phát triển phần mềm

copyright: www.pcworld.com.vn


Nếu trước kia nói đến dự án phần mềm bạn nghĩ ngay đến quy trình gồm nhiều giai đoạn khá phức tạp với thời gian hoàn thành thường vài tháng đến vài năm. Bây giờ mọi chuyện đã khác.
1. Scrum

Đó là một quy trình phát triển phần mềm theo mô hình linh hoạt (agile). Công nghệ Agile cung cấp rất nhiều phương pháp luận, quy trình và các thực nghiệm để cho việc phát triển phần mềm trở nên nhanh chóng và dễ dàng. Hiện nay tại Việt Nam, quy trình này đang được thử nghiệm tại các đội phát triển phần mềm của một số công ty lớn. Scrum theo mô hình này.
Scrum chia dự án thành các vòng lặp phát triển gọi là các sprint. Mỗi sprint thường mất 2- 4 tuần (30 ngày) để hoàn thành. Nó rất phù hợp cho những dự án có nhiều sự thay đổi và yêu cầu tốc độ cao.
Một sprint hoàn thành một số chức năng, mục đích nào đó trong toàn bộ hệ thống. Các tác vụ trong sprint được chia ra thành các danh mục, đội làm việc sẽ phát triển và đánh giá lại sao cho đạt được mục đích ban đầu trong khoảng thời gian đề ra.
Thành phần chính quan trọng của scrum là các role (vai trò) và các cuộc trao đổi đánh giá. Có các role chính là: 
+ Product Owner: là người làm những công việc bắt đầu cho dự án, tạo ra các yêu cầu trong quá trình phát triển dự án. Phân tích mục tiêu, giải phóng các kế hoạch.
+ Scrum Master: họ phải đảm bảo các sprint được hoàn thành đúng mục đích, bảo vệ đội làm việc và loại bỏ các trở ngại.
+ Đội làm việc ở scrum: thường từ 5-9 người, tùy theo quy mô dự án nó có thể có rất nhiều đội, nhiều người tham gia. Sẽ không có những lập trình viên (programmer), người thiết kế (designer), kiểm thử viên (tester),… thường thấy ở các dự án phần mềm truyền thống. Các đội làm việc sẽ tiến hành cài đặt các chức năng được mô tả trong bản yêu cầu. Họ tự quản lý, tổ chức và điều chỉnh đội làm việc của mình sao cho hiệu quả lớn nhất. Tất cả các thành viên có ảnh hưởng như nhau đến sự thành công hoặc thất bại của toàn bộ hệ thống hoặc các hệ thống nhỏ hơn trong đó.
Có 2 pha là lập kế hoạch và kết thúc sẽ xác định các tiến trình cần thiết gồm các dữ liệu đầu vào đầu ra thật đầy đủ. Có một số vòng lặp phát triển trong pha kế hoạch. Kế hoạch lập ra ban đầu chỉ là tương đối và sẽ có sự điều chỉnh.
2. So sánh scrum và các quy trình phần mềm truyền thống
Với các phương pháp truyền thống, việc lập kế hoạch dự án (xác định những việc cần làm và thời gian kế thúc) dựa trên kinh nghiệm chứ không phải là môi trường làm trực tiếp. Và so với kế hoạch đó khi bắt tay vào xây dựng thì thường có độ trễ nhất định.
Scrum và quy trình thác nước (waterfall), xoắn ốc (spiral)
Mô hình thác nước chia dự án phần mềm gồm các giai đoạn: đặc tả yêu cầu, thiết kế hệ thống, cài đặt (lập trình), kiểm thử và bảo trì. Quy trình này dễ quản lý nhưng lại kém linh hoạt và không hiệu quả bởi nếu có sự thay đổi ở các giai đoạn sau sẽ ảnh hưởng rất lớn đến các giai đoạn trước.
Quy trình xoắn ốc chia dự án thành các giai đoạn: lập kế hoạch, phân tích rủi ro, giao tiếp khách hàng, đánh giá lại, sản xuất và phân phối. Nó vẫn chưa được sử dụng rộng rãi.
Các quy trình phần mềm truyền thống thường có quá khá nhiều giai đoạn, nhiều thành phần, yếu tố trong suốt thời gian phát triển sản phẩm. Phương pháp scrum tránh điều này. (Xem bảng)
3. Cách thức cài đặt để sử dụng scrum 
Có nhiều cách để triển khai, có thể sử dụng 10 bước sau:
- Bước 1: Thu nhập các đặc điểm của sản phẩm (backlog) trong đơn đặt hàng. Đây là bước quan trọng nhất. Lập nên các đội làm việc, có thể tách thành các đội nếu cần thiết và thảo luận với nhau về nghiệp vụ cần làm. Sau đó bổ nhiệm một người vào vị trí Product owner, người này có khả năng trao đổi, bao quát công việc tốt, biết sắp xếp ưu tiên đúng thứ tự các nhiệm vụ. Sau đó tự tổ chức lại đội làm việc, đề xuất ra vị trí Scrum master và thảo luận chi tiết các yêu cầu, sắp xếp chúng theo thứ tự ưu tiên. 
• Bước 2: Ước lượng đầy các yêu cầu về sản phẩm đầu ra. Có ước lượng ở mức độ cao, chia sản phẩm thành số lượng các danh mục backlog. Tuy nhiên số lượng sẽ không chính xác được, về sau chúng sẽ được bổ sung. Tiếp đến là ước lượng chi tiết từng backlog, ước lượng số lượng các đội làm việc.
• Bước 3: Lên kế hoạch phát triển các vòng lặp sprint. Sử dụng các cuộc trao đổi kế hoạch phát triển sprint với tất cả các thành viên. Xác định khoảng thời gian sẽ phát triển một sprint (thường là 30 ngày), mục tiêu của sprint là gì, sẽ đạt được gì, phân tích các yêu cầu của sprint một cách rõ ràng.
• Bước 4: Lên kế hoạch phát triển các nhiệm vụ của sprint. Tất cả mọi người sẽ xác định ngân sách của sprint đó, chia các đặc điểm thành các tác vụ nhỏ hơn, ước lượng số thời gian sẽ làm từng task (giờ), hoàn tất các yêu cầu và nhận dạng task quan trọng.
• Bước 5: Tạo ra không gian làm việc cộng tác cho tất cả mọi người. Thường sử dụng bảng trắng để vẽ nên những vấn đề cần thiết cho tất cả mọi người cùng đánh giá.
• Bước 6: Các thành viên bắt tay xây dựng từng sprint. Lập trình, kiểm thử và điều chỉnh thời gian để có hiệu quả tốt nhất. Đôi khi có thể hủy bỏ một sprint và quay lại với việc lập kế hoạch khác.
• Bước 7: Mọi người báo cáo kết quả để tiếp tục làm việc. Các báo cáo tập trung vào các vấn đề: đạt được những gì so với lần trao đổi trước; sẽ hoàn thành những gì trong lần trao đổi tiếp theo; có những trở ngại gì trong quá trình làm việc v.v. 
• Bước 8: Tổng hợp kết quả trên biểu đồ. Đây là bức tranh tổng quát về những việc đã làm được, những việc chưa làm được, thời gian ước lượng còn lại và có thể điều chỉnh lại. 
• Bước 9: Xem xét để hoàn tất. Khi các thành viên nói công việc đã hoàn thành có nghĩa là mọi thay đổi sẽ bị từ chối, đẩy lại cho vòng lặp sau.
• Bước 10: Đánh giá, phản ánh và lặp lại. Có các cuộc họp đánh giá lại sprint của các thành viên. Sẽ trình bày những gì đạt được, phản hồi của khách hàng, xét thời hạn của sprint. Nhìn lại biểu đồ ở bước 8 để xác định lại toàn bộ hệ thống và tiếp nhận những đóng góp, bổ sung để đưa tiếp vào các vòng lặp sprint tiếp theo.
4. Các điểm mạnh
Điểm mạnh nhất đó là việc linh hoạt, dự án không được cố định từ đầu về thời gian hoàn thành hay những yêu cầu mà nó sẽ được xác định khi phát triển thực tế. 
Phân phối sản phẩm mềm dẻo: nội dung sản phẩm chuyển giao được xác định linh hoạt theo môi trường sử dụng thực tế.
Thời gian biểu linh hoạt: có thể muộn hoặc sớm hơn so với kế hoạch ban đầu.
Chất lượng sản phẩm tốt và giảm rủi ro sản xuất, chi phí thấp. Khả năng trao đổi giữa khách hàng và nhà phát triển, giữa những thành viên trong đội được đặt lên mức cao.
Tốc độ phát triển nhanh, tiết kiệm thời gian. Việc chuẩn bị hành động cho những thay đổi trong quá trình phát triển tốt hơn vì hầu như hàng ngày luôn có những buổi họp đánh giá lại ở những vòng lặp phát triển.
Các bugs (lỗi) và các vấn đề được phát hiện sớm hơn rất nhiều so với các phương pháp truyền thống bởi vì khách hàng được tham gia đánh giá rất nhiều và đầu ra của sản phẩm rất nhanh. Và khi đi sai hướng, có thể hủy ngay sprint đó để quay lại với bản kế hoạch.
Đặc điểmWaterfallSpiralScrum
Xác định các giai đoạn phát triểnBắt buộcBắt buộcChỉ có giai đoạn lập kế hoạch và kết thúc
Sản phẩm cuối cùngĐược xác định trong quá trình lập kế hoạchĐược xác định trong quá trình lập kế hoạchXác định trong quá trình xây dựng dự án
Chi phí sản phẩmĐược xác định trong quá trình lập kế hoạchThay đổi cục bộXác định trong quá trình xây dựng dự án
Ngày hoàn thành sản phẩmĐược xác định trong quá trình lập kế hoạchThay đổi cục bộXác định trong quá trình xây dựng dự án
Đáp ứng với môi trường sử dụngTrong kế hoạch ban đầuTrong kế hoạch ban đầuXuyên suốt từ kế hoạch đến xây dựng và kết thúc
Kinh nghiệm trao đổiĐào tạo trước cho đến khi bắt tay làm dự ánĐào tạo trước cho đến khi bắt tay làm dự ánThực hiện trong quá trình làm dự án
Khả năng thành côngThấpTrung bình thấpCao

Tuesday, 5 March 2013

Sử dụng Adapter Pattern Trong Lập Trình Hướng Đối Tượng

copyright from: nthoai.blogspot.com
I/ Giới thiệu.
- Khái niệm Adapter đã xuất hiện từ rất lâu và được sử dụng rất nhiều trong cuộc sống. Thiết bị điện tử của bạn không thể sạc pin bằng điện 220V mà phải thông qua một bộ chuyển, biến điện 220 thành 12V. Bạn có một con chuột với Jack cắm USB nhưng máy đã hết chỗ cắm, người bán tặng bạn thêm 1 bộ chuyển từ USB sang PS2 để giải quyết vấn đề trên…Đó là những ví dụ hay gặp nhất về Adapter, và vì chúng quá thông dụng nên ít ai ngờ đến cái mình đang sử dụng hằng ngày lại là một kiểu adapter nào đó. Từ lâu, khái niệm Adapter đã được 4 đại ca về Design Pattern đưa vào lĩnh vực làm phần mềm và nó tỏ ra có ích không kém. Tôi dám chắc là các bạn ai đều cũng từng sử dụng đến Adapter trong cuộc sống của mình, thế thì tại sao lại không sử dụng nó trong lập trình để giải quyết những vấn đề tương tự:bbpskien: :

Adapter Pattern Samble In Real Life
Adapter Pattern Samble In Real Life

Adapter Pattern Samble In Real Life
Adapter Pattern Samble In Real Life


Inheritance là một trong 3 nguyên tắc cơ bản của lập trình hướng đối tượng. Khi cần xây dựng một lớp dựa trên một hoặc nhiều lớp hay interface có sẵn bạn chỉ cần khai báo lớp mới kế thừa lớp cũ và có thể viết thêm những method, attribute của mình tùy thích. Tuy nhiên sẽ có lúc tính kế thừa của OOP sẽ không sử dụng được. Thật sự là có nhiều trường hợp như vậy mà tôi đã từng gặp phải. Giả sử bạn cần mở rộng một lớp nhưng lớp đó là lớp seal (không cho kế thừa) thì inheritance chắc chắn không sử dụng được rồi. Một ví dụ khác là khi bạn cần kết hợp nhiều thứ có sẵn để làm ra một lớp mới sử dụng lại những thứ đó. Như các bạn biết C# và Java không hỗ trợ đa kế thừa, chúng ta không thể nào kế thừa từ 2 lớp có sẵn được. Như vậy nếu bạn đã có một lớp để tìm ước số chung lớn nhất của hai số tự nhiên, một lớp để cộng hai phân số, và khi dùng adapter để kết hợp hai thứ có sẵn đó bạn sẽ làm được một lớp có khả năng cộng hai phân số với nhau với kết quả phép cộng là phân số đã tối giản.:bbpnen:

- Như vậy, Adapter Pattern là một design pattern, nó còn được gọi là Wrapper Pattern biến đổi một lớp không thể sử dụng trực tiếp được thành một lớp mới có thể sử dụng. Trong một số trường hợp, Adapter Pattern còn được sử dụng để biến đổi dạng dữ liệu. Để tiết kiệm chỗ trong và giảm tính phức tạp trong database, nhiều giá trị string có thể được lưu thành một string duy nhất với kí tự phân cách đặc biệt, mẫu Adapter sẽ chịu trách nhiệm tách các string đó ra thành array để nơi khác có thể sử dụng. Nhưng nói chung Adapter Pattern được sử dụng đúng nhất khi biến cái không thể thành cái có thể.:bbpraroi:

II/ Sử dụng Adapter Pattern như thế nào?

- Theo tôi nói ở trên, Adapter Pattern thường được dùng để biến cái không thể thành cái có thể, biến lớp không thể sử dụng thành một lớp mới có thể sử dụng. Tuy nhiên, Adapter Pattern còn được dùng để biến những lớp có sẵn thành một thứ khác dễ và tiện sử dụng hơn. Vì vậy có hai cách thiết kế và áp dụng Adapter Pattern trong lập trình, ở một số tài liệu Design Pattern, hai cách này được gọi là Object Adapter Pattern  Class Adapter Pattern. Một số trang còn gọi là Inheritance-Way  Composition-Way. Nói chung những cách gọi này đều dựa trên cách thiết kế lớp Adapter. Object Adapter Pattern hay Composition-Way là cách sử dụng một đối tượng thuộc về lớp chúng ta muốn biến đổi bên trong lớp Adapter. Trong khi đó, ClassAdapterPattern hay Inheritance-Way là cách kế thừa từ lớp chúng ta muốn biến đổi hoặc mở rộng thêm.

III/ Ví dụ mẫu về Adapter Pattern
- Tôi sẽ lần lượt đưa 2 ví dụ thiết kế lớp về 2 cách này:

A. Object Adapter Pattern (Composition-Way)
- Để kiếm đủ tiền ăn nhậu, massage:bbpxtay:, ngoài giờ làm ở cty tôi nhận làm thêm một ứng dụng quản lý bán hàng, trong đó có hỗ trợ lập biểu đồ thể hiện doanh số các kiểu. Hiện tại tôi đã đạo được phần code vẽ biểu đồ cột của một tên sinh viên học cùng trường. Tiếc thay search mãi thì chỉ tìm được một thư viện vẽ biểu đồ tròn nhưng không có source code: CloseSourceCode.BarChart. Tuy có thói quen đạo code thiên hạ:bbpcuoi3:, nhưng chương trình của tôi đã thiết kế với tính loose coupling rất cao nên đã sửa lại code của tên sinh viên đó, và truy xuất lớp đó qua Interface: IMyChart. Như vậy với cách làm thông thường tôi không thể sử dụng lớpCloseSourceCode.BarChart được vì CloseSourceCode.BarChart không thuộc interface IMyChart. Nhờ tìm hiểu kĩ về Adapter Pattern, tôi biết rằng có thể áp dụng Object Adapter Pattern trong trường hợp này. Tôi sẽ làm một lớp ThoaiChart (Thoại là tên tôi) implement từ interface IMyChart, và bên trong ThoaiChart tôi sẽ sử dụng lớpCloseSourceCode.BarChart để vẽ. Thiết kế lớp như sau:

Object Adapter Pattern

B. Class Adapter Pattern (Inheritance-Way)
- Tôi đã rất mừng khi phát hiện ra rằng chỉ mất chút ít thời gian để làm cái BarChart. Nhưng khi đưa cho khách hàng, họ yêu cầu tôi phải sửa lại cái BarChart, phải cho người dùng thấy được số liệu khi rê chuột lên hình. Đúng là đồ free có khác, không khi nào dùng ngay được. Tôi đành phải thiết kế lại lớp ThoaiChart theo hướng khác. Bây giờ tôi sẽ inherit lớp CloseSourceCode.BarChart và override lại hàm hover chuột của nó. Thiết kế lớp như sau:

Class Adapter Pattern


IV/ So sánh Adapter Pattern với các Design Patterns khác?
- Trong các Design Pattern thuộc nhóm Structural Design Pattern, có rất nhiều mẫu có thiết kế lớp tương tự nhau. Chúng ta nên nắm rõ ý nghĩa và trường hợp sử dụng của chúng để không nhầm lẫn và … để khi em trai em gái nó hỏi còn biết đường trả lời :bbpbuon:. Trong phần so sánh giữa Adapter Pattern với các Design Patterns khác, tôi có nhắc nhiều đến từ interface của lớp (class). Bạn hãy hiểu đó như là kiểu(type) của lớp. Các lớp khác namespace và khác base class (base type) sẽ có interface khác nhau. Một số tác giả Việt Nam dịch interface của lớp là "giao diện của lớp", riêng cá nhân tôi thì thấy dịch như vậy cũng kì. Một điểm nữa là các bạn cần phân biệt interface trong trường hợp này với interface trong chữ GUI, và càng nên phân biệt nó với khái niệm interface trong một số ngôn ngữ lập trình như C#, Java, ...

• Với khả năng biến cái không thể thành có thể, Adapter Pattern làm cho 1 lớp có thể sử dụng được sau khi lớp đó đã được thiết kế xong trong khi Bridge Pattern làm điều đó trước khi lớp này được tạo ra.
• Bridge Pattern được nghĩ ra với ý tưởng tách rời những abstraction ra khỏi những implementation, và tạo tính độc lập cao giữa chúng. Trong khi đó, Adapter pattern đươc dùng để làm những lớp không liên quan (không cùng namespace, khác interface) có thể làm việc với nhau.
• Adapter Pattern về ý nghĩa sẽ biến đổi interface của một lớp, Proxy Pattern sẽ không đổi interface của một lớp và Decorator Pattern sẽ kế thừa và mở rộng dựa trên interface đó.
• Adapter Pattern khi dùng sẽ thay đổi interface của một đối tượng có sẵn để biến nó thành thứ có thể dùng được. Decorator Pattern sẽ phát triển thêm trên một đối tượng mà không làm thay đổi interface của nó
• Giống với Adapter Pattern, Façade Pattern có thể kết hợp nhiều xử lý vào một lớp mới đơn giản và gọn hơn , nhưng nó sẽ định nghĩa mới 1 interface trong khi Adapter Pattern tái sử dụng một interface (Trong ví dụ về các biểu đồ ở trên thì interface được tái sử dụng là IMyChart, không hề có một interface mới được tạo ra)


- Các bạn có thể tham khảo thêm những ví dụ code mẫu cho Adapter Pattern ở trang wiki. Ví dụ thứ hai ở trang này là biến đổi 1 lớp DList thành Stack dựa trên những xử lý có sẵn của DList mà không cần viết lại những xử lý phức tạp cho lớp Stack.

Một câu chuyện về Bridge Pattern

copyright from: nthoai.blogspot.com


- Mẫu thiết kế Bridge được thiết kế với ý tưởng tách rời những xử lý của một lớp ra lớp khác, từ đó có thể dễ dàng biến đổi hoặc thay thế mà không làm ảnh hưởng đến những nơi có sử dụng lớp ban đầu. Điều này có thể hiểu như sau: bạn thiết kế một lớp với rất nhiều xử lý, bây giờ bạn không muốn để những xử lý đó trong lớp của bạn nữa, bạn sẽ tạo ra một lớp mới và move toàn bộ những xử lý đó sang lớp mới. Khi đó trong lớp cũ sẽ giữ một đối tượng thuộc về lớp mới, và đối tượng này sẽ chịu trách nhiệm xử lý thay cho lớp ban đầu. Tại sao chúng ta làm như vậy và cách thực hiện như thế nào? Hi vọng với bài viết này chúng ta tìm được lời giải thích cho 2 câu hỏi trên.

- Mẫu Bridge về khía cạnh nào đó khá giống với mẫu Adapter ở chỗ: người ta sẽ nhờ vào một lớp khác để thực hiện một số xử lý nào đó. Tuy nhiên, ý nghĩa và mục đích sử dụng của hai mẫu thiết kế này hoàn toàn khác nhau. Mẫu Adapter Pattern hay còn gọi là Wrapper pattern được dùng để biến đổi một lớp/interface sang một dạng khác có thể sử dụng được. Adapter Pattern giúp nhiều lớp có thể làm việc với nhau dễ dàng mà bình thường không thể. Một trường hợp tôi gặp phải và có thể áp dụng Adapter Pattern là khi tôi không thể kế thừa lớp A nhưng muốn làm một lớp B có những xử lý tương tự như lớp A. Khi đó tôi làm lớp B như sau, các xử lý của B sẽ gọi những xử lý của A khi cần:bbpraroi:
Adapter Pattern Example

Hình 1Ví dụ về mẫu Adapter

- Đó chỉ là một trong nhiều cách sử dụng có thể có của mẫu Adapter, tôi sẽ nói thêm về Adapter trong một bài viết khác, ở đây chỉ nêu ra ý nghĩa khác nhau của hai mẫu thiết kế này. Trước khi đi vào câu chuyện của mẫu Bridge, chúng ta hãy xem sơ đồ lớp của mẫu Bridge:

Bridge Pattern

Hình 2Sơ đồ lớp của mẫu Bridge

Câu chuyện về mẫu thiết kế Bridge (Bridge Pattern)
- Có một người đã làm nghề đầu bếp đã 20 năm. Ông ta đã đi rất nhiều nơi trên thế giới, làm việc cho rất nhiều nhà hàng khác nhau và đã học được cách nấu rất nhiều món ngon. Không những thế ông ta còn sáng tạo ra những món đặc biệt cho riêng mình nữa. Nhờ tài nghệ của ông, các nhà hàng nơi ông làm luôn luôn đông khách. Sau 20 năm nhìn lại, ông thấy đã đến lúc mình phải mở nhà hàng cho riêng mình. Đã để dành được một số vốn kha khá, ông quyết định chọn một trong những thành phố năng động của Việt Nam là TPHCM để bắt đầu sự nghiệp riêng. Thế là nhà hàng của ông ta ra đời và kinh doanh khá phát đạt nhờ vào danh tiếng và tài nghệ của mình. Ông ta dành hết tâm huyết để tự tay nấu mọi món ngon nhất cho các thực khách vì không tin tưởng vào các phụ bếp được thuê. Càng ngày danh tiếng của nhà hàng càng được nhiều người biết đến, không chỉ những người sành ăn trong nước mà cả những du khách nước ngoài cũng tìm đến nhà hàng này để thưởng thức khi có cơ hội ghé đến TPHCM. Ông ta rất vui mừng trước doanh thu ngày càng cao nhưng bên cạnh đó cũng rất lo cho sức khỏe của mình, vì ông phải đứng chế biến món ăn từ 6h sang đến 11h đêm hằng ngày:bbpbuon:

- Các con của ông rất thương bố mình và khuyên ông nên truyền nghề lại cho các học trò, các người ấy sẽ giúp ông làm việc cho nhà hàng. Suy nghĩ khá lâu, ông thấy rằng các con ông nói rất có lý. Ông ta chọn 1 đứa học trò ngoan và giỏi nhất truyền toàn bộ những gì mình biết. Sau khi đã lĩnh hội được toàn bộ khóa học, đứa học trò đã phụ ông nấu nướng cho nhà hàng, nhờ vậy ông được rảnh rổi về sớm đi tập thể dục thẩm mỹ và làm những việc quản lý, mở rộng kinh doanh.

- Thời gian trôi qua, ông muốn mở thêm một nhà hàng mới ở HN. Cũng trong giai đoạn này, ông nhận được email của một số khách ruột bảo rằng chất lượng món ăn bắt đầu kém đi, không đậm đà như trước đây. Sau khi tìm hiểu, ông phát hiện nguyên nhân là do thằng học trò đểu cáng đang âm mưu mở nhà hàng riêng nên nó lơ là việc nấu nướng :bbpnodo:, ngoài ra do ông dạy nó nhiều quá nên nó chỉ có thể nấu ngon được một số món ăn, phần lớn các món khác nấu không đạt yêu cầu. Rút kinh nghiệm, ông quyết định đăng báo dân trí tìm một số cô gái thích nấu nướng truyền cho mỗi cô 1 kĩ thuật nấu món ngon các miền. Sau này nếu có ý định mở nhà hàng ở miền Trung cũng sẽ có đầu bếp chuyên nấu món cay hợp khẩu vị của dân địa phương.


Bridge Pattern Example


Hình 3Bản kế hoạch mở 2 nhà hàng mới của ông

// Bridge pattern -- Structural example
using System;
namespace nthoai.blogspot.com.BridgePattern
{
// "Abstraction" class NhaHang {
protected DauBep _dauBep; // Property public DauBep DauBep {
set { _dauBep = value; }
} public virtual void CheBienMonAn() {
_dauBep.CheBienMonAn();
}
} // "Implementor" abstract class DauBep {
public abstract void CheBienMonAn();
} // "Nhà hàng món Huế" class NhaHangMonHue : NhaHang {
public override void CheBienMonAn() {
_dauBep.CheBienMonAn();
}
} // "Nhà hàng món miền Nam" class NhaHangMienNam : NhaHang {
public override void CheBienMonAn() {
_dauBep.CheBienMonAn();
}
} // "ConcreteImplementorA" class DauBepMonAnHue : DauBep {
public override void CheBienMonAn() {
Console.WriteLine("Đây là những món ăn Huế do đầu bếp Huế thực hiện");
}
} // "ConcreteImplementorB" class DauBepMonAnMienNam : DauBep {
public override void CheBienMonAn() {
Console.WriteLine("Đây là những món ăn miền Nam do đầu bếp miền Nam thực hiện");
}
} // Ông đầu bếp mở nhà hàng như sau class ÔngĐầuBếpGià {
static void Main() {
NhaHang _nhaHangMonHue = new NhaHangMonHue(); // Set implementation and call _nhaHangMonHue.DauBep = new DauBepMonAnHue(); _nhaHangMonHue.CheBienMonAn(); NhaHang _nhaHangMonMienNam = new NhaHangMienNam(); // Change implemention and call _nhaHangMonMienNam.DauBep = new DauBepMonAnMienNam(); _nhaHangMonMienNam.CheBienMonAn(); // Wait for user Console.Read();
}
}
}


Hình 4Kế hoạch mở nhà hàng :D

- Câu chuyện của ông đầu bếp già là một ví dụ về cách sử dụng của Bridge khi đưa những xử lý sang một lớp khác. Trong các tài liệu về mẫu Bridge, các tác giả thường sử dụng các thuật ngữ như: Abstraction, Implementor, RefinedAbstraction và ConcreteImplementor. Cá nhân tôi thấy những từ vô cùng chuyên môn như vậy hơi khó hiểu, tôi thích những ví dụ thực tế hơn, tuy nhiên những từ ấy hoàn toàn chính xác. Sử dụng mẫu Bridge trong lập trình không chỉ đơn giản là đưa những xử lý của một lớp sang lớp khác rồi gọi nó từ lớp mới, mọi việc không chỉ đơn giản như vậy. Ý tưởng trên chỉ là một vế của Bridge Pattern, ở đây chúng ta chưa nói đến vế: “từ đó có thể dễ dàng biến đổi hoặc thay thế mà không phải ảnh hưởng đến những nơi có sử dụng lớp ban đầu” (so you can vary or replace the implementation without changing the client code). Xin thưa với các bạn đây chỉ là cách diễn giải của tôi, không phải khái niệm hay định nghĩa tiếng Việt của Bridge Pattern cho nên nếu các bạn muốn xem nguồn tiếng Anh hãy chịu khó google. Quay lại chỗ “biến đổi, thay thế mà không ảnh hưởng”, tôi đã có viết về chuyện này ở loạt bài về Dependency Injection của Spring.NET. Trong trường hợp của mẫu Bridge, chúng ta có thể giảm sự phụ thuộc giữa các lớp với nhau bằng cách sử dụng Interface hoặc abstract class. Trong các tài liệu về Bridge Pattern, các Abstraction và Implementer là những lớp abstract hoặcinterface. Trong khi đó, các RefinedAbstraction và ConcreteImplementor là những thể hiện cụ thể hay những lớp con của các abstract class/ interface nói trên. Như vậy trong câu chuyện ông đầu bếp của chúng ta thì Abstraction là NhàHàng, RefinedAbstraction chính là Nhà Hàng Món Huế, Nhà Hàng Món Nướng Nam Bộ, Nhà Hàng Châu Âu còn ConcreteImplementor là các đầu bếp: Đầu Bếp Món Âu, Đầu Bếp Món Huế, …

- Như vậy chữ Bridge (chiếc cầu) ở đây là quan hệ “use/have” giữa Abstraction và Implementation, giữa Nhà Hàng và Đầu Bếp. Một RefinedAbstraction sẽ không khai báo cụ thể một ConcreteImplementor nào đang được sử dụng mà chỉ biết nó đang có 1 Implementor nào đó; khi mở một Nhà Hàng mới ta sẽ mướn Đầu Bếp (biết nấu ăn), còn cụ thể đầu bếp nấu được món miền nào sẽ quyết định lúc chọn xong địa điểm:bbpnghi:

- Trong một số trường hợp, mẫu thiết kế Bridge được dùng như một cầu nối giữa 2 nhóm đối tượng khác nhau, giữa nhóm các dữ liệu và nhóm các cách thể hiện ra màn hình, đó là ví dụ thường được dùng trong các bài viết về mẫu Bridge. Như chúng ta biết có rất nhiều chuẩn hình ảnh như JPG, PNG, BMP, GIF, … và các hệ điều hành khác nhau như Windows, MacOS, UNIX đều hiểu và có thể hiển thị các định dạng ảnh này.

- Cấu trúc hình ảnh và cách hiển thị chúng là hai thành phần quan trọng của một định dạng ảnh. Cấu trúc hình chính là cách mà hình đó được lưu trữ, và cách thể hiện chúng sẽ tương đối khác nhau trên các chương trình xem hình trên các hệ điều hành khác nhau. Trong trường hợp này các file hình với các định dạng khác nhau sẽ thường xuyên thay đổi, và các hệ điều hành cần vẽ hình cũng nhiều tương tự. Nếu được yêu cầu thiết kế lớp cho bài toán trên sao cho tính tái sử dụng cao nhất, bạn sẽ làm thế nào. Như đã nói, có rất nhiều chuẩn hình, mỗi hình sẽ có những thông tin riêng của nó và mỗi hình nên được thiết kế để có khả năng tự vẽ nó (Information Expert) . Nhưng vì cách vẽ sẽ khác nhau trên các hệ điều hành khác nhau nên nếu chúng ta thiết kế lớp hình tự thực hiện hàm vẽ rồi khi cần thì sửa hàm vẽ để nó hoạt động được trên hệ điều hành khác là không nên. Bridge Pattern sẽ giúp ta đưa những hàm vẽ đó sang những lớp khác để vẽ trên các hệ điều hành tương ứng. Nhờ vậy, khi một chuẩn hình mới được tạo ra hay có một thuật toán vẽ khác được nghĩ ra, sẽ rất dễ dàng để ta code thêm một lớp vẽ mới cho chương trình.

- Một ví dụ khác cũng tương tự là khi bạn cần xây dựng một ứng dụng thể hiện ra màn hình thông tin khác nhau với những loại user khác nhau. Cùng một dữ liệu nhưng nếu là Admin bạn sẽ cho phép hiển thị chi tiết hơn, có thêm những button cho phép edit hoặc delete chẳng hạn. Trong khi đó user thường hoặc guest chỉ có thể xem mà không thể làm gì khác. Còn rất nhiều trường hợp khác mà chúng ta có thể dùng Bridge cũng như có nhiều mẫu thiết kế tương tự Bridge như Strategy, Adaptor. Nếu chúng ta nắm được ý nghĩa, sự khác nhau và khi nào nên áp dụng những thiết kế này của 4 lão tiền bối thì công việc lập trình sẽ hứng thú, đầy tính sáng tạo và không nhàm chán chút nào. Hi vọng đến đây chúng ta đã tìm được câu trả lời cho 2 câu hỏi trên. Tôi sẽ bàn thêm một chút về những lợi ích và trở ngại khi sử dụng Bridge:

Benefits in using Bridge Pattern

1/ Đặt vấn đề: chúng ta có một lớp A, và các lớp A1, A2, A3 kế thừa từ lớp A. Các lớp A1, A2, A3 sẽ được thừa hưởng các attribute và behavior của lớp A. Như vậy vô tình các xử lý của lớp A1, A2, A3 sẽ y như A trừ khi chúng phải override lại. Trong chương trình, khi cần sử dụng một trong các lớp A1, A2, A3 người ta thường khai báo chung chung là A thay vì khai báo cụ thể là ta sẽ gọi mày đó A1, A2, A3. Cách sử dụng lớp A ta gọi là abstraction hay là trừu tượng hóa và những xử lý của lớp A mà các A1, A2, A3 thừa hưởng gọi là implementation. Sử dụng thiết kế Bridge sẽ giúp chúng ta giảm sự phục thuộc giữa abstraction và implementation. Tính kế thừa trong hướng đối tượng thường gắn chặt abstraction và implementation lúc build chương trình. Bridge Pattern có thể được dùng để cắt đứt sự phụ thuộc này và cho phép chúng ta chọn implementation phù hợp lúc runtime.

2/ Giảm số lượng những lớp con không cần thiết. Một số trường hợp sử dụng tính inheritance sẽ tăng số lượng subclass vô tội vạ. Ví dụ trường hợp chương trình xem hình trên các hệ điều hành khác nhau, ta có 6 loại hình và 3 hệ điều hành. Sử dụng inheritance trong trường hợp này sẽ làm ta thiết kế 18 lớp trong khi áp dụng Bridge sẽ giảm số lượng lớp xuống 9:bbpcuoi1:

3/ Lợi ích thứ 2 dẫn đến một hệ quả: Code sẽ gọn gàn hơn và dẫn đến kích thước ứng dụng sẽ nhỏ hơn.

4/ Các Abstraction và Implementation của nó sẽ dễ dàng thay đổi lúc runtime cũng như khi cần thay đổi thêm bớt trong tương lai. Như vậy chương trình của chúng ta cũng sẽ dễ bảo trì hơn.

5/ Tương tự như lợi ích 4, nếu sử dụng Bridge, hệ thống sẽ dễ mở rộng về sau. Đây hầu như là một yêu cầu bắt buộc đối với các chương trình lớn. Nhiều công ty sẽ cùng làm trong từng giai đoạn phát triển. Một số công ty phần mềm ở VN thường làm outsource: maintain hoặc mở rộng một framework hay một chương trình đã được làm sẵn ở nước ngoài. Công ty khách hàng sẽ yêu cầu chúng ta thêm module cho ứng dụng có sẵn nhưng không được sửa đổi framework/ứng dụng có sẵn của họ vì các framework/ứng dụng đó có thể được công ty nâng cấp lên version mới. Đó là bài toán các bạn sẽ gặp phải khi làm ở những project trung bình và lớn, và ta sẽ vô cùng bực mình và cảm thấy khó khăn khi framework/chương trình đó được đám lập trình viên ở đâu đâu code vô cùng chuối giờ lại bắt mình viết thêm vào:bbptuc:

6/ Những nơi cần sử dụng các abstraction sẽ hoàn toàn độc lập với các implementation.Ví dụ các lớp khác của chương trình xem ảnh sẽ độc lập với thuật toán vẽ ảnh trong các implementation. Như vậy ta có thể update chương trình xem ảnh khi có một thuật toán vẽ ảnh mới mà không cần phải sửa đổi nhiều thậm chí build lại toàn chương trình nếu có dùng các kĩ thuật Dependency Injection.

1 Drawbacks in using Bridge Pattern

- Khi sử dụng Bridge Pattern, chúng ta đã tăng số lần gọi gián tiếp lên hai. Trong ví dụ trên, với cách làm cũ, lớp Image sẽ thực hiện hàm vẽ của chính nó. Nếu áp dụng Bridge, hàm vẽ sẽ được gọi thông qua một lớp implementation tương tứng như vậy có thêm một lần khởi tạo đối tượng và gọi đối tượng, có thêm một lần hủy đối tượng và lượng bộ nhớ bị chiếm để chạy chương trình sẽ tăng lên một chút. Theo tôi những bất lợi này vô cùng không đáng kể so với những lợi ích mang lại khi chúng ta áp dụng Design Pattern nói chung và Bridge Pattern nói riêng.

-----------------------------------------------------------------

- Cuối cùng, ông đầu bếp già của chúng ta sẽ không có thời gian đi massage hay đi chơi gôn nếu cứ tiếp tục tự nấu ăn. Nhà hàng của ông sẽ rất khó khăn khi đầu bếp chính nghỉ việc nếu không có nhiều đầu bếp giỏi chuyên môn. Thử tưởng tượng trong thực tế chúng ta mua một chiếc xe gắn máy mà khi hư thì phải bỏ đi và mua xe mới thay vì có phải tìm phụ tùng thay thế. Tính độc lập, chuyên môn hóa giữa các bộ phận trong một hệ thống luôn được đề cao trên mọi lĩnh vực trong cuộc sống. Riêng trong thiết kế phần mềm, design pattern là những bài học kinh nghiệm mà khi áp dụng tốt sẽ biến người lập trình thành một nghệ sĩ. Một lần nữa, tôi hi vọng bài viết này không chỉ giúp các bạn biết Bridge Pattern là gì mà còn hiểu được tại sao và khi nào cần nó. Tóm lại, cách sử dụng inheritance một cách máy móc có thể vô tình dán chặt những abstraction và implementation với nhau trong khi một số ứng dụng cần điều ngược lại. Bridge Pattern có thể được sử dụng khi một abstraction có nhiều implementation và cả 2 nhóm có thể có nhiều thay đổi mà không phụ thuộc hoặc ảnh hưởng gì nhóm còn lại:bbpcuoi5: