BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƢỜNG ĐẠI HỌC DÂN LẬP HẢI PHÒNG ISO 9001:2008 ĐỖ VĂN TUYÊN LUẬN VĂN THẠC SĨ NGÀNH HỆ THỐNG THÔNG TIN Hải Phòng – 2016BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƢỜNG ĐẠI HỌC DÂN LẬP HẢI PHÒNG ĐỖ VĂN TUYÊN CHIẾN LƢỢC THIẾT KẾ LĨNH VỰC VÀ ỨNG DỤNG PHẦN MỀM QUẢN LÝ NGƢỜI DÙNG TẬP TRUNG LUẬN VĂN THẠC SĨ NGÀNH CÔNG NGHỆ THÔNG TIN CHUYÊN NGÀNH: HỆ THỐNG THÔNG TIN MÃ SỐ: 60 48 01 04 NGƢỜI HƢỚNG DẪN KHOA HỌC: TS. LÊ VĂN PHÙNGLỜI CẢM ƠN Trƣớc tiên tôi xin đƣợc bày tỏ sự trân trọng và lòng biết ơn đối với TS. Lê Văn Phùng. Trong thời gian học tập và làm luận văn tốt nghiệp, thầy đã dành nhiều thời gian quý báu, tận tình chỉ bảo và hƣớng dẫn tôi trong việc nghiên cứu, thực hiện luận văn. Tôi xin đƣợc cảm ơn các GS, TS, các thầy cô giáo đã giảng dạy tôi trong quá trình học tập và làm luận văn. Các thầy cô đã giúp tôi hiểu sâu sắc và thấu đáo hơn lĩnh vực mà mình nghiên cứu để có thể vận dụng các kiến thức đó một cách hiệu quả nhất vào trong công tác của mình. Xin cảm ơn các bạn bè, đồng nghiệp và nhất là các thành viên trong gia đình đã tạo mọi điều kiện tốt nhất, giúp đỡ, động viên, ủng hộ và cổ vũ tôi trong suốt quá trình học tập và nghiên cứu để hoàn thành tốt bản luận văn tốt nghiệp này. Tác giả Đỗ Văn TuyênLỜI CAM ĐOAN Tôi xin cam đoan rằng, đây là công trình nghiên cứu của tôi trong đó có sự giúp đỡ rất lớn của thầy hƣớng dẫn và các đồng nghiệp ở cơ quan. Các nội dung nghiên cứu và kết quả trong đề tài này là hoàn toàn trung thực. Trong luận văn, tôi có tham khảo đến một số tài liệu của một số tác giả đã đƣợc liệt kê tại phần Tài liệu tham khảo ở cuối luận văn. Hải Phòng, ngày 10 tháng12 năm 2016 Tác giả Đỗ Văn TuyênMỤC LỤC LỜI CẢM ƠN ...................................................................................................................... i LỜI CAM ĐOAN .............................................................................................................. iv MỤC LỤC ........................................................................................................................... v DANH MỤC TỪ VIẾT TẮT ........................................................................................... vii Danh mục hình .................................................................................................................. vii PHẦN MỞ ĐẦU .................................................................................................................. x Lý do chọn đề tài ................................................................................................... x Mục đích nghiên cứu ...........................................................................................xi Đối tƣợng và phạm vi nghiên cứu ......................................................................xi Phƣơng pháp nghiên cứu ....................................................................................xi Những nội dung chính của luận văn ..................................................................xi Chƣơng 1 .............................................................................................................................. 1 Tổng quan về các tiến trình phát triển phần mềm................................................................ 1 và các chiến lƣợc thiết kế ..................................................................................................... 1 1.1. Tổng quan về các tiến trình phát triển phần mềm và kỹ nghệ phần mềm hƣớng đối tƣợng..................................................................................................... 1 1.1.1. Tiến trình phát triển phần mềm ................................................................ 1 1.1.2. Kỹ nghệ phần mềm hƣớng đối tƣợng ..................................................... 11 1.2. Các cách tiếp cận thiết kế phần mềm......................................................... 16 1.3. Một số chiến lƣợc hiện đại để thiết kế phần mềm .................................... 18 1.3.1.Thiết kế phần mềm hƣớng mô hình ......................................................... 18 1.3.2. Thiết kế phần mềm hƣớng dữ liệu .......................................................... 19 1.3.3. Thiết kế phần mềm hƣớng Trách nhiệm ................................................ 23 1.3.4. Thiết kế phần mềm hƣớng kiểm thử ...................................................... 261.3.5. Thiết kế phần mềm hƣớng lĩnh vực ........................................................ 33 KẾT LUẬN CHƢƠNG ...................................................................................... 33 Chƣơng 2 ............................................................................................................................ 35 Chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực .................................................................. 35 2.1. Cách tiếp cận hƣớng lĩnh vực trong tiến trình phát triển phần mềm .... 35 2.1.1. Khái niệm về thiết kế hƣớng lĩnh vực .................................................... 35 2.1.2.Tìm hiểu về lĩnh vực ................................................................................ 36 2.1.3.Ngôn ngữ chung ...................................................................................... 38 2.2. Các đặc trƣng thiết kế phần mềm hƣớng lĩnh vực ................................... 40 2.2.1 Thực thể ................................................................................................... 43 2.2.2 Đối tƣợng giá trị ...................................................................................... 45 2.2.2 Dịch vụ .................................................................................................... 47 2.2.3 Mô-đun .................................................................................................... 50 2.3. Các mô hình trong chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực ......... 52 2.3.1 Aggregates and Aggregate Roots ............................................................ 53 2.3.2 Factory ..................................................................................................... 56 2.3.3. Repository ............................................................................................... 60 2.3.4 Bounded Contexts ................................................................................... 65 2.4. Quy trình phân tích và thiết kế phần mềm hƣớng lĩnh vực .................... 67 Chƣơng 3: Ứng dụng chiến lược thiết kế hƣớng lĩnh vực trong việc xây dựng phần mềm quản lý tài khoản tập trung theo hƣớng dịch vụ microservice ........................................... 69 3.1 Mô tả bài toán quản lý tài khoản dùng chung tại trƣờng ĐHDL Hải Phòng .................................................................................................................... 69 Đề xuất giải pháp cho các vấn đề đặt ra: ............................................................ 70 3.2 Tìm hiểu kiến trúc Microservices ................................................................ 703.3 Tìm hiểu mô hình Publisher – Subscriber Event ....................................... 75 3.4 Phân tích và thiết kế yêu cầu phần mềm hƣớng lĩnh vực ......................... 76 3.5. Cài đặt và đánh giá phần mềm thử nghiệm .............................................. 87 Đánh giá và kết luận ........................................................................................... 94 TÀI LIỆU THAM KHẢO ................................................................................................. 95 DANH MỤC TỪ VIẾT TẮT DDD Domain Driven Design RAD Rapid Application Development PO People-oriented MDD Model Driven Design MDA Model Driven Achitecture CSDL Cơ sở dữ liệu TDD Test-Driven Development BDD Behavior-Driven Development AMS Account Management System Danh mục hình Hình 1- 1 Quá trình phát triển phần mềm ................................................................... 1 Hình 1- 2Mô hình thác nƣớc ....................................................................................... 2 Hình 1- 3Mô hình chữ V ............................................................................................. 3 Hình 1- 4 Mô hình xoắn ốc ......................................................................................... 4 Hình 1- 5Mô hình tiếp cận lặp .................................................................................... 5 Hình 1- 6 Mô hình tăng trƣởng ................................................................................... 6 Hình 1- 7Mô hình phát triển ứng dụng nhanh............................................................. 7 Hình 1- 8Mô hình Agile .............................................................................................. 9 Hình 1- 9 Mô hình SCRUM ...................................................................................... 10 Hình 2- 1. Mô hình ngôn ngữ chung ......................................................................... 38 Hình 2- 2 Kiến trúc phân lớp .................................................................................... 41Hình 2- 3 Mô hình 3 lớp ............................................................................................ 43 Hình 2- 4 Value Object ............................................................................................. 47 Hình 2- 5 Những mẫu sử dụng trong DDD ............................................................... 52 Hình 2- 6 Aggregate root .......................................................................................... 55 Hình 2- 7 Factory ...................................................................................................... 58 Hình 2- 8 Repository ................................................................................................. 63 Hình 2- 9 Cài đặt repository ...................................................................................... 64 Hình 2- 10 Quy trình thiết phát triển phần mềm theo hƣớng DDD .......................... 68 Hình 3- 1Quy trình phát triển TDDđề cập vấn đề khó khăn trong việc hiểu rõ yêu cầu chức năng trƣớc khi viết kịch bản kiểm thử ....................................................... 27 Hình 3- 2 TDD trong Agile framework phác họa bởi Mohammad Sami ................. 29 Hình 3- 3 Mô hình BDD – TDD trong Agile mô phỏng bởi Paul Littlebury ........... 30 Hình 3- 4 Factory ...................................................................................................... 59 Hình 3- 5 Quá trình phát triển các mô hình ứng dụng phần mềm của nhà trƣờng ... 69 Hình 3- 6 Microservices của một công ty điều hành taxi kiểu Uber, Hailo [13] ...... 71 Hình 3- 7Mô hình Publisher – Subscriber Events ..................................................... 75 Hình 3- 8 Mô hình kiến trúc liên lạc ......................................................................... 75 Hình 3- 9 Usecase của hệ thống ................................................................................ 77 Hình 3- 10Mô hình kiến trúc của hệ thống hƣớng Microservice .............................. 79 Hình 3- 11 Mô hình DDD ......................................................................................... 79 Hình 3- 12 DDD của dịch vụ Profile ........................................................................ 80 Hình 3- 13Profile Usecase ........................................................................................ 81 Hình 3- 14DDD Account .......................................................................................... 82 Hình 3- 15 Account Usecase ..................................................................................... 82 Hình 3- 16 Tạo tài khoản ngƣời dùng ....................................................................... 83 Hình 3- 17Mô hình DDD của dịch vụ Authenticate ................................................. 84 Hình 3- 18Authenticate Usecase ............................................................................... 84 Hình 3- 19Mô hình DDD của dịch vụ ApplicationRole ........................................... 85 Hình 3- 20 Mô hình DDD của ApplicationRole ....................................................... 85Hình 3- 21 Register Account..................................................................................... 87 Hình 3- 22 Change password .................................................................................... 87 Hình 3- 23 Xóa một Profile ....................................................................................... 88 Hình 3- 24 Các Envets .............................................................................................. 89 Hình 3- 25 Cấu trúc thƣ mục code chƣơng trình ...................................................... 90 Hình 3- 26 Danh sách các Model .............................................................................. 91PHẦN MỞ ĐẦU Lý do chọn đề tài Gần đây các tổ chức, doanh nghiệp, nhóm phát triển phần mềm thƣờng chọn Domain Driven Design (DDD) làm phƣơng pháp chính trong việc thiết kế phần mềm. Khác với các phƣơng pháp thiết kế phần mềm truyền thống, DDD tập trung vào việc hiểu vấn đề khách hàng cần giải quyết. Nó đặt yêu cầu của khách hàng vào trung tâm của quá trình thiết kế phần mềm. Theo quan điểm đó, nhóm phát triển tiến hành trao đổi với khách hàng để tìm hiểu về lĩnh vực (domain) hoạt động, các quy trình nghiệp vụ và vấn đề mà họ đang gặp phải. Mô hình DDD đƣợc hình thành xoay quanh các đối tƣợng và nghiệp vụ nhằm giải quyết các vấn đề của khách hàng. Thông qua mô hình DDD, một ngôn ngữ chung (Ubiquitous language) đƣợc thiết lập cho mọi đối tƣợng tham gia vào phát triển phần mềm: nhóm thiết kế, nhóm lập trình, nhóm kiểm thử và cả khách hàng. Phƣơng pháp thiết kế tiếp cận theo lĩnh vực làm đơn giản hóa các bài toán có nghiệp vụ lớn và phức tạp, đồng thời cung cấp cái nhìn sâu vào hành vi nghiệp vụ trong một cách nhƣ nhau để dễ hiểu hơn cho cả nhân viên nghiệp vụ và kỹ thuật khi phát triển phần mềm. Khi thiết kế các hệ thống lớn, số lƣợng ngƣời dùng lớn có nhiều chức năng, nghiệp vụ phức tạp thì module quản lý ngƣời dùng là nền tảng vì cung cấp khả năng quản lý toàn bộ ngƣời dùng mà các modul đƣợc phát triển sau đều phải sử dụng. Đối với một hệ thống phức tạp, có tính thay đổi nhanh, vòng đời ngắn, nhóm phát triển không thể dự đoán trƣớc mọi yêu cầu mong muốn của khách hàng. Liệu việc thiết kế phần mềm theo hƣớng DDD có thể giải quyết đƣợc vấn đề này?. Khả năng thích ứng, linh hoạt của phần mềm theo DDD trƣớc những thay đổi, những yêu cầu mới của khách hàng sẽ nhƣ thế nào và các bƣớc nào sẽ phải triển khai khi xây dựng ngôn ngữ dùng chung cho nhóm phát triển đối với một phần mềm cụ thể? Đó cũng là lý do mà tôi chọn đề tài “Chiến lược thiết kế lĩnh vực và ứng dụng phần mềm quản lý người dùng tập trung.” nhằm tìm hiểu, giải quyết và trả lời những câu hỏi đƣợc nêu ở trên.Mục đích nghiên cứu Nghiên cứu bản chất của chiến lƣợc hƣớng lĩnh vực, khả năng ứng dụng của nó trong việc phát triển phần mềm quản lý ngƣời dùng tập trung tại trƣờng Đại học dân lập Hải Phòng. Đối tƣợng và phạm vi nghiên cứu Đối tƣợng nghiên cứu là chiến lƣợc thiết kế hƣớng lĩnh vực (DDD). Phạm vi nghiên cứu là trong kỹ nghệ phát triển phần mềm và ứng dụng trong môi trƣờng trƣờng đại học. Phƣơng pháp nghiên cứu Sƣu tập tổng hợp lý thuyết về: Tiến trình phát triển phần mềm, chiến lƣợc thiết kế phần mềm theo DDD Thử nghiệm: Xây dựng phần mềm quản lý ngƣời dùng tập trung theo mô hình DDD. Phân tích, so sánh định tính với các chiến lƣợc thiết kế khác Những nội dung chính của luận văn Bố cục của luận văn gồm có 3 chƣơng: Chương 1: Tổng quan về các tiến trình phát triển phần mềm và các chiến lƣợc thiết kế: tiến trình phát triển phần mềm, kỹ nghệ phần mềm hƣớng đối tƣợng, chiến lƣợc thiết kế phần mềm, một số chiến lƣợc thiết kế phần mềm phổ biến. Chương 2: Chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực: cách tiếp cận hƣớng lĩnh vực trong tiến trình phát triển phần mềm, các đặc trƣng thiết kế phần mềm hƣớng lĩnh vực, các mô hình trong chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực, quy trình phân tích và thiết kế phần mềm hƣớng lĩnh vực. Chương 3: Ứng dụng chiến lƣợc thiết kế hƣớng lĩnh vực trong việc xây dựng phần mềm quản lý tài khoản dùng chung: mô tả bài toán quản lý tài khoản dùng chung tại trƣờng ĐHDL Hải Phòng, phân tích và thiết kế yêu cầu phần mềm hƣớng lĩnh vực, một số giao diện tiêu biểu của phần mềm, cài đặt và đánh giá phần mềm thử nghiệm, đồng thời đƣa ra những vấn đề nghiên cứu tiếp theo cho tƣơng lai.1 Chƣơng 1 Tổng quan về các tiến trình phát triển phần mềm và các chiến lƣợc thiết kế 1.1. Tổng quan về các tiến trình phát triển phần mềm và kỹ nghệ phần mềm hƣớng đối tƣợng 1.1.1. Tiến trình phát triển phần mềm Một tiến trình phát triển phần mềm là một tập của các hoạt động cần thiết (đặc tả, xây dựng, đánh giá, tiến hóa) để chuyển các yêu cầu của ngƣời dùng thành một hệ thống phần mềm đáp ứng đƣợc các yêu cầu đặt ra. Hình 1- 1 Quá trình phát triển phần mềm Vòng đời phát triển của phần mềm đƣợc chia thành 4 pha [4]: - Đặc tả phần mềm: Định nghĩa đƣợc các chức năng, điều kiện hoạt động của phần mềm. - Phát triển phần mềm: Là quá trình xây dựng các đặc tả. Đặc tả phần mềm Xây dựng phần mềm Đánh giá phần mềm2 - Đánh giá phần mềm: Phầm mềm phải đƣợc đánh giá để chắc chắn rằng ít nhất có thể thực hiện những gì mà tài liệu đặc tả yêu cầu. - Tiến hóa phần mềm: Đây là quá trình hoàn thiện các chức năng cũng nhƣ giao diện để ngày càng hoàn thiện phần mềm cũng nhƣ các yêu cầu đƣa ra từ phía khách hàng. Các mô hình phát triển trong dự án phần mềm [12]: a) Waterfall model- Mô hình thác nƣớc: Hình 1- 2Mô hình thác nước Mô tả: - Mô hình thác nƣớc là mô hình áp dụng theo tính tuần tự của các giai đoạn phát triển phần mềm. - Có nghĩa là: giai đoạn sau chỉ đƣợc thực hiện tiếp khi giai đoạn trƣớc đã kết thúc. - Không đƣợc quay lại giai đoạn trƣớc để xử lí các thay đổi trong yêu cầu - Đây đƣợc coi là mô hình phát triển phần mềm đầu tiên. Áp dụng: - Thƣờng đƣợc áp dụng cho các dự án không thƣờng xuyên bị thay đổi về yêu cầu. Đặc điểm: + Ƣu điểm: o Dễ sử dụng, dễ tiếp cận3 o Các giai đoạn và hoạt động đƣợc xác định rõ ràng o Xác nhận ở từng giai đoạn, đảm bảo phát hiện sớm các lỗi + Nhƣợc điểm: o Rất khó để quay lại giai đoạn nào khi nó đã kết thúc o Ít tính linh hoạt và phạm vi điều chỉnh của nó khá là khó khăn, tốn kém. b) V- Shaped Model- Mô hình chữ V Hình 1- 3Mô hình chữ V Mô tả: - Đây là mô hình mở rộng từ mô hình thác nƣớc - Thay vì di chuyển xuống theo tuần tự các bƣớc thì quy trình sẽ đi theo hình chữ V Áp dụng: - Yêu cầu phần mềm phải xác định rõ ràng - Công nghệ phần mềm và các công cụ phải đƣợc tìm hiểu kĩ Đặc điểm: + Ƣu điểm:4 o Đơn giản dễ sử dụng o Phấn phối cụ thể theo mỗi giai đoạn o Thực hiện verification và validation sớm trong mỗi giai đoạn phát triển + Nhƣợc điểm: o Phạm vi điều chỉnh khá là khó khăn và tốn kém. c) Spiral Model – Mô hình xoắn ốc Hình 1- 4 Mô hình xoắn ốc Mô tả: - Là mô hình kết hợp giữa các tính năng của mô hình prototyping và mô hình thác nƣớc. - Mô hình xoắn ốc đƣợc ƣa chuộng cho các dự án lớn, đắt tiền và phức tạp. - Mô hình này sử dụng nhiều những giai đoạn tƣơng tự nhƣ mô hình thác nƣớc, về thứ tự, plan, đánh giá rủi ro, Áp dụng:5 - Thƣờng đƣợc sử dụng cho các ứng dụng lớn và các hệ thống đƣợc xây dựng theo các giai đoạn nhỏ hoặc theo các phân đoạn Đặc điểm: + Ƣu điểm: o Estimates (i.e. budget, schedule, etc.) trở nên thực tế hơn nhƣ là một quy trình làm việc, bởi vì những vấn đề quan trọng đã đƣợc phát hiện sớm hơn. o Có sự tham gia sớm của deverlopers o Quản lý rủi ro và phát triển hệ thống theo phase + Nhƣợc điểm: o Chi phí cao và thời gian dài để có sản phẩm cuối cùng o Phải có kỹ năng tốt để đánh giá rủi ro và giả định. d) Iterative Model- Mô hình tiếp cận lặp Hình 1- 5Mô hình tiếp cận lặp - Một mô hình đƣợc lặp đi lặp lại từ khi start cho đến khi làm đầy đủ spec - Thay vì phát triển phần mềm từ spec đặc tả rồi mới bắt đầu thực thi thì mô hình này có thể review dần dần để đi đến yêu cầu cuối cùng. - Quy trình phát triển đƣợc lặp đi lặp lại cho mỗi một version của sản phẩm trong mỗi chu kỳ.6 - Áp dụng: - Yêu cầu của hề thống đã hoàn chỉnh, đƣợc xác định rõ ràng và dễ hiểu - Yêu cầu chính cần đƣợc xác định và một số chi tiết có thể đƣợc đổi mới theo thời gian Đặc điểm + Ƣu điểm: o Xây dựng và hoàn thiện các bƣớc sản phẩm theo từng bƣớc o Nhận đƣợc phản hồi của ngƣời sử dụng từ những bản phác thảo o Thời gian làm tài liệu sẽ ít hơn so với thời gian thiết kế + Nhƣợc điểm: o Mỗi giai đoạn lặp lại thì cứng nhắc o Tốn kiến trúc hệ thống hoặc thiết kế các vấn đề có thể phát sinh nhƣng không phải tất cả đều xảy ra trong toàn bộ vòng đời. e) Incremental Model – Mô hình tăng trƣởng Ví dụ: Hình 1- 6 Mô hình tăng trưởng Mô tả: - Trong mô hình này thì spec đƣợc chia thành nhiều phần. - Chu kỳ đƣợc chia thành các module nhỏ, dễ quản lý.7 - Mỗi môđun sẽ đi qua các yêu cầu về thiết kế, thực hiện, … nhƣ 1 vòng đời phát triển thông thƣờng. Áp dụng: - Áp dụng cho những dự án có yêu cầu đã đƣợc mô tả, định nghĩa và hiểu một cách rõ ràng - Có nhu cầu về sản phẩm sớm Đặc điểm: + Ƣu điềm: o Phần mềm làm việc một cách nhanh chóng trong suốt vòng đời phát triền o Mô hình này linh hoạt hơn, ít tốn kém hơn để thay đổi phạm vi và yêu cầu o Dễ dàng hơn trong việc kiểm tra và sửa lỗi với sự lặp lại nhỏ hơn + Nhƣợc điểm: o Cần lập plan và thiết kế tốt o Cần một định nghĩa rõ ràng và đầy đủ của toàn bộ hệ thống trƣớc khi nó có thể đƣợc chia nhỏ và đƣợc xây dựng từng bƣớc o Tổng chi phí là cao hơn so với thác nƣớc. f) RAD Model (Rapid Application Development) Hình 1- 7Mô hình phát triển ứng dụng nhanh Mô tả: - Là một dạng của incremental model8 - Trong mô hình RAD các thành phần hoặc chức năng đƣợc phát triển song song nhƣ thể chúng là các dự án nhỏ - Việc phát triển này theo thời gian nhất định, cung cấp và lắp ráp thành một nguyên mẫu làm việc - Điều này có thể nhanh chóng đƣa ra một cái gì đó cho khách hàng để xem và sử dụng và cung cấp thông tin phản hồi liên quan đến việc cung cấp và yêu cầu của họ. Áp dụng: - RAD nên đƣợc sử dụng khi có nhu cầu để tạo ra một hệ thống có Modularized trong khoảng thời gian 2-3 tháng. - Nên đƣợc sử dụng khi đã có sẵn designer cho model và chi phí cao Đặc điểm: + Ƣu điềm: o Giảm thời gian phát triển. o Tăng khả năng tái sử dụng của các thành phần o Đƣa ra đánh giá ban đầu nhanh chóng o Khuyến khích khách hàng đƣa ra phản hồi + Nhƣợc điểm: o Cần có một team giỏi để xác định yêu cầu phần mềm o Chỉ những hệ thống có module mới sứ dụng đƣợc mô hình này o Yêu cầu về dev/ design phải có nhiều kinh nghiệm o Phụ thuộc rất nhiều vào kỹ năng model g) Agile Model9 Hình 1- 8Mô hình Agile Mô tả: - Dựa trên mô hình iterative and incremental - Các yêu cầu và giải pháp phát triển dựa trên sự kết hợp của các function Áp dụng: - Nó có thể đƣợc sử dụng với bất kỳ loại hình dự án nào, nhƣng nó cần sự tham gia và tính tƣơng tác của khách hàng. Ngoài ra, nó có thể đƣợc sử dụng khi khách hàng yêu cầu chức năng sẵn sàng trong khoảng thời gian ngắn ( 3 tuần) Đặc điểm: + Ƣu điểm: o Giảm thời gian cần thiết để tận dụng một số tính năng của hệ thống o Kết quả cuối cùng là phần mềm chất lƣợng cao trong thời gian ít nhất có thể và sự hài lòng của khách hàng Nhƣợc điểm: o Phụ thuộc vào kỹ năng của ngƣời phát triển phần mềmScalability o Tài liệu đƣợc thực hiện ở giai đoạn sau o Cần một team có kinh nghiệm. h) Scrum Model10 Hình 1- 9 Mô hình SCRUM Mô tả: Là một quy trình phát triển phần mềm theo mô hình linh hoạt (agile). Với nguyên tắc chủ đạo là chia nhỏ phần mềm cần sản xuất ra thành các phần nhỏ để phát triển (các phần nhỏ này phải độc lập và Release đƣợc), lấy ý kiến khách hàng và thay đổi cho phù hợp ngay trong quá trình phát triển để đảm bảo sản phẩm release đáp ứng những gì khách hàng mong muốn. 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. Ngoài ra Scrum hoạt động dựa trên ba giá trị cốt lõi, còn gọi là “Ba chân của Scrum” bao gồm Minh bạch, Thanh tra và Thích nghi. Đặc điểm: - Scrum (hay agile nói chung) đƣợc xếp vào nhóm “Feature-driven development”. Sản phầm đƣợc phát triển theo tính năng, chứ không phát triển sản phẩm theo kiến trúc hệ thống. - Scrum khác với các mô hình Agile ở chỗ nó là mô hình hƣớng khách hàng (Customer oriented), vai trò của khách hàng trong việc đánh giá sản phẩm rất quan trọng. Chỉ sau mỗi sprint (2-4 tuần) khách hàng sẽ thấy đƣợc sự thay đổi của sản phẩm của mình qua đó đƣa ra phản hồi sớm để định hƣớng. Thích ứng nhanh với sự thay đổi yêu cầu11 - Scrum giảm thiểu tài nguyên dành cho việc quản lý mà tập trung nhiều hơn cho những công việc liên quan trực tiếp đến việc làm ra sản phẩm. Bằng cách giảm vai trò quản lý (PM) bằng cách đẩy việc quản lý tới từng ngƣời, - Giảm thời gian dành cho việc viết tài liệu bằng cách tăng thời gian trao đổi trực tiếp. Thông thƣờng khi estimate công việc, thì team estimate cả thời gian dành cho communication để hoàn thành task đó nữa. - Tập trung vào sản phẩm, sản phẩm mới là đích cuối cùng chứ không phải qui trình. + Ƣu điểm: o Một ngƣời có thể làm nhiều việc ví dụ nhƣ dev có thể test o Phát hiện lỗi sớm hơn rất nhiều so với các phƣơng pháp truyền thống o Khách hàng nhanh chóng thấy đƣợc sản phẩm qua đó đƣa ra phản hồi sớm. o Có khả năng áp dụng đƣợc cho những dự án mà yêu cầu khách hàng không rõ ràng ngay từ đầu. + Nhƣợc điểm: o Trình độ của nhóm là có một kỹ năng nhất định o Phải có sự hiểu biết về mô hình aglie . o Khó khăn trong việc xác định ngân sách và thời gian. o Luôn nghe ý kiến phản hồi từ khách hàng và thay đổi theo nên thời gian sẽ kéo dài khi có quá nhiều yêu cầu thay đổi từ khách hàng. o Vai trò của PO rất quan trọng, PO là ngƣời định hƣớng sản phẩm. Nếu PO làm không tốt sẽ ảnh hƣởng đến kết quả chung 1.1.2. Kỹ nghệ phần mềm hƣớng đối tƣợng Để xây dựng đƣợc những hệ thống phần mềm đáp ứng đƣợc những yêu cầu chất lƣợng, ta cần phải: - Có một qui trình phát triển phần mềm thống nhất gồm các bƣớc thực hiện rõ ràng, mà sau mỗi bƣớc đều phải có các sản phẩm cụ thể. - Có các phƣơng pháp và kỹ nghệ phù hợp với những pha thực hiện phát triển phần mềm.12 - Có công cụ để làm ra sản phẩm phần mềm theo yêu cầu. Quá trình phát triển một sản phẩm là quá trình định nghĩa ai làm cái gì, làm khi nào và nhƣ thế nào. Quá trình xây dựng một sản phẩm phần mềm hoặc nâng cấp một sản phẩm đã có đƣợc gọi là quá trình phát triển phần mềm. Hệ thống phần mềm đƣợc kiến tạo là sản phẩm của một loạt các hoạt động sáng tạo và có quá trình phát triển. Quá trình phát triển những phần mềm phức tạp phải có nhiều ngƣời tham gia thực hiện. Trƣớc hết đó là khách hàng và những nhà đầu tư, đó là những ngƣời đƣa ra vấn đề cần giải quyết trên máy tính. Những ngƣời phát triển hệ thống gồm các nhà phân tích, thiết kế và lập trình làm nhiệm vụ phân tích các yêu cầu của khách hàng, thiết kế các thành phần của hệ thống và thực thi cài đặt chúng. Sau đó phần mềm đƣợc đƣợc kiểm thử và triển khai ứng dụng để thực thi những vấn đề mà ngƣời dùng yêu cầu. Quá trình phát triển phần mềm đƣợc xác định thông qua các hoạt động cần thực hiện để chuyển đổi các yêu cầu của khách hàng thành hệ thống phần mềm. Có năm bƣớc chính cần thực hiện trong quá trình phát triển phần mềm: - Xác định các yêu cầu - Phân tích hệ thống - Thiết kế hệ thống - Lập trình và kiểm tra hệ thống - Vận hành và bảo trì hệ thống. Có thể thực hiện các bƣớc trên theo nhiều phƣơng pháp khác nhau, theo đó số các bƣớc đề xuất của các phƣơng pháp cũng có thể khác nhau. a) Xác định các yêu cầu hệ thống Pha xác định các yêu cầu của hệ thống gồm 2 giai đoạn: + Xây dựng mô hình nghiệp vụ + Xác định yêu cầu Xây dựng mô hình nghiệp vụ Việc đi tới nắm bắt rành mạch, rõ ràng về hệ thống cần tin học hóa cần xuất phát từ việc tìm hiểu và nghiên cứu về hệ thống thực. Công việc tìm hiểu này đƣợc tiến hành bằng cách tìm hiểu hoạt động nghiệp vụ và xây dựng các mô13 hình miền và mô hình nghiệp vụ để nắm bắt đƣợc toàn bộ các vấn đề liên quan đến nghiệp vụ của hệ thống. Việc tìm hiểu quy trình nghiệp vụ của hệ thống đƣợc tiến hành qua các bƣớc sau: - Tìm hiểu bối cảnh hệ thống - Nắm bắt những yêu cầu bổ sung, các yêu cầu phi chức năng. Xác định yêu cầu Từ những yêu cầu của khách hàng, ta xác định đƣợc mục tiêu của hệ thống cần thực hiện. Thƣờng đó là các yêu cầu chức năng về những gì mà hệ thống phải thực hiện, nhƣng chƣa cần chỉ ra các chức năng đó thực hiện nhƣ thế nào. Việc xác định đúng và đầy đủ yêu cầu bài toán là nhiệm vụ hết sức quan trọng, nó làm cơ sở cho tất cả các bƣớc tiếp theo trong dự án phát triển phần mềm. Muốn vậy, thì phải thực hiện đặc tả chi tiết các yêu cầu của hệ thống. Ngôn ngữ mô hình hóa UML(Unified Modeling Languge)cũng cung cấp biểu đồ ca sử dụng để đặc tả các yêu cầu của hệ thống. Các bƣớc trong giai đoạn này gồm các bƣớc sau: + Tìm các tác nhân và các ca sử dụng + Sắp xếp thứ tự ƣu tiên các ca sử dụng + Mô tả chi tiết một ca sử dụng + Tạo một bản mẫu giao diện ngƣời dùng + Tái cấu trúc mô hình ca sử dụng b) Phân tích hệ thống Phân tích hƣớng đối tƣợng là một giai đoạn của quá trình phát triển phần mềm, trong đó mô hình khái niệm đƣợc mô tả chính xác, xúc tích thông qua các đối tƣợng thực và các khái niệm của bài toán ứng dụng. Giai đoạn này tập trung vào việc tìm kiếm các đối tƣợng, khái niệm trong lĩnh vực bài toán và xác định mối quan hệ của chúng trong hệ thống. Nhiệm vụ của ngƣời phân tích là nghiên cứu kỹ các yêu cầu của hệ thống và phân tích các thành phần của hệ thống cùng các mối quan hệ của chúng. Kết quả của chính của pha phân tích hệ thống hƣớng đối tƣợng là sơ đồ lớp (sơ lƣợc), sơ đồ trạng thái, sơ đồ trình tự, sơ đồ hành động.14 Giai đoạn phân tích hệ thống bao gồm các giai đoạn chính sau: - Phân tích kiến trúc - Phân tích một ca sử dụng - Phân tích một lớp - Phân tích một gói c) Thiết kế hệ thống Dựa vào các đặc tả yêu cầu và các kết quả phân tích thể hiện ở các biểu đồ để thực hiện thiết kế hệ thống. Thiết kế hƣớng đối tƣợng là một giai đoạn trong quá trình phát triển phần mềm, trong đó hệ thống đƣợc tổ chức thành tập các đối tƣợng tƣơng tác với nhau và mô tả đƣợc các hệ thống thực thi nhiệm vụ của bài toán ứng dụng. Nhiệm vụ chính của giai đoạn này là xây dựng các thiết kế chi tiết mô tả các thành phần của hệ thống ở mức cao hơn khâu phân tích để phục vụ cho việc cài đặt. Nghĩa là các lớp đối tƣợng đƣợc định nghĩa chi tiết gồm đầy đủ các thuộc tính, thao tác phục vụ cho việc cài đặt. Đồng thời đƣa ra đƣợc kiến trúc hệ thống để đảm bảo cho hệ thống có thể thay đổi, có tính mở, dễ bảo trì, thân thiện với ngƣời dùng,… Nghĩa là các tổ chức các lớp thành các hệ thống con theo một kiến trúc phù hợp với nhu cầu phát triển công nghệ và xu hƣớng phát triển của lĩnh vực ứng dụng. Những kết quả đƣợc thể hiện trong các biểu đồ: biểu đồ lớp ( chi tiết), biểu đồ công tác thành phần và biểu đồ triển khai. Pha thiết kế hệ thống này gồm các giai đoạn chính sau: - Thiết kế kiến thúc - Thiết kế một ca sử dụng - Thiết kế một hệ thống con d) Lập trình và kiểm tra vận hành Giai đoạn xây dựng phần mềm có thể đƣợc hiện sử dụng kỹ thuật lập trình hƣớng đối tƣợng. Đó là phƣơng phức thực hiện thiết kế đối tƣợng qua việc sử dụng một ngôn ngữ lập trình cõ hỗ trợ các tính năng hƣớng đối tƣợng. Một vài ngôn ngữ hƣớng đối tƣợng thƣờng đƣợc nhắc tới nhƣ C++,15 Java, … Kết quả chung của giai đoạn này là một loạt các code chạy đƣợc, nó chỉ đƣa vào sử dụng sau khi đã trải qua nhiều vòng thử nghiệm khác nhau. Trong giai đoạn này, mỗi thành phần đã đƣợc đƣợc thiết kế sẽ đƣợc lập trình thành những mô-đun chƣơng trình (các chƣơng trình con). Mỗi mô – đun này sẽ đƣợc kiểm chứng hoặc thử nghiệm theo các tài liệu đặc tả của giai đoạn thiết kế. Sau đó, các mô-đun chƣơng trình đã đƣợc kiểm tra sẽ đƣợc tích hợp với nhau thành hệ thống tổng thể và đƣợc kiểm tra xem có đáp ứng các yêu cầu của khách hàng. Kết quả của giai đoạn này là phần mềm cần đƣợc xây dựng. e) Vận hành và bảo trì Giai đoạn này bắt đầu bằng việc cài đặt hệ thống phần mềm trong môi trƣờng sử dụng của khách hàng sau khi sản phẩm đã đƣợc giao cho họ. Hệ thống sẽ hoạt động, cung cấp các thông tin, xử lý các yêu cầu và thực hiện những gì đã đƣợc thiết kế. Tuy nhiên vấn đề bảo trì phần mềm hoàn toàn khác với bảo trì của phần mềm cứng. Nhƣ đã phân tích ở trên, bảo trì phần mềm là đảm bảo cho hệ thống, hoạt động đáp ứng đƣợc các yêu cầu của ngƣời sử dụng, của khách hàng. Mà các yêu cầu này thay đổi hệ thống sao cho nó phù hợp với các yêu cầu hiện tại của họ, thậm chí có những thay đổi chƣa phát hiện đƣợc trong các pha phân tích, thiết kế. Nghĩa là hệ thống phần mềm phải đƣợc nâng cấp, hoàn thiện liên tục và chi phí cho công tác bảo trì là khá tốn kém. Thông thƣờng, có hai loại nâng cấp: - Nâng cấp hiệu quả của hệ thống: Bao gồm những thay đổi mà khách hàng cho là sẽ cải thiện hiệu quả công việc của hệ thống, nhƣ bổ sung thêm các chức năng hay giảm thời gian xử lý, trả lời của hệ thống,… - Đảm bảo sự thích nghi đối với sự thay đổi của môi trƣờng của hệ thống hay sự thay đổi cho phù hợp với những thay đổi của chính sách, qui chế mới ban hành của Chính phủ.16 1.2. Các cách tiếp cận thiết kế phần mềm Do các hệ phần mềm lớn là phức tạp nên ngƣời ta thƣờng dùng các cách tiếp cận khác nhau trong việc thiết kế các phần khác nhau của một hệ thống. Chẳng có một cách tiếp cận nào tốt nhất chung cho các dự án. Hai cách tiếp cận thiết kế hiện đang đƣợc dùng rộng rãi trong việc phát triển phần mềm đó là cách tiếp cận theo hƣớng chức năng và hƣớng đối tƣợng. Mỗi cách tiếp cận đều có ƣu và nhƣợc điểm riêng phụ thuộc vào ứng dụng phát triển và nhóm phát triển phần mềm. Cách tiếp cận hƣớng chức năng hay hƣớng đối tƣợng là bổ sung và hỗ trợ cho nhau chứ không phải là đối kháng nhau. Kỹ sƣ phần mềm sẽ chọn cách tiếp cận thích hợp nhất cho từng giai đoạn thiết kế. Cách tiếp cận Hướng chức năng (Function-oriented (structured) approach): Theo hướng chức năng, hệ thống đƣợc thiết kế theo quan điểm chức năng, bắt đầu ở mức cao nhất, sau đó tinh chế dần dần để thành thiết kế chi tiết hơn. Thiết kế hƣớng chức năng là một cách tiếp cận thiết kế phần mềm trong đó bản thiết kế đƣợc phân giải thành một bộ các đơn thể tác động lẫn nhau, mà mỗi đơn thể có một chức năng đƣợc xác định rõ ràng. Các chức năng có các trạng thái cục bộ nhƣng chúng chia sẻ với nhau trạng thái hệ thống, trạng thái của hệ thống là tập trung và mọi chức năng đều có thể truy cập đƣợc. Cách tiếp cận hướng đối tượng (Object oriented approach): Hệ thống đƣợc nhìn nhận nhƣ một bộ các đối tƣợng (chứ không phải là bộ các chức năng). Hệ thống đƣợc phân tán, mỗi đối tƣợng có những thông tin trạng thái riêng của nó. Đối tƣợng là một bộ các thuộc tính xác định trạng thái của đối tƣợng đó và các phép toán của nó. Nó đƣợc thừa kế từ một vài lớp đối tƣợng lớp cao hơn, sao cho dễ định nghĩa nó chỉ cần nêu đủ các khác nhau giữa nó và các lớp cao hơn nó. Che dấu thông tin là chiến lƣợc thiết kế dấu càng nhiều thông tin trong các thành phần càng hay. Cái đó ngầm hiểu rằng việc kết hợp điều khiển logic và cấu trúc dữ liệu đƣợc thực hiện trong thiết kế càng chậm càng tốt. Liên lạc thông qua các thông tin trạng thái dùng chung (các biến tổng thể) là ít nhất, nhờ vậy khả năng hiểu là đƣợc tăng lên. Thiết kế là tƣơng đối dễ thay đổi vì sự thay đổi một thành phần không thể không dự kiến các hiệu ứng phụ trên các thành phần khác. Cách tiếp cận hƣớng đối tƣợng là dựa17 trên việc che dấu thông tin, nhìn hệ phần mềm nhƣ là một bộ các đối tƣợng tƣơng tác với nhau chứ không phải là một bộ các chức năng nhƣ cách tiếp cận chức năng. Các đối tƣợng này có một trạng thái đƣợc che dấu và các phép toán trên các trạng thái đó. Thiết kế biểu thị các dịch vụ đƣợc yêu cầu và đƣợc cung cấp bởi các đối tƣợng có tƣơng tác với nó. Cách tiếp cận hướng đối tượng có ba đặc trưng: + Vùng dữ liệu dùng chung là bị loại bỏ. Các đối tƣợng liên lạc với nhau bằng cách trao đổi thông báo chứ không phải bằng các biến dùng chung. + Các đối tƣợng là các thực thể độc lập mà chúng sẵn sàng đƣợc thay đổi vì rằng tất cả các trạng thái và các thông tin biểu diễn là chỉ ảnh hƣởng trong phạm vi chính đối tƣợng đó thôi. Các thay đổi về biểu diễn thông tin có thể đƣợc thực hiện không cần sự tham khảo tới các đối tƣợng hệ thống khác. + Các đối tƣợng có thể phân tán và có thể hành động tuần tự hoặc song song. Không cần có quyết định về tính song song ngay từ một giai đoạn sớm của quá trình thiết kế. Các ưu điểm: + Dễ bảo trì vì các đối tƣợng là độc lập. Các đối tƣợng có thể hiểu và cải biên nhƣ là một thực thể độc lập. Thay đổi trong thực hiện một đối tƣợng hoặc thêm các dịch vụ sẽ không làm ảnh hƣởng tới các đối tƣợng hệ thống khác. + Các đối tƣợng là các thành phần dùng lại đƣợc thích hợp (do tính độc lập của chúng). Một thiết kế có thể dùng lại đƣợc các đối tƣợng đã đƣợc thiết kế trong các bản thiết kế trƣớc đó. + Đối với một vài lớp hệ thống, có một phản ánh rõ ràng giữa các thực thể có thực (chẳng hạn nhƣ các thành phần phần cứng) với các đối tƣợng điều khiển nó trong hệ thống. Điều này cải thiện đƣợc tính dễ hiểu của thiết kế. Nhược điểm: Sự tƣờng minh các đối tƣợng hệ thống thích hợp là khó khăn. Cách nhìn tự nhiên nhiều hệ thống là cách nhìn chức năng và việc thích nghi với cách nhìn hƣớng đối tƣợng đôi khi là khó khăn. Cách tiếp cận kế hƣớng đối tƣợng vẫn còn là tƣơng đối chƣa chín muồi và đang thay đổi mau chóng.18 1.3. Một số chiến lƣợc hiện đại để thiết kế phần mềm 1.3.1.Thiết kế phần mềm hƣớng mô hình Phát triển phần mềm truyền thống ngày càng phải đối mặt với nhiều khó khăn nhƣ vấn đề quy trình phát triển, vấn đề khả chuyển, vấn đề tính liên tác hay vấn đề làm tài liệu và bảo trì. Chính vì vậy, một xu hƣớng phát triển phần mềm mới nhằm khắc phục những khó khăn này là kỹ nghệ phát triển phần mềm hƣớng mô hình (Model Driven Design– MDD). Hiện nay, các kết quả đạt đƣợc của MDD chủ yếu dựa trên kiến trúc phần mềm hƣớng mô hình (Model Driven Achitecture- MDA). Tuy nhiên, trong quá trình chuyển đổi mô hình vẫn còn một số vấn đề tồn tại. Để giải quyết những vấn đề này, trong khung làm việc chuyển đổi mô hình, ngƣời ta tập trung vào hai kỹ thuật chính là áp dụng ngôn ngữ chuyển đổi mô hình và áp dụng mẫu thiết kế. Khung làm việc MDA dựa trên nền tảng các chuẩn UML, MOF, XMI và xoay quanh các ý tƣởng chính là mô hình độc lập nền (PIM), mô hình cụ thể nền (PSM) và sự chuyển đổi giữa chúng. Có thể nói, phát triển phần mềm hƣớng mô hình nói chung và kiến trúc phần mềm hƣớng mô hình nói riêng hứa hẹn một bƣớc tiến mới trong phát triển phần mềm giúp quá trình phát triển tập trung nhiều hơn vào mô hình, nâng cao chất lƣợng sản phẩm và năng suất làm việc. Trong quá trình phát triển phần mềm hƣớng mô hình, có hai vấn để nổi lên là việc chuyển đổi mô hình và việc biểu diễn mẫu thiết kế: 1. Vấn đề chuyển đổi mô hình Chuyển đổi mô hình là trái tim của kỹ nghệ phần mềm hƣớng mô hình. Một ví dụ điển hình là các mô hình ở mức trừu tƣợng cao đƣợc chuyển đổi sang các mô hình cụ thể gần với nền phát triển. Tuy nhiên, còn có rất các dạng chuyển đổi khác đƣợc áp dụng trong quá trình phát triển phần mềm theo hƣớng mô hình. 2. Vấn đề biểu diễn mẫu thiết kế Mẫu thiết kế là một định dạng chung của các thiết kế có thể tái sử dụng. Một mẫu thiết kế mô tả họ các giải pháp cho một lớp của các vần đề thiết kế lặp lại. Tuy nhiên, các thông tin không tổng quát của các giải pháp mẫu mô tả làm hạn chế khả năng sử dụng mẫu, nhƣ là việc ứng dụng mẫu vào sự phát triển các công cụ hỗ trợ19 cách sử dụng mẫu thiết kế trong phát triển phần mềm. Trong đó có một hƣớng đi mới trong phát triển phần mềm đó là phát triển phần mềm hƣớng mô hình yêu cầu một sự đặc tả chính xác mẫu thiết kế. Có các phƣơng pháp biểu diễn mẫu theo hai hƣớng chủ yếu là mô tả mẫu theo nguyên mẫu và đặc tả mẫu theo hƣớng tự động hóa bằng ngôn ngữ đặc tả mẫu. Để hiện thực hóa quy trình phát triển phần mềm hƣớng mô hình, các công cụ phát triển phải hỗ trợ tự động hóa sự chuyển đổi mô hình. Các công cụ này không chỉ cần phải cung cấp khả năng áp dụng những sự chuyển đổi đƣợc định nghĩa trƣớc mà còn phải cung cấp một ngôn ngữ cho phép ngƣời dùng định nghĩa sự chuyển đổi mô hình và thực thi chúng theo các yêu cầu riêng. Nói cách khác, những cài đặt cho ngôn ngữ chuyển đổi không chỉ hỗ trợ phát triển phần mềm hƣớng mô hình mà còn phải nâng cao năng suất và chất lƣợng của sự phát triển. 1.3.2. Thiết kế phần mềm hƣớng dữ liệu Ta biết rằng, cấu trúc dữ liệu có tác động quan trọng tới độ phức tạp và tính hiệu quả của thuật toán đƣợc thiết kế để xử lý thông tin. Khi thiết kế phần mềm tiến hoá, một trƣờng phái cho rằng: Việc xác định cấu trúc dữ liệu cố hữu (đối với hệ thống dựa trên máy tính) là điều sống còn, còn cấu trúc của dữ liệu (cái vào và cái ra) có thể đƣợc dùng để đƣa ra cấu trúc (và một số chi tiết) về chƣơng trình. Trong lĩnh vực ứng dụng một cấu trúc thông tin có cấp bậc, phân biệt là tồn tại. Dữ liệu vào, thông tin ghi nhớ bên trong (nhƣ CSDL) và dữ liệu ra có thể có một cấu trúc duy nhất. Thiết kế hƣớng cấu trúc dữ liệu dùng những cấu trúc này làm nền tảng cho việc phát triển phần mềm. Cấu trúc dữ liệu phản ánh thiết kế của các khía cạnh cấu trúc và thủ tục của phần mềm. Trong thực tế, cấu trúc thông tin là điều báo trƣớc cho cấu trúc chƣơng trình. Thiết kế hƣớng cấu trúc dữ liệu biến đổi một biểu diễn của cấu trúc dữ liệu thành biểu diễn của phần mềm. Giống nhƣ các kỹ thuật luồng dữ liệu, ngƣời phát triển thiết kế hƣớng cấu trúc dữ liệu xác định ra một tập các thủ tục ánh xạ có dùng cấu trúc (dữ liệu) thông tin nhƣ hƣớng dẫn. Các đóng góp của thiết kế hƣớng cấu trúc dữ liệu có thể tìm thấy trong những thảo luận về nền tảng của cấu trúc dữ liệu, thuật toán máy tính, cấu trúc điều khiển20 và dữ liệu, và khái niệm về trừu tƣợng dữ liệu. Những xử lí thực chứng hơn về thiết kế phần mềm và mối quan hệ của nó với cấu trúc dữ liệu đã dƣợc Jackson, Warnier và Orr đề nghị. Lập trình có cấu trúc Jackson (JSP), một phƣơng pháp thiết kế phần mềm đƣợc sử dụng rộng rãi, lấy quan điểm là sự song song giữa cấu trúc của dữ liệu vào và dữ liệu ra (báo cáo) sẽ đảm bảo chất lƣợng thiết kế. Những mở rộng gần đây hơn thành phƣơng pháp luận, gọi là phát triển hệ thống Jackson, tập trung vào việc xác định các thực thể thông tin và những hành động đƣợc áp dụng lên chúng và hoàn toàn tƣơng tự trong một số khía cạnh của cách tiếp cận thiết kế hƣớng sự vật đã đƣợc mô tả. Jackson nhấn mạnh về mặt thực hành, phát triển thực chứng để biến đổi dữ liệu thành cấu trúc chƣơng trình. Xây dựng logic chƣơng trình (LPC), đƣợc J.D.Warnier phát triển, đƣa ra một phƣơng pháp chặt chẽ cho thiết kế phần mềm. Rút ra từ mối quan hệ giữa cấu trúc dữ liệu và cấu trúc thủ tục, Warnier đã phát triển một tập các kĩ thuật thực hiện ánh xạ từ cấu trúc dữ liệu vào/ra sang biểu diễn thủ tục chi tiết cho phần mềm. Phát triển hệ thống có cấu trúc dữ liệu (DSSD), cũng còn đƣợc gọi là phƣơng pháp luận Warnier Orr, là một mở rộng của LCP và bổ sung thêm các khả năng phân tích cũng nh thiết kế mạnh. Cách tiếp cận DSSD đƣa ra một phƣơng pháp và nhiều thủ tục để suy ra cấu trúc dữ liệu, cấu trúc chƣơng trình, và thiết kế thủ tục chi tiết cho các thành phần chƣơng trình (mô đun). Bên cạnh đó, DSSD cung cấp một kí pháp làm cho ngƣời thiết kế có khả năng xem xét luồng dữ liệu giữa nơi phát và nơi nhận thông tin và đi qua các tiến trình biến đổi thông tin. Một kĩ thuật gọi là xây dựng logic phần mềm là đại biểu cho việc tổng hợp của các cách tiếp cận thiết kế hƣớng luồng dữ liệu và cấu trúc dữ liệu. Những ngƣời phát triển phong pháp này cho rằng thiết kế logic có thể đƣợc mô tả tƣờng minh nếu phần mềm đƣợc xét nhƣ một hệ thống các tập dữ liệu và các phép biến đổi dữ liệu. Thiết kế hƣớng cấu trúc dữ liệu có thể đƣợc áp dụng thành công trong các ứng dụng có cấu trúc thông tin cấp bậc, đƣợc xác định rõ. Các thí dụ điển hình bao gồm: ứng dụng hệ thống thông tin kinh doanh, cái vào và cái ra có cấu trúc phân biệt (nhƣ tệp vào, báo cáo ra); việc dùng CSDL cấp bậc là thông dụng, các ứng dụng hệ thống. Cấu trúc dữ liệu cho hệ điều hành có chứa nhiều bảng, tệp và danh sách có21 cấu trúc xác định rõ, các ứng dụng CAD/CAE/CIM. Các hệ thống thiết kế, kĩ nghệ và chế tạo có máy tính trợ giúp đòi hỏi các cấu trúc dữ liệu phức tạp để ghi nhớ, chuyển dịch và xử lí thông tin. Cả hai cách thiết kế hƣớng cấu trúc dữ liệu và luồng dữ liệu đều bắt đầu từ cách phân tích để đặt nền tảng cho các bƣớc thiết kế tiếp; cả hai đều hƣớng theo thông tin; cả hai đều định biến đổi thông tin thành biểu diễn phần mềm; cả hai đều dựa trên các khái niệm suy diễn tách biệt về thiết kế tốt. Thiết kế hƣớng cấu trúc dữ liệu không dùng biểu đồ luồng dữ liệu một cách tƣờng minh. Do đó, các phân loại phép biến đổi và luồng giao tác ít có liên can tới phƣơng pháp thiết kế hƣớng cấu trúc dữ liệu. Điều quan trọng hơn là mục tiêu cuối cùng của phƣơng pháp hƣớng cấu trúc dữ liệu là tạo ra một mô tả thủ tục cho phần mềm. Khái niệm về cấu trúc mô đun chƣơng trình không đƣợc xem xét một cách tƣờng minh. Các mô đun đƣợc coi nhƣ các thứ phẩm của thủ tục và triết lí về sự độc lập của mô đun cũng ít đƣợc nhấn mạnh tới. Thiết kế hƣớng cấu trúc dữ liệu dùng biểu đồ phân cấp để biểu diễn cấu trúc thông tin. Thiết kế hƣớng cấu trúc dữ liệu và thiết kế hƣớng sự vật (OOD) đều tập trung vào các sự vật thế giới thực và biểu diễn của chúng trong hệ thống dựa trên phần mềm nên có những điểm tƣơng đồng quan trọng giữa hai phƣơng pháp thiết kế. Thiết kế hƣớng cấu trúc dữ liệu và OOD cả hai đều hƣớng thông tin; cả hai đều dùng một biểu diễn dữ liệu làm cơ sở cho việc phát triển mộ biểu diễn chƣơng trình; cả hai có khái niệm riêng của chúng (đƣợc suy diễn độc lập) về thiết kế tốt. Cấp bậc dữ liệu (đƣợc dùng trong các phƣơng pháp hƣớng cấu trúc dữ liệu) là tƣơng tự với cấp bậc lớp đƣợc dùng trong OOD. Cả hai đều áp dụng các trừu tƣợng dữ liệu và mỗi phƣơng pháp đều coi các thao tác biến đổi dữ liệu là thứ yếu so với chính khoản mục dữ liệu. Sự khác biệt chủ yếu giữa OOD và phƣơng pháp thiết kế hóng cấu trúcdữ liệu ở trong định nghĩa về sự vật. Trong OOD, một sự vật bao bọc cả dữ liệu và tiến trình. Các phƣơng pháp thiết kế hƣớng cấu trúc dữ liệu chọn con đƣờng qui ƣớc nhiều hơn một sự vật (sự vật dữ liệu) chỉ là dữ liệu. Mặc dầu không có biểu diễn trực tiếp cho kế thừa, truyền thông báo, hay bao bọc trong phƣơng pháp thiết22 kế hƣớng cấu trúc dữ liệu, các khái niệm này vẫn cứ tự biểu lộ tinh vi trong trực cảm thiết kế đƣợc mô tả trong chƣơng trình Thiết kế hướng dữ liệu (Data driven design) là kết quả của phƣơng pháp thiết kế kiểu dữ liệu trừu tƣợng ứng với đối tƣợng lập trình. Sự thích nghi là đơn giản bởi vì các lớp khá giống nhau. Từ một quan điểm hoàn toàn thực tế trên, đối tƣợng đóng gói hành vi (thực hiện trách nhiệm của một đối tƣợng) và cấu trúc (các đối tƣợng khác nhận biết trực tiếp đối tƣợng đó). Điều này cũng tƣơng tự nhƣ định nghĩa của một kiểu dữ liệu trừu tƣợng. Trƣớc khi mô tả thiết kế hƣớng dữ liệu, ta hãy xem xét việc thiết kế kiểu dữ liệu trừu tƣợng. Một kiểu dữ liệu trừu tƣợng là đóng gói dữ liệu và các thuật toán hoạt động trên dữ liệu đó. Các kiểu dữ liệu trừu tƣợng đƣợc thiết kế bằng cách hỏi các câu hỏi: - Kiểu này gồm loại dữ liệu gì ? - Các thuật toán nào có thể đƣợc áp dụng cho dữ liệu này? Trọng tâm chính của những câu hỏi này là để xác định những dữ liệu đang đƣợc trình diễn trong hệ thống. Điều này có thể đƣợc thực hiện ban đầu bằng cách xác định các dữ liệu cần thiết của chƣơng trình (có lẽ chỉ một phần của nó). Những thông tin này sau đó có thể đƣợc nhóm lại thành các loại sử dụng sự gắn kết nhƣ một hƣớng dẫn. (Gắn kết, chẳng hạn nhƣ cho một nhóm các dữ liệu, là một độ đo về sự liên quan chặt đến mức nào giữa các bộ phận của nhóm ). Cuối cùng, việc xác định các thuật toán kết hợp với những loại dữ liệu thƣờng dẫn đến việc phát hiện các loại yêu cầu khác. Trong thiết kế hƣớng dữ liệu, các đối tƣợng đƣợc thiết kế bằng cách hỏi các câu hỏi: 1- đối tƣợng này đại diện cho cấu trúc nào? 2-hoạt động nào có thể đƣợc thực hiện bởi đối tƣợng này? Một lần nữa, tiêu điểm chính lại nhằm vào cấu trúc dữ liệu đƣợc đại diện trong hệ thống.23 Lợi ích chính của cách tiếp cận hƣớng dữ liệu là một quá trình quen thuộc cho các lập trình viên có kinh nghiệm với ngôn ngữ thủ tục truyền thống. Nó là tƣơng đối dễ dàng cho các lập trình nhƣ vậy để thích nghi với kinh nghiệm trƣớc đây của mình để thiết kế hệ thống hƣớng đối tƣợng. 1.3.3. Thiết kế phần mềm hƣớng Trách nhiệm Các phƣơng pháp của một nhà thiết kế có ảnh hƣởng sâu sắc đến mức độ mà đóng gói đƣợc thể hiện trong một thiết kế. Khi mô tả các phƣơng pháp tiếp cận hƣớng dữ liệu để thiết kế và lý do tại sao nó không thành công để tối đa hóa đóng gói. Ngƣời ta đã dùng phƣơng pháp thiết kế thay thế, gọi là trách nhiệm điều khiển để thiết kế với mục đích đạt đƣợc mức độ cao hơn về đóng gói. Mục đích của thiết kế hƣớng trách nhiệm là để nâng cao đóng gói. Mô hình client/server cũng có mục đích nhƣ vậy nhƣng ở mức thấp. Mô hình Client-Server Mô hình client /server là một mô tả sự tƣơng tác giữa hai thực thể: các máy khách và máy chủ. Một khách hàng đƣa ra yêu cầu của máy chủ để thực hiện dịch vụ. Một Server cung cấp một bộ các dịch vụ theo yêu cầu. Những cách thức trong đó khách hàng có thể tƣơng tác với máy chủ đƣợc mô tả bằng một hợp đồng: một danh sách các yêu cầu mà có thể đƣợc thực hiện của máy chủ của khách hàng. Cả hai đều phải thực hiện hợp đồng: khách hàng bằng cách làm cho chỉ có những yêu cầu đó quy định cụ thể. và các máy chủ bằng cách đáp ứng những yêu cầu đó. Trong lập trình hƣớng đối tƣợng, cả hai máy khách và máy chủ là một trong hai lớp học hoặc các trƣờng hợp của các lớp. Bất kỳ đối tƣợng có thể hoạt động nhƣ hoặc là một khách hàng hoặc một máy chủ tại bất kỳ thời điểm nào. Ƣu điểm của mô hình client/server là nó tập trung vào những gì các máy chủ không cho các khách hàng, chứ không phải là làm thế nào các máy chủ hiện nó. Việc thực hiện các máy chủ đƣợc đóng gói - cách khóa không cho phép khách hàng xâm nhập. Một lớp có thể có ba loại khác nhau của khách hàng: 1- khách hàng bên ngoài 2- khách hàng lớp con24 3- chính lớp đó. Mỗi một loại khách hàng đƣợc mô tả: 1-Khách hàng bên ngoài Một khách hàng bên ngoài của một lớp là một đối tƣợng gửi tin nhắn đến một thể hiện của lớp hoặc các lớp học chính nó. Ngƣời nhận đƣợc xem nhƣ là một máy chủ, và ngƣời gửi sẽ đƣợc xem nhƣ là một khách hàng. Làm sao thông điệp đƣợc trả lời không phải là quan trọng cho ngƣời gửi. Tập hợp các thông điệp mà một đối tƣợng đáp ứng, bao gồm cả các loại tham số và kiểu trả về, định nghĩa hợp đồng giữa khách hàng và máy chủ. 2-Khách hàng lớp con Một khách hàng lớp con của một lớp học bất kỳ lớp kế thừa từ các lớp. Các lớp cha đƣợc xem nhƣ là một hệ thống thoát nƣớc; các phân lớp đƣợc xem nhƣ là một khách hàng. Các lớp con không nên quan tâm đến việc thực hiện bất kỳ hành vi mà nó thừa kế . Tập hợp các tin nhắn đƣợc thừa kế bởi các phân lớp định nghĩa hợp đồng giữa khách hàng và máy chủ. Trong hầu hết các ngôn ngữ hƣớng đối tƣợng, các lớp con kế thừa không chỉ là hành vi mà còn cấu trúc đƣợc định nghĩa bởi cha của chúng. Thật là không may, vì nó có xu hƣớng khuyến khích các lập trình vi phạm đóng gói để tăng số lƣợng mã tái sử dụng. 3-Bản thân khách hàng Đối với mục đích tối đa hóa đóng gói, các lớp cũng nên đƣợc xem nhƣ là khách hàng của mình. Số lƣợng mã dựa trực tiếp vào cấu trúc của lớp nên đƣợc giảm thiểu. Nói cách khác, cấu trúc của lớp nên đƣợc gói gọn trong số minium của phƣơng pháp. Đây là sự tối thiểu hóa sự lệ thuộc của một đối tƣợng trên cấu trúc riêng của mình, cho phép thay đổi cấu trúc đó đƣợc thực hiện càng minh bạch càng tốt. Định nghĩa thiết kế hƣớng Trách nhiệm Thiết kế hƣớng trách nhiệm là đƣợc thể hiện theo tinh thần từ mô hình client/server. Nó tập trung vào các hợp đồng bằng cách hỏi: - Những hành động nào bắt đối tƣợng này chịu trách nhiệm?25 - Những thông tin nào bắt đối tƣợng này phải chia sẻ ? Một điểm quan trọng là thông tin đƣợc chia sẻ bởi một đối tƣợng có thể hoặc không thể là một phần của cấu trúc của đối tƣợng đó. Điều này có nghĩa là các đối tƣợng có thể tính toán các thông tin, hoặc nó có thể ủy thác yêu cầu thông tin cho đối tƣợng khác. Bản chất của thiết kế hƣớng đối tƣợng nằm trong cam kết ràng buộc vào cuối của chi tiết thực hiện các yêu cầu, và tập trung vào lúc đầu và giữa về các hành vi cần thiết để nhận ra những khả năng để đáp ứng yêu cầu quy định (Wirfs-Brock &Wilkerson, 1989). Một trong những nguyên lý của phƣơng pháp hƣớng đối tƣợng là khả năng của mình để giúp quản lý sự phức tạp của sự phát triển hệ thống lớn. Giải thích về mục đích, cấu trúc và hành vi của các hệ thống thông minh là tƣơng ứng phức tạp và đòi hỏi các phƣơng pháp và các công cụ tƣơng tự để giúp phơi bày những lý do cơ bản nhƣ thế nào và tại sao họ làm việc theo cách mà họ làm. Theo Wirfs-Brock và Wilkerson (1989) trách nhiệm của các đối tƣợng bao gồm cả những hành động mà họ thực hiện hoặc các thông tin mà họ cung cấp. Một điểm quan trọng là một trách nhiệm không nhất thiết phải thực hiện hoặc thực hiện hoàn toàn trong các đối tƣợng đƣợc gắn thẻ với trách nhiệm. Các đối tƣợng có thể thực hiện trách nhiệm của mình bằng cách ủy quyền toàn bộ hoặc một phần của việc thực hiện cho các đối tƣợng khác, cho các hệ thống, cho các nguồn dữ liệu, hoặc ngay cả cho con ngƣời. Điều này cho thấy một cách tiếp cận để giải thích dựa trên phân chia chức năng và nhiệm vụ của các hành vi đến các yếu tố mô hình nguyên tử do đó trách nhiệm giải trình phân tán có thể bị xử lý tại địa phƣơng đến mức tối đa có thể. Điểm mạnh của thiết kế hƣớng Trách nhiệm Đóng gói đƣợc thỏa hiệp khi các chi tiết cấu trúc của một đối tƣợng trở thành một phần của giao diện cho đối tƣợng đó. Điều này chỉ có thể xảy ra nếu các nhà thiết kế sử dụng kiến thức của những chi tiết về cấu trúc, thiết kế Trách nhiệm hƣớng tối đa hóa đóng gói khi các nhà thiết kế cố tình bỏ qua thông tin này. Tính đa hình làm tăng khả năng đóng gói, bởi vì các khách hàng của một đối tƣợng không cần phải biết cách các đối tƣợng thực hiện các dịch vụ đƣợc yêu cầu,26 mà cũng không cần biết lớp nào đã đáp ứng yêu cầu đó. Phƣơng pháp tiếp cận hƣớng trách nhiệm có thể giúp một nhà thiết kế xác định các giao thức chuẩn (tên thông điệp) bằng cách khuyến khích các nhà thiết kế tập trung vào trách nhiệm thực hiện một cách độc lập. Điều này đã làm tăng tính đa hình. Việc thiết kế các lớp mà không cần biết cấu trúc của chúng đã khuyến khích việc thiết kế hệ thống phân cấp thừa kế, vì chỉ biết kiểu của lớp đó. Nếu phân cấp thừa kế kéo theo một kiểu phân cấp, thì kiểu của các lớp là một kiểu con của lớp cha của lớp đó. Điều này có hai lợi thế: 1- Nó cải thiện đóng gói đối với khách hàng ở lớp con, đảm bảo rằng tất cả các hành vi thừa kế là một phần của hợp đồng của lớp con. 2-Nó làm cho các lớp trừu tƣợng dễ nhận diện. Một khó khăn trong việc xác định các lớp trừu tƣợng là xác định những phần nào của giao thức trong lớp hiện tại là những phần của kiểu trong các lớp dó, và những phần nào là những chi tiết thực hiện. Bởi vì các giao thức của một lớp chỉ bao gồm những thông điệp nào hình thành nên kiểu của lớp đó, do vậy sẽ loại trừ đƣợc khó khăn này. 1.3.4. Thiết kế phần mềm hƣớng kiểm thử “Test-Driven Development” có thể hiểu là mô hình phát triển với trọng tâm hƣớng về việc kiểm thử. TDD đƣợc xây dựng theo hai tiêu chí: Test-First (kiểm thử trƣớc) và Refactoring (điều chỉnh mã nguồn). Quy trình phát triển TDD khi một yêu cầu phần mềm (requirement) đƣợc đặt ra nhƣ sau: Ngƣời phát triển soạn thảo kịch bản kiểm thử (test case) cho yêu cầu đó trƣớc tiên và chạy thử kịch bản đó lần đầu tiên. Hiển nhiên, việc chạy thử sẽ đƣa ra 1 kết quả thất bại vì hiện tại chức năng đó chƣa đƣợc xây dựng (và thông qua kết quả đó, ta cũng kiểm tra đƣợc là kịch bản kiểm thử đó đƣợc viết đúng). Theo đó, dựa vào mong muốn (expectation) của kịch bản kia, ngƣời phát triển sẽ xây dựng một lƣợng mã nguồn (source code) vừa đủ để lần chạy thứ 2 của kịch bản đó thành công. Nếu trong lần chạy thứ 2 vẫn đƣa ra kết quả thất bại, điều đó có nghĩa là thiết kế chƣa ổn và ngƣời phát triển lại chỉnh sửa mã nguồn và chạy lại kịch bản đến khi thành công.27 Khi kịch bản kiểm thử đƣợc chạy thành công, ngƣời phát triển tiến hành chuẩn hóa đoạn mã nguồn (base-line code) và tiếp tục hồi quy với kịch bản kiểm thử tiếp theo. Việc chuẩn hóa bao gồm thêm các chú giải, loại bỏ các dƣ thừa, tối ƣu các biến,… Hình 3- 1Quy trình phát triển TDDđề cập vấn đề khó khăn trong việc hiểu rõ yêu cầu chức năng trước khi viết kịch bản kiểm thử Thông qua quy trình TDD nhƣ trên, có thể dễ dàng nhận ra là thứ tự các bƣớc xây dựng 1 tính năng phần mềm gần nhƣ đã đƣợc đảo ngƣợc so với 1 quy trình truyền thống. Vậy điều này giúp ích gì và có gì hay hơn? Đối với mô hình thác nƣớc (Waterfall Model): việc phân tích các yêu cầu (requirements) thƣờng đƣợc tiến hành bởi nhà phát triển một cách chuyên hóa và khi đến giai đoạn xây dựng (implementing phase) thì đa phần các nhà phát triển tiếp xúc với các yêu cầu phần mềm dƣới dạng các bản thiết kế. Họ chỉ quan tâm đến đầu vào, đầu ra (Input, Output) của tính năng mình xây dựng mà thiếu đi cái nhìn thực tiễn từ góc nhìn ngƣời dùng (end-users). Một hệ quả tất yếu là lỗi phần mềm đến từ việc sản phẩm không tiện dụng với ngƣời dùng. Cùng với Agile, việc ứng dụng TDD góp phần làm gần khoảng cách giữa đội ngũ thiết kế phần mềm và sản phẩm thực tiễn, tối ƣu quy trình. Cụ thể nhƣ sau: Thông qua kịch bản kiểm thử, nhà phát triển có cái nhìn trực quan về sản phẩm ngay trƣớc khi xây dựng mã nguồn. Sản phẩm họ tạo ra chính xác và gần gũi ngƣời dùng hơn.28 Phần mã nguồn đƣợc thêm vào chỉ vừa đủ để chạy thành công kịch bản kiểm thử, hạn chế dƣ thừa và qua đó hạn chế khả năng xảy ra lỗi trên những phần dƣ thừa. Bảo đảm mã nguồn luôn phản ánh đúng và vừa đủ yêu cầu phầm mềm, hạn chế đƣợc công sức tối ƣu mã nguồn về sau. Trong quá trình hình thành, TDD có liên quan mật thiết đến khái niệm “Test-First Programming” trong mô hình eXtreme Programming “XP” thuần túy Agile – thịnh hành từ năm 1999. Tuy nhiên, bằng việc ứng dụng đa dạng và linh hoạt, TDD cũng có những đặc điểm và tùy biến của riêng nó. Ở đây, phƣơng thức phát triển phần mềm linh hoạt (Agile Software Development), gọi tắt là “Agile”, đã trở nên phổ biến trong ngành phát triển phần mềm là một triết lý cùng với nhóm các phƣơng pháp và phƣơng pháp luận phát triển phần mềm dựa trên các nguyên tắc phát triển phân đọan lặp (iterative) và tăng trƣởng (incremental) trong đó các yêu cầu và giải pháp tiến hóa thông qua sự liên kết cộng tác giữa các nhóm tự quản và liên chức năng. Agile là cách thức làm phần mềm linh hoạt để làm sao đƣa sản phẩm đến tay ngƣời dùng càng nhanh càng tốt càng sớm càng tốt và đƣợc xem nhƣ là sự cải tiến và phổ biến vƣợt trội so với những mô hình cũ nhƣ mô hình “Thác nƣớc (waterfall)” hay “CMMI” (theo khảo sát của hãng nghiên cứu thị trƣờng Forrester). Alige thƣờng sử dụng cách lập kế hoạch thích ứng (adaptive planning), việc phát triển và chuyển giao theo hƣớng tiến hóa, sử dụng các khung thời gian ngắn và linh hoạt để dễ dàng phản hồi lại với các thay đổi trong quá trình phát triển. Với những phƣơng phức tổ chức và triển khai mới lạ, năng động và linh hoạt, Agile đã thu hút sự quan tâm lớn và trở thành sự lựa chọn hàng đầu của cộng đồng làm phần mềm. Triết lý Alige đã vƣợt xa khỏi khu vực truyền thống của mình là phát triển phần mềm để đóng góp sự thay đổi trong cách thức làm việc, quản lý, sản xuất ở các ngành khác nhƣ sản xuất, dịch vụ bán hàng, quảng cáo, giáo dục,… Thuật ngữ“Alige” chính thức đƣợc sử dụng rộng rãi theo cách thống nhất kể từ khi “Tuyên ngôn Alige” (Agile manifesto) đƣợc giới thiệu ra công chúng năm 2001. Tuyên ngôn của Agile đƣợc xem là cốt lõi là ngôi sao dẫn đƣờng trong Agile.29 Nó giúp các nhà phát triển có đƣợc gợi ý trong thực hành và vận dụng các phƣơng pháp Agile trong thực tiễn. Theo tuyên ngôn, Agile hoạt động dựa trên 4 tôn chỉ: 1-Cá nhân và sự tương tác hơn là quy trình và công cụ; 2-Phần mềm chạy tốt hơn là tài liệu đầy đủ; 3-Cộng tác với khách hàng hơn là đàm phán hợp đồng; 4-Phản hồi với các thay đổi hơn là bám sát kế hoạch. TDD đáp ứng “Tuyên ngôn về Agile” khi bản thân quy trình TDD thúc đẩy tính thực tiễn của sản phẩm, tƣơng tác với ngƣời dùng. Để phát huy tối đa những lợi ích mà TDD mang lại, độ lớn của 1 đơn vị tính năng phần mềm (unit of function) cần đủ nhỏ để kịch bản kiểm thử dễ dàng đƣợc xây dựng và đọc hiểu, công sức debug kịch bản kiểm thử khi chạy thất bại cũng giảm thiểu hơn. Hình 3- 2 TDD trong Agile framework phác họa bởi Mohammad Sami 1.3.5. Thiết kế phần mềm hướng hành vi Trong mô hình TDD nhiệm vụ kiểm thử do nhà phát triển đảm nhiệm và vai trò chuyên hóa của ngƣời kiểm thử gần nhƣ không còn nữa. Để làm tốt công việc, xuyên suốt chu trình, ngƣời phát triển phải chú ý thêm những vấn đề thuần túy của30 kiểm thử (test) nhƣ: Cái gì cần test và cái gì không?, Viết bao nhiêu kịch bản là đủ?, Làm sao để hiểu là test đó thất bại?, Bắt đầu test từ đâu?,… Để giải quyết vần đề phát sinh mà vẫn tận dụng triệt để lợi ích mà TDD mang lại, Dan North phát triển một mô hình mới với tên gọi: Behavior-Driven Development – BDD (hoặc ta có thể hiểu là Acceptance Test-Driven Development – ATDD). Trong đó, một vai trò mới trong việc thiết kế kiểm thử (Test Design) đƣợc đặt ra: Thay vì chờ đợi sản phẩm hoàn thành và kiểm thử, ngƣời tester/analyst tham gia vào quá trình xây dựng mã nguồn với vai trò phân tích và xây dựng hệ thống kịch bản kiểm thử dƣới góc độ ngôn ngữ tự nhiên dễ hiểu từ các yêu cầu (requirement). Đồng thời, họ giúp đỡ ngƣời phát triển trong việc giải thích và đƣa ra các phƣơng án xây dựng mã nguồn mang tính thực tiễn với ngƣời dùng ngay trƣớc khi bắt tay xây dựng. Ngƣời phát triển liên hệ mật thiết với ngƣời tester và xây dựng mã nguồn với những phƣơng án mà ngƣời kiểm thử cung cấp theo mô hình TDD. Kịch bản kiểm thử đƣợc phân chia làm 2 lớp: Lớp chấp nhận (feature/acceptance test) và Lớp đơn vị (unit test). Theo đó, kịch bản kiểm thử lớp đơn vị mang thuần tính thiết kế và phục vụ cho việc kiểm thử đơn vị (Unit test) còn kịch bản kiểm thử lớp chấp nhận có thể đƣợc tái sử dụng cho quá trình kiểm thử hồi quy (Regression Test) về sau Hình 3- 3 Mô hình BDD – TDD trong Agile mô phỏng bởi Paul Littlebury Từ mô hình trên ta dễ dàng nhìn nhận đƣợc sự ƣu việt BDD mang lại đặc biệt là trong các dự án phần mềm lớn và phức tạp, khi cả hai khía cạnh phân hóa vai31 trò và chất lƣợng phải đi đôi. Ngoài ra, việc chạy kịch bản kiểm thử và xử lý sớm các vấn đề thiết kế ngay trong khâu xây dựng giúp giảm thiểu tối đa chi phí và công sức sữa chữa lỗi. Trong khi khái niệm BDD mang tính lý thuyết, việc ứng dụng của nó lại đặt nặng sự thực nghiệm. Để phát huy lợi ích về thời gian trong việc xây dựng kịch bản kiểm thử, ngôn ngữ và cách truyền tải là một thử thách khi phải đáp ứng khả năng đọc hiểu từ cả hai khía cạnh: tự nhiên và thiết kế. Bằng sự vay mƣợn từ ngôn ngữ viết User Story, ngôn ngữ Gherkin đƣợc phát triển để phục vụ nhu cầu đó với cấu trúc đơn giản, hƣớng đối tƣợng và tƣơng đồng cho mọi kịch bản: Given – When – Then. Ví dụ: Given: Là một sinh viên, When: Tôi đăng ký một khóa học thành công Then: Tôi phải thấy tên khóa học hiện ra trong danh sách môn học của tôi. Nói gọn lại, BDD (Behaviour Driven Development) là một quá trình phát triển phần mềm dựatrên phƣơng pháp Agile (phát triển phần mềm linh hoạt); nó là sự mở rộng của TDD (Test driven development). Thay vì tập trung vào phát triển phần mềm theo hƣớng kiểm thử, BDD tập trung vào phát triển phần mềm theo hƣớng hành vi. BDD thêm vào những phƣơng pháp sau: -Áp dụng kỹ thuật“5 Why” vào mỗi vấn đề của ngƣời sử dụng để biết đƣợc giá trị kinh doanh củamỗi ngƣời sử dụng. -“Tƣ duy từ ngoài vào”, tức là chỉ cài đặt những hành vi mang lại giá trị kinh doanh để giảm thiểu lãng phí. -Mô tả hành vi theo một loại ngôn ngữ mà cả chuyên gia nghiệp vụ, kiểm thử viên và nhà phát triển có thể giao tiếp đƣợc với nhau. Dựa vào yêu cầu các kịch bản kiểm thử (Scenarios) sẽ đƣợc viết trƣớc dƣới dạng ngôn ngữ tự nhiên và dễ hiểu nhất sau đó mới thực hiện cài đặt mã nguồn. Những kịch bản kiểm thử này đƣợc viết dƣới dạng các tệpđặc trƣng (feature file) và đòi hỏi sự cộng tác từ tất cả các thành viên tham gia dự án hay các bên liên quan (stakeholder).32 BDD đƣợc viết dƣới dạng plain text language gọi là Gherkin. Những lợi ích khi sử dụng BDD bao gồm: – Giúp xác định đúng yêu cầu của khách hàng: tài liệu đƣợc viết dƣới dạng ngôn ngữ tự nhiên, bất kỳ đối tƣợng nào cũng có thể hiểu đƣợc. Khi đọc tài liệu này, khách hàng có thể dễ dàng nhận biết đƣợc lập trình viên có hiểu đúng yêu cầu của họ không và có phản hồi kịp thời. – Là tài liệu sống của dự án: tài liệu này luôn đƣợc cập nhật khi có bất kỳ sự thay đổi nào nên tất cả các thành viên sẽ không bị miss thông tin khi phát triển hệ thống – Nâng cao chất lƣợng phần mềm, tạo ra sản phẩm hữu ích: vì phát triển phần mềm theo hƣớng hành vi nên có thể focus vào việc tạo ra sản phẩm đúng với yêu cầu của khách hàng nhƣng vẫn hữu ích cho ngƣời dùng. Nhƣ vậy, Behaviour Driven Development là một quá trình phát triển phần mềm dựa trên thử nghiệm hƣớng phát triển. BDD quy định rằng các ngƣời phát triển và ngƣời sở hữu sản phẩm cần hợp tác và xác định hành vi của ngƣời sử dụng. TDD với việc cộng gộp vai trò cả của kiểm thử chấp nhận (acceptance test) vào ngƣời phát triển dẫn tới phát sinh vấn đề quá tải cho ngƣời phát triển. Do đó, BDD sinh ra, hƣớng tới các kiểm thử đặc trƣng (feature test) mà ngƣời thực hiện là các ngƣời kiểm thửchấp nhận (Acceptance Tester). Thay vì chờ đợi sản phẩm hoàn thành và kiểm thử, ngƣời kiểm thử hay ngƣời phân tích tham gia vào quá trình xây dựng mã nguồn với vai trò phân tích và xây dựng hệ thống kịch bản kiểm thử dƣới góc độ ngôn ngữ tự nhiên dễ hiểu từ các yêu cầu (requirement). Đồng thời, họ giúp đỡ ngƣời phát triển trong việc giải thích và đƣa ra các phƣơng án xây dựng mã nguồn mang tính thực tiễn với ngƣời dùng ngay trƣớc khi bắt tay xây dựng. Ngƣời phát triển liên hệ mật thiết với ngƣời kiểm thử và xây dựng mã nguồn với những phƣơng án mà ngƣời kiểm thử cung cấp theo mô hình TDD. Kịch bản kiểm thử đƣợc phân chia làm 2 lớp: 1-Kiểm thử chấp nhận (feature/acceptance test) 2- Kiểm thử đơn vị (unit test) .33 Theo đó, kịch bản kiểm thử đơn vị mang thuần tính thiết kế và phục vụ cho việc kiểm thửđơn vị (Unit test) còn kịch bản kiểm thử lớp chấp nhận có thể đƣợc tái sử dụng cho quá trình kiểm thử hồi quy về sau (Regression Test) Một ứng dụng phổ biến của BDD là cố gắng kế thừa TDD bằng cách tập trung chủ yếu vào việc tạo ra nhiều phép thử của các kiểm thử ch ấp nhận hoặc chạy thử các đặc tả kỹ thuật. Mỗi đặc tả kỹ thuật tƣơng ứng với đầu vào chu kỳ phát triển và mô tả, từ quan điểm của ngƣời dùng từng bƣớc từng bƣớc một, làm thế nào hệ thống hoạt động chính xác. Với một lần viết kịch bản nhƣng các ngƣời phát triển có thể sử dụng đặc điểm kỹ thuật và quá trình TDD sẵn có của họ để triển khai phát triển mã trình đáp ứng đúng kịch bản. 1.3.5. Thiết kế phần mềm hƣớng lĩnh vực Thiết kế hƣớng lĩnh vực (Domain Driven Design- DDD) đƣợc giới thiệu lần đầu tiên bởi Eric Evans, trong cuốn sách của ông với tựa đề: Domain Driven Design Tackling Complexity in the Heart of Software. DDD là cách tiếp cận đến phát triển phần mềm cho phép các đội quản lý cấu trúc và bảo trì phần mềm trong những lĩnh vực có độ phức tạp lớn. Đây là nội dung quan trọng mà luận văn hƣớng tới đi sâu nghiên cứu và ứng dụng. Chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực sẽ đƣợc trình bày chi tiết ngay trong chƣơng sau. KẾT LUẬN CHƢƠNG Một tiến trình phát triển phần mềm là một tập của các hoạt động cần thiết (đặctả, xây dựng, đánh giá, tiến hóa) để chuyển các yêu cầu của ngƣời dùng thành một hệ thống phần mềm đáp ứng đƣợc các yêu cầu đặt ra. Có năm bƣớc chính cần thực hiện trong quá trình phát triển phần mềm: - Xác định các yêu cầu - Phân tích hệ thống - Thiết kế hệ thống - Lập trình và kiểm tra hệ thống - Vận hành và bảo trì hệ thống.34 Do các hệ phần mềm lớn là phức tạp nên ngƣời ta thƣờng dùng các cách tiếp cận khác nhau trong việc thiết kế các phần khác nhau của một hệ thống. Chẳng có một cách tiếp cận nào tốt nhất chung cho các dự án. Hai cách tiếp cận thiết kế hiện đang đƣợc dùng rộng rãi trong việc phát triển phần mềm đó là cách tiếp cận theo hƣớng chức năng và hƣớng đối tƣợng. Mỗi cách tiếp cận đều có ƣu và nhƣợc điểm riêng phụ thuộc vào ứng dụng phát triển và nhóm phát triển phần mềm. Chúng bổ sung và hỗ trợ cho nhau chứ không đối kháng nhau. Có một số chiến lƣợc hiện đại để thiết kế phần mềm nhƣ thiết kế phần mềm theo hƣớng mô hình,hƣớng dữ liệu, hƣớng trách nhiệm, hƣớng kiểm thử, hƣớng hành vi, hƣớng lĩnh vực. Mỗi hƣớng có những đặc thù riêng và có những lợi thế riêng, trong đó hƣớng lĩnh vực là trọng tâm nghiên cứu của luận văn.35 Chƣơng 2 Chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực 2.1. Cách tiếp cận hƣớng lĩnh vực trong tiến trình phát triển phần mềm 2.1.1. Khái niệm về thiết kế hƣớng lĩnh vực Với cách tiếp cận truyền thống khi xây dựng một ứng dụng. Đầu tiên ta đọc các yêu cầu đặc tả và tìm hiểu các chức năng, sau đó tiến hành chia nhỏ các công việc. Trong phần lớn trƣờng hợp, việc này nhằm mục đích ƣớc lƣợng thời gian và lên kế hoạch thực hiện cho các công việc. Vậy trình tự công việc sẽ là ƣớc lƣợng thời gian, chia việc cho các thành viên trong team, thiết kế CSDL, cuối cùng là bắt tay và code. Đây là cách thiết kế hƣớng dữ liệu hay còn gọi là Data Driven Design [1]. Vậy vấn đề với cách tiếp cận là gì? Lâu nay ta vẫn tiếp cận theo cách này và vẫn làm tốt ? Câu trả lời là Đúng và Sai. Đúng ở chỗ ta vẫn làm tốt trong việc bàn giao Project, Sai ở chỗ ta chƣa thực hiện tốt trong việc bảo trì và mở rộng project. Trong các ứng dụng điển hình có rất nhiều phần code xử lý các công việc không liên quan đến Logic nghiệp vụ nhƣ truy cập file, mạng hay database, các thành phần này thƣờng đƣợc gọi là plumping code (điền code) và đƣợc nhúng trực tiếp vào trong Business Object và nhiều Business Logic cũng đƣợc nhúng vào thao tác của giao diện Widget hay script của database, điều này thƣờng xảy ra vì nó làm ta phát triển ứng dụng một cách nhanh chóng và dễ dàng. Việc này dẫn đến phần lớn thời gian phát triển của Deverloper là dành cho việc viết các plumping code thay vì viết Business Logic thực sự, nó làm cho thiết kế của ta bị mất đi tính hƣớng đối tƣợng trong thực tế. Ngoài ra khi logic nghiệp vụ trộn lẫn với lớp khác khiến cho việc đọc hiểu và suy nghĩ về logic của ứng dụng trở nên khó khăn hơn đối với những ngƣời ngoài. Chỉ một thay đổi nhỏ ở tầng UI (User interface)cũng có thể dẫn tới việc thay đổi tầng logic và ngƣợc lại khi thay đổi một business rule của ứng dụng đòi hỏi ta phải36 quan tâm đến từng chi tiết nhỏ phía UI cũng nhƣ database để đáp ứng đƣợc sự thay đổi này. Trong những ứng dụng nhỏ thì vấn đề này ta không nhìn thấy. Ở các ứng dụng cỡ vừa thì thấy vấn đề này đã tồn tại và bắt đầu dẫn đến tình trạng phá vỡ các thiết kế chuẩn. Đối với các ứng dụng lớn thì nó trở thành vấn đề nghiêm trọng, cách tiếp cận trên sẽ không thể cho ta đƣa ra một thiết kế hƣớng đối tƣợng chính xác. Giải pháp ở đây chính là Domain Driven Design. Vậy DDD là gì ? DDD không liên quan gì đến công nghệ hay framework là những thứ thuộc về tầng vật lý mà nó là một khái niệm thuộc về tầng logic khi ta xây dựng một hệ thống phần mềm. Cụ thể hơn nó là mẫu thiết kế (design pattern) và hơn nữa đây là design pattern ở cấp độ kiến trúc của hệ thống, ta cần phân biệt rõ điều này để phân biệt các design pattern và ở cấp độ class. Nó cung cấp một cấu trúc thực hành và các thuật ngữ cho việc ra quyết định thiết kế nhằm tập trung và tăng tốc các dự án phần mềm trong các lĩnh vực phức tạp. 2.1.2.Tìm hiểu về lĩnh vực Để tạo một phần mềm tốt, cần hiểu về phần mềm đó. Ta không thể làm ra hệ thống phần mềm ngân hàng nếu trừ khi ta có hiểu biết tƣơng đối tốt về mảng ngân hàng và những điều liên quan. Nghĩa là, để làm phần mềm tốt, ta cần hiểu lĩnh vực ngân hàng. Liệu có thể làm đƣợc phần mềm ngân hàng phức tạp dù không có hiểu biết nghiệp vụ tốt? Không thể. Không bao giờ. Ai hiểu về banking? Ngƣời thiết kế phần mềm? Không. Ngƣời này chỉ tới ngân hàng để gửi tiền và rút tiền khi cần. Ngƣời phân tích phần mềm? Cũng không hẳn. Anh ta chỉ biết phân tích một chủ đề cụ thể khi anh ta có đầy đủ tất cả cấu phần. Lập trình viên? Vậy là ai? Nhân viên ngân hàng, hiển nhiên. Hiểu nhất về hệ thống ngân hàng là những ngƣời ở trong đó, những chuyên gia của họ. Họ hiểu mọi thứ chi tiết, cái haydở, mọi vấn đề có thể và mọi quy định. Đây là nơi ta thƣờng xuất phát: Lĩnh vực (domain). Giả sử cần xây dựng một hệ thống phần mềm quản lý bệnh viện. Rõ ràng là cần phải làm việc với đội ngũ bác sĩ, y tá (chính là các chuyên gia trong lĩnh vực này - domain expert) để xây dựng kiến thức về domain. Qua nói chuyện, trao đổi kiến thức, đặt câu hỏi và trả lời. Cần hiểu rõ càng nhiều càng tốt về domain này. Bằng37 cách đặt câu hỏi đúng, xử lý thông tin đúng cách, kỹ sƣ phần mềm và chuyên gia sẽ dần vẽ ra một domain, một mô hình domain (domain model). Kỹ sƣ phần mềm, kết hợp với domain expert cùng tạo nên một domain model và mô hình đó là nơi kiến thức chuyên môn của cả hai bên đƣợc kết hợp và tổng hợp lại. Hãy xem xét tiếp ví dụ sau. Giả sử ta đang tham gia thiết kế một tòa nhà. Yêu cầu là: + Xây dựng trên một diện tích đất cố định + Tòa nhà cao 6 tầng + Mỗi tầng có 4 căn hộ Vậy domain ở đây là gì? Là công trình xây dựng chăng? Cũng có thể. Nhƣng nếu xem công trình xây dựng là domain, thì thể ta đang bỏ qua một vài chi tiết trong yêu cầu. Công trình xây dựng đang thiết kế phải bao gồm thiết kế căn hộ cho ngƣời dân sinh sống. Vậy thuật ngữ "công trình xây dựng" có thể khiến ta bỏ lỡ chi tiết, thay vì đó ta có thể thu hẹp xuống thành "chung cư". Lúc này nếu nói với các kỹ sƣ về việc thiết kế, rõ ràng thuật ngữ "chung cư" sẽ dễ hiểu hơn là "công trình xây dựng" đơn thuần. Ta thấy đấy, chỉ một thay đổi nhỏ trong ngôn từ cũng có thể tạo nên sự khác biệt. Trở lại ví dụ phần mềm bệnh viện ở trên, ngƣời thiết kế phần mềm và các bác sĩ, y tá không thể nói cùng một ngôn ngữ đƣợc. Họ nói về từ ngữ chuyên môn, ngƣời thiết kế phần mềm nói bằng đối tƣợng, phƣơng thức, quan hệ. Đó chính là lúc ta cần một ngôn ngữ chung để cả hai bên có thể làm việc với nhau dễ dàng hơn.38 2.1.3.Ngôn ngữ chung Hình 2- 1. Mô hình ngôn ngữ chung Ta đã thấy sự cần thiết không thể phủ nhận của việc phát triển mô hình cho domain qua sự làm việc giữa chuyên gia phần mềm và chuyên gia domain; tuy nhiên, cách làm này ban đầu thƣờng gặp những khó khăn về rào cản giao tiếp cơ bản. Lập trình viên chỉ nghĩ tới lớp, method, thuật toán, pattern và có khuynh hƣớng diễn tả mọi thứ đời thƣờng bằng những tạotác lập trình. Họ muốn nhìn lớp đối tƣợng và tạo quan hệ mô hình giữa chúng. Họ nghĩ đến những thứ nhƣ kế thừa, đa hình, OOP... Và họ luôn nói theo cách đó. Điều này là dễ hiểu với lập trình viên. Lập trình viên vẫn chỉ là lập trình viên. Tuy vậy, chuyên gia domain thƣờng không hiểu những khái niệm đó. Họ không có khái niệm gì về thƣ viện, framework phần mềm và trong nhiều trƣờng hợp, thậm chí họ không hiểu về cơ sở dữ liệu. Tất cả những gì họ biết là chuyên ngành cụ thể của họ. Ví dụ: Trong theo dõi không lƣu, chuyên gia domain biết về máy bay, route, cao độ, vĩ độ, kinh độ,độ lệch của route chuẩn, về quỹ đạo của máy bay. Họ nói về những điều này bằng ngôn ngữ riêng của họ, đôi khi gây khó hiểu với ngƣời ngoài ngành. Để vƣợt qua sự khác nhau về cách giao tiếp, ta xây dựng mô hình, ta phải trao đổi, giao tiếp ý tƣởng về mô hình, về những thành phần liên quan đến mô hình, cách ta liên kết chúng, chúng có liên quan với nhau hay không. Giao tiếp ở mức độ39 này là tối quan trọng cho sự thành công của dự án. Nếu ai đó nói điều gì đó và ngƣời khác không hiểu, hoặc tệ hơn, hiểu sai, thì liệu ta có cơ hội tiếp tục dự án không? Dự án sẽ gặp vấn đề nghiêm trọng nếu thành viên nhóm không chia chung ngôn ngữ khi trao đổivề domain. Chuyên gia domain dùng từ lóng của riêng họ trong khi thành viên kỹ thuật lại dùng ngôn ngữ riêng của họ để trao đổi về những thuật ngữ của domain trong thiết kế. Bộ thuật ngữ trong trao đổi hành ngày tách riêng với bộ thuật ngữ nhúng trong mã nguồn (là sản phẩm quan trọng cuối cùng của dự án phần mềm). Cùng một ngƣời có thể dùng khác ngôn ngữ khi nói hay viết do đó các thể hiện sắc sảo nhất của domain thƣờng hiện ra và biến mất chóng vánh,không thể nhìn thấp trong mã nguồn hay trong văn bản viết. Khi trao đổi, ta thƣờng "dịch" sự hiểu về khái niệm nào đó. Lập trình viên thƣờng diễn tả mẫu thiết kế bằng ngôn ngữ bình dân và thƣờng là họ thất bại. Chuyên gia domain cố gắng hiểu những ý tƣởng đó và thƣờng tạo ra bộ jargon mới. Khi cuộc chiến đấu về ngôn ngữ kiểu này xảy ra, sẽ rất khó để có quy trình xây dựng kiến thức. Ta có khuynh hƣớng dùng "phương ngữ" riêng của mình trong phiên thiết kế, các "phương ngữ" này có thể trở thành ngôn ngữ chung vì không một ngôn ngữ nào thỏa mãn nhu cầu của tất cả mọi ngƣời. Hiển nhiên ta cần nói chung một ngôn ngữ khi ta gặp và trao đổi về mô hình, qua nghĩa chúng. Vậy ngôn ngữ sẽ là gì? Là ngôn ngữ của lập trình viên? Là ngôn ngữ củachuyên gia domain? Hay một cái gì đó khác, ở giữa? Một nguyên tắc cốt lõi của thiết kế hƣớng lĩnh vực là sử dụng ngôn ngữ dựa trên mô hình. Vì mô hình là xuất phát điểm chung, là nơi ở đó phần mềm "gặp" domain, việc sử dụng nó là nền tảng cho ngôn ngữ là hợp lý. Hãy sử dụng mô hình nhƣ là xƣơng sống của ngôn ngữ. Hãy yêu cầu nhóm sử dụng ngôn ngữ một cách nhất quán trong mọi trao đổi, bao gồm cả mã nguồn. Khi chia sẻ và làm mô hình, nhóm dùng ngôn ngữ nói, viết và giản đồ. Hãy đảm bảo rằng ngôn ngữ xuất hiện một cách nhất quán trong mọi hình thức trao đổi sử dụng trong nhóm; chính vì lý do này, ngôn ngữ này đƣợc gọi là Ngôn ngữ chung.40 Ngôn ngữ chung kết nối mọi phần của thiết kế, tạo thành tiền hoạt động của nhóm thiết kế. Có thể mất hàng vài tuần hay thậm chí vài tháng để thiết kế của một dự án lớn ổn định đƣợc. Thành viên nhóm phát hiện yếu tố mới trong thiết kế cần hay cần xem xét để đƣa vào thiết kế tổng thể. Những việc này không thể làm đƣợc nếu thiếu ngôn ngữ chung. Ngôn ngữ không xuất hiện một cách dễ dàng. Nó đòi hỏi nỗ lực và sự tập trung để đảm bảo rằng những thành phần chính của ngôn ngữ đƣợc chắt lọc. Ta cần tìm ra những khái niệm chính, định nghĩa domain và thiết kế, tìm ra những thuật ngữ tƣơng ứng và sử dụng chúng. Một số từ dễ nhìn ra, một số khó tìm ra hơn. Vƣợt qua những khó khăn bằng việc trình bày theo một cách khác mô tả mô hình khác. Sau đó refactor mã nguồn, đổi tên lớp, method, mô-đun để phù hợp với mô hình mới. Giải quyết sự nhầm lẫn về thuật ngữ trong trao đổi chính là cách ta làm để đi tới sự đồng thuận của những thuật ngữ tầm thƣờng. Xây dựng một ngôn ngữ theo cách đó có hiệu quả rõ ràng: Mô hình và ngôn ngữ gắn kết chặt hơn. Một thay đổi ngôn ngữ nên kéo theo sự thay đổi về mô hình. Chuyên gia domain cần phản đối những từ hoặc cấu trúc rắc rối hay không phù hợp cho việc hiểu domain. Nếu chuyên gia domain không hiểu điều gì đó trong mô hình hoặc ngôn ngữ thì chắc chắn có gì không ổn. Mặt khác, lập trình viên cần để tới sự không rõ ràng và tính không nhất quán vốn hay xảy ra trong thiết kế 2.2. Các đặc trƣng thiết kế phần mềm hƣớng lĩnh vực Khi ta tạo ra một ứng dụng phần mềm, một lƣợng lớn thành phần của ứng dụng không liên quan trực tiếp đến nghiệp vụ, nhƣng chúng là một phần của hạ tầng phần mềm hoặc phục vụ chính bản thân ứng dụng. Nó có khả năng và ổn cho phần nghiệp vụ của ứng dụng nhỏ so với các phần còn lại, vì một ứng dụng điển hình chứa rất nhiều đoạn mã liên quan đến truy cập CSDL, tệp hoặc mạng, giao diện ngƣời dùng,...Trong một ứng dụng hƣớng đối tƣợng thuần túy, giao diện ngƣời dùng, mã truy cập CSDLvà các đoạn mã hỗ trợ khác thƣờng đƣợc viết trực tiếp vào trong các đối tƣợng nghiệp vụ. Thêm vào đó, đối tƣợng nghiệp vụ này lại đƣợc nhúng vào trong các hành vi của giao diện ngƣời dùng và các kịch bản CSDL. Đôi khi điều này diễn ra bởi vì nó là cách dễ nhất để làm cho mọi việc trở nên nhanh chóng. Tuy nhiên, khi các đoạn code liên quan đến nghiệp vụ đƣợc trộn lẫn giữa các41 tầng lại với nhau, nó trở nên vô cùng khó khăn cho việc đọc cũng nhƣ suy nghĩ về chúng. Các thay đổi ở giao diện ngƣời dùng cũng có thể thực sự thay đổi cả logic nghiệp vụ. Để thay đổi logic nghiệp vụ có thể yêu cầu tới truy vết tỉ mỉ các đoạn mã của giao diện ngƣời dùng, CSDL, hoặc các thành phần khác của chƣơng trình. Mô hình phát triển hƣớng đối tƣợng trở nên phi thực tế. Kiểm thử tự động sẽ khó khăn. Với tất cả các công nghệ và logic liên quan trong từng hoạt động, chƣơng trình cần đƣợc giữ rất đơn giản hoặc không thì sẽ biến chúng trở nên không thể hiểu đƣợc. Do đó, hãy phân chia một chƣơng trình phức tạp thành các LỚP. Phát triển một thiết kế cho mỗi LỚP để chúng trở nên gắn kết và chỉ phụ thuộc vào các tầng bên dƣới. Tuân theo khuôn mẫu kiến trúc chuẩn để cung cấp liên kết lỏng lẻo tới các tầng phía trên. Tập trung các đoạn mã liên quan đến các đối tƣợng nghiệp vụ trong một lớp và cô lập chúng khỏi lớp giao diện ngƣời dùng, ứngdụng và infrastructure. Các đối tƣợng nghiệp vụ, đƣợc giải phóng khỏi việc hiển thị, lƣu trữ chính chúng, hay quản lý các nhiệm vụ của ứng dụng, … và có thể tập trung vào việc biểu hiện domain model. Điều này cho phép một model tiến hóa đủ phong phú và rõ ràng, nhằm nắm bắt kiến thức nghiệp vụ thiết yếu và áp dụng nó vào làm việc. Một giải pháp kiến trúc chung cho DDD chứa bốn lớp (trên lý thuyết): Hình 2- 2 Kiến trúc phân lớp - Giao diện ngƣời dùng(User Interface - Presentation Layer):Chịu trách nhiệm trình bày thông tin tới ngƣời sử dụng và thông dịch lệnh của ngƣời dùng. - Lớp chƣơng trình(Application Layer): Đây là một lớp mỏng phối hợp các hoạt động của ứng dụng. Nó không chứa logic nghiệp vụ. Nó không lƣu giữ42 trạng thái của các đối tƣợng nghiệp vụ nhƣng nó có thể giữ trạng thái của một tiến trình của ứng dụng. - Lớp Domain(Domain Layer): Tầng này chứa thông tin về các lĩnh vực. Đây là trái tim của nghiệp vụ phần mềm. Trạng thái của đối tƣợng nghiệp vụ đƣợc giữ tại đây. Persistence của các đối tƣợng nghiệp vụ và trạng thái của chúng có thể đƣợc ủy quyền cho tầng Infrastructure. - Lớp hạ tầng (Infrastructure Layer):Lớp này đóng vai trò nhƣ một thƣ viện hỗ trợ cho tất cả các lớp còn lại. Nó cung cấp thông tin liên lạc giữa các lớp, cài đặt persistence cho đối tƣợng nghiệp vụ, đồng thời chứa các thƣ viện hỗ trợ cho tầng giao diện ngƣời dùng,... Điều quan trọng là phải phân chia một ứng dụng ra nhiều lớp riêng biệt và thiết lập các quy tắc tƣơng tác giữa các lớp với nhau. Nếu các đoạn code không đƣợc phân chia rõ ràng thành các lớp nhƣ trên, thì nó sẽ sớm trở nên vƣớng víu khiến vô cùng khó khăn cho việc quản lý các thay đổi. Một thay đổi nhỏ trong một phần của đoạn code có thể gây kết quả bất ngờ và không mong muốn trong các phần khác. Lớp domain nên tập trung vào những vấn đề nghiệp vụ cốt lõi. Nó không nên tham gia vào các hoạt động của infrastructure. Giao diện ngƣời dùng không nên kết nối quá chặt chẽ với các logic nghiệp vụ, cũng nhƣ không nên làm các nhiệm vụ mà thông thƣờng thuộc về các lớp infrastructure. Một lớp application cần thiết trong nhiều trƣờng hợp. Nó cần thiết để quản lý logic nghiệp vụ mà trong đó là giám sát và điều phối toàn bộ hoạt động của ứng dụng. Chẳng hạn, một sự tƣơng tác điển hình của các lớp application, domain và infrastructure có thể rất giống nhau. Ngƣời dùng muốn đặt một chặng bay và yêu cầu một service trong lớp application để làm nhƣ vậy. Tầng application sẽ tìm nạp các đối tƣợng nghiệp vụ có liên quan từ infrastructure vàgọi các phƣơng thức có liên quan từ chúng, ví dụ để việc kiểm tra security margin của các chuyến bay đã đặt khác. Một khi đối tƣợng nghiệp vụ đã vƣợt qua tất cả các kiểm tra và trạng thái của chúng đƣợc cập nhật sang “đã chốt”, dịch vụ chƣơng trình sẽ gắn kết với đối tƣợng trong lớp hạ tầng.43 Đến đây thì ta sẽ thấy kiến trúc của DDD tuy mới nhìn có vẻ lạ nhƣng chỉ đơn giản là nó tùy biến lại mô hình kiến trúc 3 lớp (3-tier architecture) cho linh hoạt hơn. Tính linh hoạt này đƣợc tạo ra từ hệ quả của việc tái tổ chức lại các layer từ mô hình ba lớp, nó thể hiện ở data flow và control flow giữa 2 mô hình. Hình 2- 3 Mô hình 3 lớp Ta có thể thấy là trong mô hình 3 lớp thì tầng trên sẽ phụ thuộc trực tiếp vào tầng dƣới nên không thể truy cập dữ liệu một cách trực tiếp từ tầng Presentation sang tầng Data Access Layer mà không thông qua tầng Business Layer. Còn mô hình DDD thì từ tầng User Interface nếu muốn lƣu cái gì đó vào trong database chẳng hạn nó có thể gọi trực tiếp xuống tầng Infrastructure để làm đƣợc việc đó. Rõ ràng là trong kiến trúc DDD thì tính lose coupling đƣợc đảm bảo tốt hơn. Có thể hình dung một cách trực quan là mô hình 3 lớp giống nhƣ một ngôi nhà 3 tầng chỉ có cầu thang bộvà việc di chuyển giữa tầng một và tầng 3 cần đi qua sàn tầng 2, trong khi mô hình DDD giống nhƣ ngôi nhà 4 tầng có lắp thêm thang máy, ta có thể di chuyển đến các tầng khác nhau một cách tự do hơn.[8] 2.2.1 Thực thể Trong các đối tƣợng của một phần mềm, có một nhóm các đối tƣợng có định danh riêng, những định danh - tên gọi này của chúng đƣợc giữ nguyên xuyên suốt trạng thái hoạt động của phần mềm. Đối với những đối tƣợng này thì các thuộc tính của chúng có giá trị nhƣ thế nào không quan trọng bằng việc chúng tồn tại liên tục và xuyên suốt quá trình của hệ thống, thậm chí là sau cả khi đó. Chúng đƣợc gọi tên là những Thực thể - Entity. Các ngôn ngữ lập trình thƣờng lƣu giữ các đối tƣợng trong bộ nhớ và chúng đƣợc gắn với một tham chiếu hoặc một địa chỉ nhớ cho từng44 đối tƣợng. Tham chiếu trong vùng nhớ này có đặc điểm là sẽ không thay đổi trong một khoảng thời gian nhất định khi chạy chƣơng trình, tuy nhiên không có gì đảm bảo là nó sẽ luôn nhƣ vậy mãi. Thực tế là ngƣợc lại, các đối tƣợng liên tục đƣợc đọc vào và ghi ra khỏi bộ nhớ, chúng có thể đƣợc đóng gói lại và gửi qua mạng và đƣợc tái tạo lại ở đầu kia, hoặc có thể chỉ đơn giản là chúng sẽ bị hủy. Và do vậy nên tham chiếu này chỉ đại diện cho một trạng thái nhất định của hệ thống và không thể là định danh mà ta đã nói ở trên đƣợc. Lấy ví dụ một lớp chứa thông tin về thời tiết, ví dụ nhƣ nhiệt độ, khả năng có hai đối tƣợng có cùng một giá trị là hoàn toàn có thể xảy ra. Cả hai đối tƣợng này y hệ nhau và có thể sử dụng thay thế cho nhau, tuy nhiên chúng có tham chiếu khác nhau. Đây không phải là Thực thể. Lấy một ví dụ khác, để tạo một lớp Person chứa thông tin về một ngƣời ta có thể tạo Person với các trƣờng nhƣ: tên, ngày sinh, nơi sinh v.v... Những thuộc tính này có thể coi là định danh của một ngƣời không? Tên thì không phải vì có thể có trƣờng hợp trùng tên nhau, ngày sinh cũng không phải là định danh vì trong một ngày có rất nhiều ngƣời sinh ra và nơi sinh cũng vậy. Một đối tƣợng cần phải đƣợc phân biệt với những đối tƣợng khác cho dù chúng có chung thuộc tính đi chăng nữa. Việc nhầm lẫn về định danh giữa các đối tƣợng có thể gây lỗi dữ liệu nghiêm trọng. Cuối cùng ta hãy thử xem xét một hệ thống tài khoản ngân hàng. Mỗi tài khoản có một số tài khoản riêng và chúng có thể đƣợc xác định chính xác thông qua con số này. Số tài khoản đƣợc giữ nguyên trong suốt thời gian tồn tại của hệ thống, đảm bảo tính liên tục. Nó có thể đƣợc lƣu nhƣ là một đối tƣợng trong bộ nhớ, hoặc có thể đƣợc xóa trong bộ nhớ và ghi ra cơ sở dữ liệu. Khi tài khoản bị đóng thì nó có thể đƣợc lƣu trữ ra đâu đó và sẽ tiếp tục tồn tại chừng nào còn có nhu cầusử dụng. Cho dù đƣợc lƣu ở đâu thì con số này vẫn là không đổi. Do vậy, để có thể viết đƣợc một Thực thể trong phần mềm ta cần phải tạo một Định danh. Đối với một ngƣời đó có thể là một tổ hợp của các thông tin nhƣ: tên, ngày sinh, nơi sinh, tên bố mẹ, địa chỉ hiện tại v.v..., hay nhƣ ở Mỹ thì có thể chỉ cần mã số an sinh xã hội. Đối với một tài khoản ngân hàng thì số tài khoản là đủ để tạo định danh. Thông thƣờng định danh là một hoặc một tổ hợp các thuộc tính của một đối tƣợng, chúng có thể45 đƣợc tạo để lƣu riêng cho việc định danh, hoặc thậm chí là hành vi. Điểm mấu chốt ở đây là hệ thống có thể phân biệt hai đối tƣợng với hai định danh khác nhau một cách dễ dàng, hay hai đối tƣợng chung định danh có thể coi là một. Nếu nhƣ điều kiện trên không đƣợc thỏa mãn, cả hệ thống có thể sẽ gặp lỗi. Có nhiều cách để tạo một định danh duy nhất cho từng đối tƣợng. Định danh (từ nay ta gọi là ID) có thể đƣợc sinh tự động bởi một mô đun và sử dụng trong nội bộ phần mềm mà ngƣời sử dụng không cần phải biết. Đó có thể là một khóa chính trong cơ sở dữ liệu, điều này đảm bảo tính duy nhất của khóa. Mỗi khi đối tƣợng đƣợc lấy ra từ cơ sở dữ liệu, ID của đối tƣợng sẽ đƣợc đọc và tạo lại trong bộ nhớ. Trong trƣờng hợp khác, ID của một sân bay lại đƣợc tạo bởi ngƣời dùng, mỗi sân bay sẽ có một ID chung đƣợc cả thế giới ghi nhận và đƣợc sử dụng bởi các công ty vận chuyển trên toàn thế giới trong lịch trình bay của họ. Một giải pháp khác là sử dụng luôn những thuộc tính của đối tƣợng để làm ID, nếu nhƣ vẫn chƣa đủ thì có thể tạo thêm một thuộc tính khác cho việc đó. Khi một đối tƣợng đƣợc xác định bởi định danh thay vì thuộc tính của nó, hãy làm rõ việc này trong định nghĩa model của đối tƣợng. Định nghĩa của một lớp nên chú trọng vào tính đơn giản, liên tục của chu kỳ tồn tại (life cycle) của chúng. Nên có một phƣơng thức để phân biệt các đối tƣợng mà không phụ thuộc vào trạng thái hay lịch sử của chúng. Cần lƣu ý kỹ các so sánh đối tƣợng dựa trên thuộc tính của chúng. Hãy định nghĩa một thao tác đƣợc đảm bảo sẽ có kết quả duy nhất cho từng đối tƣợng khác nhau (nhƣ gắn một ký hiệu đặc biệt cho chúng). Phƣơng pháp này có thể xuất phát từ bên ngoài hoặc là một định danh tạo bởi hệ thống, miễn sao nó đảm bảo đƣợc tính duy nhất trong model. Model cần định nghĩa sao cho hai đối tƣợng ở hai nơi là một. Các thực thể là những đối tƣợng rất quan trọng của domain model và việc mô hình hóa quá trình nên lƣu ý đến chúng ngay từ đầu. Việc xác định xem một đối tƣợng có phải là thực thể hay không cũng rất quan trọng. 2.2.2 Đối tƣợng giá trị Khi ta không quan tâm đó là đối tƣợng nào, mà chỉ quan tâm thuộc tính nó có. Một đối tƣợng mà đƣợc dùng để mô tả các khía cạnh cố định của một Domain và không có định danh, đƣợc gọi tên là Value Object.46 Vì những đặc điểm này nên ta cần phân biệt rõ Entity Object và Value Object. Để đảm bảo tính đồng nhất ta sẽ không gắn mọi đối tƣợng thành thực thể. Thay vào đó ta chỉ gắn thực thể cho những đối tƣợng nào phù hợp nhất với các đặc tính của thực thể. Các đối tƣợng còn lại sẽ là ValueObject. Điều này sẽ đơn giản hóa bản thiết kế và sẽ có các lợi ích về sau. Nhờ không có định danh, Value Object có thể đƣợc tạo và hủy dễ dàng. Lập trình viên không cần quan tâm tạo định danh. Điều này thực sự đơn giản hóa thiết kế rất nhiều. Một điểm quan trọng là Value Object thì không khả chuyển. Chúng đƣợc tạo bởi các hàm constructorvà không bao giờ đƣợc thay đổi trong vòng đời của mình. Khi bạn muốn đối tƣợngvới giá trị khác, bạn tạo một đối tƣợng mới chứ không thay đổi giá trị của đối tƣợng cũ. Điều này ảnh hƣởng rõ ràng tới thiết kế. Do không khả chuyển và không có định danh, Value Object có thể đƣợc dùng chung. Đó có thể là đòi hỏi cần thiết cho nhiều thiết kế. Các đối tƣợng không khả chuyển có thể chia sẻ là gợi ý tốt về hiệu năng. Chúng cũng thể hiện tính toàn vẹn, nhƣ toàn vẹn về dữ liệu. Tƣởng tƣợng việc chia sẻ các đối tƣợng khả chuyển. Ví dụ một trong các thuộc tính của đối tƣợng đó là mã chuyến bay. Một khách hàng đặt vé cho một điểm đến. Một khách hàng khác đặt chuyến bay tƣơng tự. Trong thời gian đó, ngƣời khách hàng thứ hai này đổi ý và chọn chuyến bay khác. Hệ thống khi đó đổi mã chuyến bay bởi vì mã chuyến bay "khả chuyển". Kết quả là mã chuyến bay của khách hàng đầu cũng bị đổi theo, dù không hề mong muốn. Quy luật vàng: nếu Value Object có thể đƣợc chia sẻ, thì nó phải không khả chuyển. Value Objectnên đƣợc thiết kế và duy trì đơn giản và mỏng. Khi một Value Object đƣợc truy xuất, ta có thể đơn giản là truyền giá trị, hoặc truyển một bản copy. Tạo một bản copy của một Value Object thì đơn giản và không tạo ra hệ quả gì. Và vì Value Object không có định danh, ta có thể tạo bao nhiêu bản copy cũng đƣợc và hủy các bản đó khi cần thiết. Value Object có thể chứa đựng các Value Object khác và nó thậm chí chứa đựng các tham chiếu tới các thực thể. Mặc dù Value Object đƣợc sử dụng đơn giản nhƣ chứa đựng các thuộc tính của một đối tƣợng Domain, nhƣng không có nghĩa là nó nên chứa đựng nhiều thuộc tính. Các47 thuộc tính nên đƣợc nhóm lại vào các đối tƣợng khác nhau. Các thuộc tính tạo nên một Value Object nên thuộc về một Value Object. Một khách hàng bao gồm họ tên, tên đƣờng phố, thành phố và bang. Và thông tin địa chỉ nên đƣợc đặt trong một đối tƣợng và đối tƣợng khách hàng sẽ chứa tham chiếu tới đối tƣợng địa chỉ đó. Tên đƣờng, thành phố, bang nên hình thành đối tƣợng Địa chỉ của riêng nó, vì chúng thuộc cùng khái niệm với nhau, thay vì đặt chúng là các thuộc tính rời của đối tƣợng Khách hàng, nhƣ hình vẽ dƣới đây. Hình 2- 4 Value Object 2.2.2 Dịch vụ Khi phân tích domain để xác định những đối tƣợng chính có trong mô hình ta sẽ gặp những thành phần không dễ để có thể gán chúng cho một đối tƣợng nhất định nào đó. Một đối tƣợngthông thƣờng đƣợc xem là sẽ có những thuộc tính - những trạng thái nội tại - đƣợc quản lý bởi đối tƣợng đó, ngoài ra đối tƣợng còn có những hành vi. Khi thiết lập Ngôn ngữ chung, các khái niệm chính của domain sẽ đƣợc thể hiện trong Ngôn ngữ chung này, các danh từ sẽ là các đối tƣợng, các động từ đi kèm với danh từ đó sẽ thành các hành vi của đối tƣợng. Tuy nhiên có một số hành vi trong domain, những động từ trong Ngôn ngữ chung, lại có vẻ không thuộc về một đối tƣợng nhất định nào cả. Chúng thể hiện cho những hành vi quan trọng trong domain nên cũng không thể bỏ qua chúng hoặc gắn vào các Thực thể hay Đối tƣợng giá trị. Việc thêm hành vi này vào một đối tƣợng sẽ làm mất ý nghĩa của đối tƣợng đó, gán cho chúng những chức năng vốn không thuộc về chúng. Dù sao đi nữa, vì ta đang sử dụng Lập trình hƣớng đối tƣợng nên ta vẫn cần phải có một đối tƣợng để chứa các hành vi này. Thông thƣờng hành vi này hoạt động trên nhiều đối48 tƣợng khác nhau, thậm chí là nhiều lớp đối tƣợng. Ví dụ nhƣ việc chuyển tiền từ một tài khoản này sang một tài khoản khác, chức năng này nên đặt ở tài khoản gửi hay tài khoản nhận? Trong trƣờng hợp này cả hai đều không phù hợp. Đối với những hành vi nhƣ vậy trong domain, các tốt nhất là khai báo chúng nhƣ là một Dịch vụ. Một Dịch vụ không có trạng thái nội tại và nhiệm vụ của nó đơn giản là cung cấp các chức năng cho domain. Dịch vụ có thể đóng một vai trò quan trọng trong domain, chúng có thể bao gồm các chức năng liên quan đến nhau để hỗ trợ cho các Thực thể và Đối tƣợng mang giá trị. Việc khai báo một Dịch vụ một cách tƣờng minh là một dấu hiệu tốt của một thiết kế cho domain, vì điều này giúp phân biệt rõ các chức năng trong domain đó, giúp tách biệt rạch ròi khái niệm. Sẽ rất khó hiểuvà nhập nhằng nếu gán các chức năng nhƣ vậy vào một Thực thể hay Đối tƣợng giá trị vì lúc đó ta sẽ không hiểu nhiệm vụ của các đối tƣợng này là gì nữa. Dịch vụ đóng vai trò là một interface cung cấp các hành động. Chúng thƣờng đƣợc sử dụng trong các framework lập trình, tuy nhiên chúng cũng có thể xuất hiện trong tầng domain. Khi nói về mộtdịch vụ ngƣời ta không quan tâm đến đối tƣợng thực hiện Dịch vụ đó, mà quan tâm tới những đối tƣợng đƣợc xử lý bởi dịch vụ. Theo cách hiểu này, Dịch vụ trở thành một điểm nối tiếp giữa nhiều đối tƣợng khác nhau. Đây chính là một lý do tại sao các Dịch vụ không nên tích hợp trong các đối tƣợng của domain. Làm nhƣ thế sẽ tạo ra các quan hệ giữa các đối tƣợng mang chức năng và đối tƣợng đƣợc xử lý, dẫn đến gắn kết chặt chẽ giữa chúng. Đây là dấu hiệu của một thiết kế không tốt, mã nguồn chƣơng trình sẽ trở nên rất khó đọc hiểu và quan trọng hơn là việc sửa đổi hành vi sẽ khó khăn hơn nhiều. Một Dịch vụ không nên bao gồm các thao tác vốn thuộc về các đối tƣợng của domain. Sẽ là không nên cứ có bất kỳ thao tác nào ta cũng tạo một Dịch vụ cho chúng. Chỉ khi một thao tác đóng một vai trò quan trọng trong domain ta mới cần tạo một Dịch vụ để thực hiện. Dịch vụ có ba đặc điểm chính: 1. Các thao tác của một Dịch vụ khó có thể gán cho một Thực thể hay Đối tƣợng giá trị nào 2. Các thao tác này tham chiếu đến các đối tƣợng khác của domain49 3. Thao tác này không mang trạng thái (stateless). Khi một quá trình hay sự biến đổi quan trọng trong domain không thuộc về một Thực thể hay Đối tƣợng giá trị nào, việc thêm thao tác này vào một đối tƣợng/giao tiếp riêng sẽ tạo ra một Dịch vụ.Định nghĩa giao tiếp này theo Ngôn ngữ chung của mô hình, tên của thao tác cũng phải đặt theomột khái niệm trong Ngôn ngữ chung, ngoài ra cần đảm bảo Dịch vụ không chứa trạng thái. Khi sử dụng Dịch vụ cần đảm bảo tầng domain đƣợc cách ly với các tầng khác. Sẽ rất dễ nhầm lẫn giữa các dịch vụ thuộc tầng domain và thuộc các tầng khác nhƣ infrastructure hay application nênta cần cẩn thận giữ sự tách biệt của tầng domain. Thông thƣờng Dịch vụ của các tầng domain và application đƣợc viết dựa trên các Thực thể và Đối tƣợng giá trị nằm trong tầng domain, cung cấp thêm chức năng liên quan trực tiếp tới các đối tƣợng này. Để xác định xem một Dịch vụ thuộc về tầng nào không phải dễ dàng. Thông thƣờng nếu Dịch vụ cung cấp các chức năng liên quan tới tầng application ví dụ nhƣ chuyển đổi đối tƣợng sang JSON, XML thì chúng nên nằm ở tầng này. Ngƣợc lại nếu nhƣ chức năng của Dịch vụ liên quan tới tầng domain và chỉ riêng tầng domain, cung cấp các chức năng mà tầng domain cần thì Dịch vụ đó thuộc về tầng domain. Hãy xem xét một ví dụ thực tế: một chƣơng trình báo cáo trên web. Các báo cáo sử dụng các dữ liệu lƣu trong CSDL và đƣợc sinh ra theo các mẫu có sẵn (template). Kết quả sau cùng là mộttrang HTML để hiển thị trên trình duyệt của ngƣời dùng. Tầng UI nằm trong các trang web và cho phép ngƣời dùng có thể đăng nhập, lựa chọn các báo cáo họ cần và yêu cầu hiển thị. Tầng application là một tầng rất mỏng nằm giữa giao diện ngƣời dùng, tầng domain và tầng infrastructure. Tầng này tƣơng tác với CSDL khi đăng nhập và với tầng domain khi cần tạo báo cáo. Tầng domain chứa các logic nghiệp vụ của domain, các đối tƣợng trực tiếp liên quan tới báo cáo. Hai trong số chúng là Report và Template, đó là những lớp đối tƣợng để tạo báo cáo. Tầng Infrastructure sẽ hỗ trợ truy vấn CSDL và file.50 Khi cần một báo cáo, ngƣời dùng sẽ lựa chọn tên của báo cáo đó trong một danh sách các tên. Đây là reportID, một chuỗi. Một số các tham số khác cũng sẽ đƣợc truyền xuống, nhƣ các mục có trong báo cáo, khoảng thời gian báo cáo. Để đơn giản ta sẽ chỉ quan tâm đến reportID, tham số này sẽ đƣợc truyền xuống từ tầng application xuống tầng domain. Tầng domain giữ trách nhiệm tạo và trả về báo cáo theo tên đƣợc yêu cầu. Vì các báo cáo đƣợc sinh ra dựa trên các mẫu, chúngta có thể sử dụng một Dịch vụ ở đây với nhiệm vụ lấy mẫu báo cáo tƣơng ứng với reportID. Mẫu này có thể đƣợc lƣu trong file hoặc trong CSDL. Sẽ không hợp lý lắm nếu nhƣ thao tác này nằm trong đối tƣợng Report hay Template. Và vì thế nên ta sẽ tạo ra một Dịch vụ riêng biệt với nhiệm vụ lấy về mẫu báo cáo dựa theo ID của báo cáo đó. Dịch vụ này sẽ đƣợc đặt ở tầng domainvà sử dụng chức năng truy xuất file dƣới tầng infrastructure để lấy về mẫu báo cáo đƣợc lƣu trên đĩa. 2.2.3 Mô-đun Với hệ thống lớn và phức tạp, mô hình thƣờng có xu hƣớng phình càng ngày càng to. Khi mô hình phình tới một điểm ta khó nắm bắt đƣợc tổng thể, việc hiểu quan hệ và tƣơng tác giữa các phần khác nhau trở nên khó khăn. Vì lý do đó, việc tổ chức mô hình thành các mô-đun là cần thiết. Mô-đun đƣợc dùng nhƣ một phƣơng pháp để tổ chức các khái niệm và tác vụ liên quan nhằm giảm độ phức tạp. Mô-đun đƣợc dùng rộng rãi trong hầu hết các dự án. Sẽ dễ dàng hơn để hình dung mô hình lớn nếu ta nhìn vào những mô-đun chứa trong mô hình đó, sau đó là quan hệ giữa các mô-đun. Khi đã hiểu tƣơng tác giữa các mô-đun, ta có thể bắt đầu tìm hiểu phần chi tiết trong từng mô-đun. Đây là cách đơn giản và hiệu quả để quản lý sự phức tạp. Một lý do khác cho việc dùng mô-đun liên quan tới chất lƣợng mã nguồn. Thực tế đƣợc chấp nhận rộng rãi là, phần mềm cần có độ tƣơng liên cao và độ liên quan thấp. Sự tƣơng liên bắt đầu từ mức lớp (class) và phƣơng thức (method) và cũng có thể áp dụng ở mức mô-đun. Ta nên nhóm những lớp có mức độ liên quan cao thành một mô-đun để đạt đƣợc tính tƣơng liên cao nhất có thể. Có nhiều loại tƣơng liên. Hai loại tƣơng liên hay dùng nhất là tƣơng liên giao tiếp và tƣơng51 liênchức năng. Tƣơng liên giao tiếp có đƣợc khi hai phần của mô-đun thao tác trên cùng dữ liệu. Nó có ý nghĩa là nhóm chúng lại vì giữa chúng có quan hệ mạnh. Tƣơng liên chức năng có đƣợc khi mọi phần của mô-đun làm việc cùng nhau để thực hiện một tác vụ đã đƣợc định nghĩa rõ. Loại này đƣợc coi là tƣơng liên tốt nhất. Sử dụng mô-đun trong thiết kế là cách để tăng tính tƣơng liên là giảm tính liên kết. Mô-đun cầnđƣợc tạo nên bởi những thành phần thuộc về cùng một tƣơng liên có tính chức năng hay logic. Mô-đun cần có giao diện đƣợc định nghĩa rõ để giao tiếp với các mô-đun khác. Thay vì gọi ba đối tƣợng của một mô-đun, sẽ tốt hơn nếu truy cập chúng qua một giao diện để giảm tính liên kết.Tính liên kết thấp làm giảm độ phức tạp và tăng khả năng duy trì. Việc hiểu cách hệ thống hoạt động sẽ dễ hơn khi có ít kết nối giữa các mô-đun thực hiện những tác vụ đã đƣợc định nghĩa rõ hơn là việc mọi mô-đun có rất nhiều kết nối với các mô-đun khác. Việc chọn mô-đun nói lên câu chuyện của hệ thống và chứa tập có tính tƣơng liên của các khái niệm. Điều này thƣờng thu đƣợc bằng tính liên kết thấp giữa các mô-đun, nhƣng nếu không nhìn vào cách mô hình ảnh hƣởng tới các khái niệm, hoặc nhìn quá sâu vào vào những khái niệm có thể trở thành phần cơ bản của mô-đun có thể sẽ tìm ra những cách thức có ý nghĩa. Tìm ra sự liên kết thấp theo cách mà các khái niệm đƣợc hiểu và lý giải một cách độc lập với nhau. Làm mịn mô hình này cho tới khi các phần riêng rẽ tƣơng ứng với khái niệm domain ở mức cao và mã nguồn tƣơng ứng đƣợc phân rã thật tốt. Hãy đặt tên mô-đun và lấy tên mô-đun đó là một phần của Ngôn ngữ Chung. Mô-đun và tên của nó cần thể hiện ý nghĩa sâu xa của domain. Ngƣời thiết kế thƣờng quen với việc tạo thiết kế ngay từ đầu. Và nó thƣờng trở thành một phần của thiết kế. Sau khi vai trò của mô-đun đƣợc quyết định, nó thƣờng ít thay đổi trong khi phần trong của mô-đun thì thƣờng xuyên thay đổi. Ngƣời ta khuyến nghị rằng nên có sự linh hoạt ở mức độ nào đó, cho phép mô-đun đƣợc tiến hóa trong dự án chứ không giữ nguyên nó cố định. Thực tế là việc refactor một mô-đun thƣờng tốn kém hơn việc refactor một lớp (class), nhƣng khi ta52 phát hiện lỗi trong thiết kế, tốt nhất là nên chỉ ra sự thay đổi của mô-đun và tìm ra phƣơng án giải quyết. 2.3. Các mô hình trong chiến lƣợc thiết kế phần mềm hƣớng lĩnh vực Các khuôn mẫu quan trọng nhất đƣợc sử dụng trong DDD. Mục đích của những khuôn mẫu này là để trình bày một số yếu tố chính của mô hình hóa hƣớng đối tƣợng và thiết kế phần mềm từ quan điểm của DDD. Sơ đồ sau đây là một biểu đồ của các khuôn mẫu sẽ đƣợc trình bày và các mối quan hệ giữa chúng. Hình 2- 5 Những mẫu sử dụng trong DDD Các phần trƣớc đã nhấn mạnh tầm quan trọng của cách tiếp cận tới quy trình phát triển phần mềm tập trung vào lĩnh vực nghiệp vụ. Ta đã biết nó có ý nghĩa then chốt để tạo ra một model cógốc rễ là domain. Ngôn ngữ chung nên đƣợc thực hiện đầy đủ trong suốt quá trình mô hình hóa nhằm thúc đẩy giao tiếp giữa các chuyên gia phần mềm với chuyên gia domainvà khám phá ra các khái niệm chính của domain nên đƣợc sử dụng trong model. Mục đích của quá trình mô hình hóa là nhằm tạo ra một model tốt. Bƣớc tiếp theo là hiện thực nó trong code. Đây là một giai đoạn quan trọng không kém của quá trình phát triển phần mềm. Sau khi tạo ra một mô hình tuyệt vời, nhƣng không chuyển thể chúng thành code đúng cách thì sẽ chỉ kết thúc bằng phần mềm có vấn đề về chất lƣợng.53 2.3.1 Aggregates and Aggregate Roots Khi quản lý vòng đời của các đối tƣợng trong domain. Trong suốt vòng đời của mình các đối tƣợng trải qua những trạng thái khác nhau, chúng đƣợc tạo ra, lƣu trong bộ nhớ, sử dụng trong tính toán và bị hủy. Một số đối tƣợng sẽ đƣợc lƣu vào trong hệ thống lƣu giữ ngoài nhƣ CSDL để có thể đọc ra sau này, hoặc chỉ để lƣu trữ. Một số thời điểm khác chúng có thể sẽ đƣợc xóa hoàn toàn khỏi hệ thống, kể cả trong CSDL cũng nhƣ lƣu trữ ngoài. Việc quản lý vòng đời các đối tƣợng trong domain không hề đơn giản, nếu nhƣ làm không đúng sẽ có thể gây ảnh hƣởng đến việc mô hình hóa domain. Sau đây ta sẽ đề cập đến ba mẫu (pattern)thƣờng dùng để hỗ trợ giải quyết vấn đề này. Aggregate (tập hợp) là pattern để định nghĩa việc sở hữu đối tƣợng và phân cách giữa chúng. Factory và Repository là hai pattern khác giúp quản lý việc tạo và lƣu trữ đối tƣợng. Trƣớc hết ta sẽ nói đến Aggregate. Một mô hình có thể đƣợc tạo thành từ nhiều đối tƣợng trong domain. Cho dù có cẩn thận trong việc thiết kế nhƣ thế nào thì ta cũng không thể tránh đƣợc việc sẽ có nhiều mối quan hệ chằng chịt giữa các đối tƣợng, tạo thành một lƣới các quan hệ. Có thể có nhiều kiểu quan hệ khác nhau, với mỗi kiểu quan hệ giữa các mô hình cần có một cơ chế phần mềm để thực thi nó. Các mối quan hệ sẽ đƣợc thể hiện trong mã nguồn phần mềm và trong nhiều trƣờng hợp trong cả CSDL nữa. Quan hệ một-một giữa khách hàng và một tài khoản ngân hàng của anh ta sẽ đƣợc thể hiện nhƣ là một tham chiếu giữa hai đối tƣợng, hay một mối quan hệ giữa hai bảng trong CSDL, một bảng chứa khách hàng và một bảng chứa tài khoản. Những khó khăn trong việc mô hình hóa không chỉ là đảm bảo cho chúng chứa đầy đủ thông tin, mà còn làm sao để cho chúng đơn giản và dễ hiểu nhất có thể. Trong hầu hết trƣờng hợp việc bỏ bớt các quan hệ hay đơn giản hóa chúng sẽ đem lại lợi ích cho việc quản lý dự án. Tất nhiên là trừ trƣờng hợp những mối quan hệ này quan trọng trong việc hiểu domain. Mối quan hệ một-nhiều có độ phức tạp hơn so với mối quan hệ một-một vì có liên quan đến nhiều đối tƣợng một lúc. Mối quan hệ này có thể đƣợc đơn giản hóa bằng cách biến đổi thành mối quan hệ giữa một đối tƣợng và một tập hợp các54 đối tƣợng khác, tuy nhiên không phải lúc nào cũng có thể thực hiện đƣợc điều này. Ngoài ra còn có mối quan hệ nhiều-nhiều và phần lớn trong số chúng là mối quan hệ qua lại. Điều này khiến cho độ phức tạp tăng lên rất nhiều và việc quản lý vòng đời của các đối tƣợng trong mốiquan hệ rất khó khăn. Số quan hệ nên đƣợc tối giản càng nhỏ càng tốt. Trƣớc hết, những mối quan hệ không phải là tối quan trọng cho mô hình nên đƣợc loại bỏ. Chúng có thể tồn tại trong domain nhƣng nếu nhƣ không cần thiết trong mô hình thì nên bỏ chúng. Thứ hai, để hạn chế việc tăng số lƣợng quan hệ theo theo cấp số nhân, ta nên sử dụng các ràng buộc. Nếu có rất nhiều các đối tƣợng thỏa mãn một mối quan hệ, có thể chỉ cần một đối tƣợng trong số đó nếu nhƣ ta đặt một ràng buộc lên mối quan hệ. Thứ ba, trong nhiều trƣờng hợp những mối quan hệ qua lại có thể đƣợc chuyển thành những mối quan hệ một chiều. Mỗi chiếc xe đều có động cơ và mỗi động cơ đều thuộc về một chiếc xe. Đây là một mối quan hệ qua lại, tuy nhiên ta có thể giản lƣợc nó nếu nhƣ chỉ cần biết mỗi chiếc xe đều có một động cơ. Sau khi ta đã tối giản và đơn giản hóa các mối quan hệ giữa các đói tƣợng, có thể sẽ vẫn còn rất nhiều các mối quan hệ còn lại. Lấy ví dụ một hệ thống ngân hàng lƣu giữ và xử lý thông tin của khách hàng. Những dữ liệu này bao gồm các thông tin cá nhân của khách hàng nhƣ tên, địa chỉ, số điện thoại, nghề nghiệp và thông tin tài khoản: số tài khoản, số dƣ, các thao tác đã thực hiện. Khi hệ thống lƣu trữ hoặc xóa hoàn toàn thông tin của một khách hàng thì nó cần đảm bảo rằng tất cả các tham chiếu đã đƣợc loại bỏ. Nếu nhƣ có nhiều các đối tƣợng lƣu trữ các tham chiếu nhƣ vậy thì việc trên là rất khó khăn. Ngoài ra nữa, khi thay đổi thông tin của một khách hàng, hệ thống cần đảm bảo rằng dữ liệu đã đƣợc cập nhật trong toàn bộ hệ thống và tính toàn vẹn dữ liệu không bịxâm phạm. Thông thƣờng yêu cầu này đƣợc đảm bảm ở dƣới tầng CSDL bằng các Giao dịch. Tuy nhiên nếu nhƣ mô hình không đƣợc thiết kế cẩn thận thì có thể sẽ gây ra nghẽn ở tầng CSDL gây suy giảm hiệu năng hệ thống. Mặc dù các giao dịch đóng vai trò rất quan trọng trong CSDL, việc quản lý tính toàn vẹn dữ liệu trực tiếp trong mô hình sẽ đem lại nhiều lợi ích. Ngoài tính toàn vẹn dữ liệu, ta cũng cần đảm bảo các invariant của dữ liệu. Các Invariant là những luật, ràng buộc yêu cầu phải đƣợc thỏa mãn mỗi khi dữ liệu thay55 đổi. Điều này rất khó thực hiện khi có nhiều đối tƣợng cùng lƣu tham chiếu để sửa đổi dữ liệu.Việc đảm bảo tính thống nhất sau các thay đổi của một đối tƣợng có nhiều mối quan hệ không phải là dễ dàng. Các Invariant không chỉ ảnh hƣởng đến từng đối tƣợng riêng rẽ mà thƣờng là tập hợp các đối tƣợng. Nếu ta sử dụng khóa quá mức sẽ khiến cho các thao tác chồng chéo lên nhau và hệ thống không thể sử dụng đƣợc. Do vậy, ta cần sử dụng Aggregate. Một Aggregate là một nhóm các đối tƣợng, nhóm này có thể đƣợc xem nhƣ là một đơn vị thống nhất đối với các thay đổi dữ liệu. Vậy bằng cách nào mà Aggregate có thể đảm bảo đƣợc tính toàn vẹn và các ràng buộc của dữ liệu? Vì các đối tƣợng khác chỉ có thể tham chiếu đến gốc của Aggregate, chúng không thể thay đổi trực tiếp đến các đối tƣợng nằm bên trong mà chỉ có thể thay đổi thông qua gốc, hoặc là thay đổi gốc Aggregate trực tiếp. Tất cả các thay đổi của Aggregate sẽ thực hiện thông qua gốc của chúng và ta có thể quản lý đƣợc những thay đổi này, so với khi thiết kế cho phép các đối tƣợng bên ngoài truy cập trực tiếp vào các đối tƣợng bên trong thì việc đảm bảo các invariant sẽ đơn giản hơn nhiều khi ta phải thêm các logic vào các đối tƣợng ở ngoài để thực hiện. Nếu nhƣ gốc của Aggregate bị xóa và loại bỏ khỏi bộ nhớ thì những đối tƣợng khác trong Aggregate cũng sẽ bị xóa, vì không còn đối tƣợng nào chứa tham chiếu đến chúng. Nhƣng việc chỉ cho phép truy cập thông qua gốc không có nghĩa là ta không đƣợc phép cấp các tham chiếu tạm thời của các đối tƣợng nội tại trong aggregate cho các đối tƣợng bên ngoài, miễn là các tham chiếu này đƣợc xóa ngay sau khi thao tác hoàn thành. Một trong những cách thực hiện điều này là sao chép các Value Hình 2- 6 Aggregate root56 Object cho các đối tƣợng ngoài. Việc thay đổi các đối tƣợng này sẽ không gây ảnh hƣởng gì đến tính toàn vẹn của aggregate cả.Nếu nhƣ các đối tƣợng của Aggregate đƣợc lƣu trong CSDL thì chỉ nên cho phép truy vấn trựctiếp lấy gốc của aggregate, các đối tƣợng nội tại còn lại nên đƣợc truy cập thông qua các mối quanhệ bên trong.Các đối tƣợng nội tại của Aggregate có thể lƣu tham chiếu đến gốc của các Aggregate khác. Thực thể gốc có một định danh trong toàn hệ thống và giữ trách nhiệm đảm bảo các ràng buộc.Các thực thể bên trong có định danh nội bộ. Gộp các Thực thể và các Value Object thành những Aggregate và tạo các đƣờng biên giữa chúng. Lựa chọn một Thực thể làm gốc cho một Aggregate và quản lý truy cập tới các đối tƣợng trong đƣờng biên thông qua gốc. Chỉ cho phép các đối tƣợng bên ngoài lƣu tham chiếu đến gốc. Các tham chiếu tạm thời tới các đối tƣợng nội bộ có thể đƣợc chép ra ngoài để sử dụng cho từng thao tác một. Vì gốc quản lý truy cập nên gốc phải biết đến mọi thay đổi nội tại của Aggregate. Cách thiết kế này giúp đảm bảo các ràng buộc trên các đối tƣợng của Aggregate cũng nhƣ toàn bộ Aggregate. Dƣới đây là một sơ đồ của một ví dụ cho Aggregate. Đối tƣợng khách hàng là gốc của Aggregate, các đối tƣợng khác là nội tại. Nếu nhƣ một đối tƣợng bên ngoài cần địa chỉ thì có thể cho thamchiếu tới một bản sao của đối tƣợng này. 2.3.2 Factory Các Thực thể và đối tƣợng tập hợp có thể lớn và phức tạp - quá phức tạp để tạo trong constructor của thực thể gốc (root entity). Trong thực tế, việc cố gắng tạo ra một Aggregate phức tạp trong hàm constructor là trái với những gì thƣờng xảy ra về mặt domain, nơi mà những thứ thƣờng đƣợc tạo ra bởi thứ khác (nhƣ các57 thiết bị điện tử tạo từ các vi mạch). Nó giống nhƣ việc có chiếc máy in lại tự tạo ra nó vậy. Khi một đối tƣợng khách thể muốn tạo ra đối tƣợng khác, nó gọi hàm khởi tạo của nó và có thể truyền thêm một vài tham số. Nhƣng khi việc tạo đối tƣợng là một quá trình mệt nhọc, tạo ra đối tƣợng liên quan đến nhiều kiến thức về cấu trúc bên trong của đối tƣợng, về mối quan hệ giữa các đối tƣợng trong nó và các luật (rule) cho chúng. Điều này có nghĩa là mỗi đối tƣợng khách thể sẽ nắm giữ hiểu biết riêng về các đối tƣợng đƣợc sinh ra. Điều này phá vỡ sự đóng gói của đối tƣợng nghiệp vụ và của các Aggregate. Nếu các khách thể thuộc về tầng ứng dụng, một phần của tầng nghiệp vụ đƣợc chuyển ra ngoài, làm toàn bộ thiết kế bị lộn xộn. Trong cuộc sống thực, giống nhƣ việc ta đƣợc cung cấp nhựa, cao su, kim loại và ta phải tự làm cái máy in. Điều đó thì không phải là không thể, nhƣng nó có thực sự đáng để làm? Bản thân việc tạo một đối tƣợng có thể là thao tác chính của chính nó, nhƣng những thao tác lắp ráp phức tạp không hợp với trách nhiệm của đối tƣợng đƣợc tạo ra. Việc tổ hợp những trách nhiệm ấy có thể tạo nên những thiết kế vụng về khó hiểu. Do đó, ta cần đƣa ra một khái niệm mới. Khái niệm này giúp việc gộp quy trình tạo ra đối tƣợng phức tạp và đƣợc gọi là Factory. Factory đƣợc dùng để gộp kiến thức cần cho việc tạo đối tƣợng và chúng đặc biệt hữu dụng cho Aggregate. Khi gốc của Aggregate đƣợc tạo ra, mọi đối tƣợng chứa trong Aggregate đó cũng đƣợc tạo ra cùng cùng những yếu tố bất biến. Điều quan trọng là quá trình tạo ra (Factory) là atomic. Nếu kết quả tạo ra không phải là atomic thì có khả năng là quá trình sẽ chỉ tạo ra một số đối tƣợng nửa vời và chúng ở trạng thái không đƣợc định nghĩa. Điều này càng đúng hơn với Aggregate. Khi root đƣợc tạo ra, điều cần thiết là mọi đối tƣợng phải là bất biến cũng đƣợc tạo ra. Nếu không, những bất biến này không thể đƣợc đảm bảo.Với Đối tƣợng Giá trị bất biến, điều này nghĩa là mọi thuộc tính đƣợc khởi tạo với trạng thái hợp lệ của chúng. Nếu một đối tƣợng không thể đƣợc tạo ra một cách đúng đắn thì cần phải sinh rangoại lệ và trả về giá trị không hợp lệ.Do đó, hãy58 chuyển trách nhiệm của việc tạo instance cho đối tƣợng phức tạp và Aggregate tới một đối tƣợng riêng. Bản thân đối tƣợng này có thể không có trách nhiệm đối với mô hình domain nhƣng vẫn là một phần của thiết kế domain. Hãy cung cấp interface gộp mọi phần rời rạc phức tạp và không yêu cầu client phải tham chiếm tới những lớp cụ thể của đối tƣợng đang đƣợc khởi tạo. Tạo toàn bộ Aggregate nhƣ là một đơn vị, đảm bảo những yếu tốt bất biến của nó. Có nhiều design pattern có thể dùng để thực thi Factory. Có thể chia pattern này thành 2 loại Factory Phƣơng pháp và Factory Trừu tƣợng. Ta không thể hiện những pattern này dƣới góc độ thiết kế mà thể hiện chúng từ mô hình domain. Một Factory Phƣơng pháp là một phƣơng pháp đối tƣợng chứa và ẩn kiến thức cần thiết để tạo ra một đối tƣợng khác. Điều này rất hữu dụng khi client muốn tạo một đối tƣợng thuộc về một Aggregate. Giải pháp là thêm một method tới gốc của Aggregate. Method này sẽ đảm nhiệm việc tạo ra đối tƣợng, đảm bảo mọi điều kiện bất biến, trả về một tham chiếu tới đối tƣợng đó hoặc một bản copy tới nó. Hình 2- 7 Factory Container chứa các thành phần và chúng thuộc một loại nào đó. Khi một thành phần đƣợc tạo ra,nó cần đƣợc tự động thuộc về một container. Việc này là cần thiết. Client gọi methodcreateComponent(Type t) của container. Container khởi tạo một thành phần mới. Lớp cụ thể củathành phần này đƣợc xác định dựa trên loại của nó. Sau khi việc tạo thành công, thành phần đƣợc thêm vào tập các thành phần đƣợc chứa bởi container đó và trả về một copy cho client. Với nhiều trƣờng hợp, khi việc xây dựng một đối tƣợng phức tạp hơn, hoặc khi việc tạo đối tƣợng liên quan đến việc tạo một chuỗi các đối tƣợng. Ví dụ: việc tạo một Aggregate. Việc cần nhu cầu tạo nội bộ của một Aggregate có thể đƣợc59 thực hiện trong một đối tƣợng Factory riêng dành riêng cho tác vụ này. Hãy xem ví dụ với mô-đun chƣơng trình tính route có thể phải chạy qua của một ôtô từ điểm khởi hành tới điểm đích với một chuỗi các ràng buộc. Ngƣời dùng đăng nhập vào sitechạy chƣơng trình và chỉ định ràng buộc: route nhanh nhất, route rẻ nhất. Route đƣợc ta có thể đƣợc chú thích bởi thông tin ngƣời dùng cần đƣợc lƣu để họ có thể tham chiếu lại khi đăng nhập lần sau. Hình 3- 4 Factory Bộ sinh Route ID đƣợc dùng để tạo định danh duy nhất cho mỗi route, cái mà cần thiết cho một Thực Thể. Khi tạo ra một Factory, ta buộc phải vi phạm tính đóng gói của đối tƣợng - là cái cần phải đƣợc thực hiện cẩn thận. Bất cứ khi nào một thứ gì đó thay đổi trong đối tƣợng có ảnh hƣởng đến quy tắc khởi dựng hoặc trên một số invariant, ta cần chắc chắn rằng Factory cũng đƣợc cập nhật để hỗ trợ điều kiện mới. Các Factory có liên quan chặt chẽ đến các đối tƣợng mà chúng tạo ra. Đó là một điểm yếu, nhƣng cũng có thể là một điểm mạnh. Một Aggregate chứa một loạt các đối tƣợng có liên quan chặt chẽ với nhau. Sự khởi dựng của gốc liên quan tới việc tạo ra các đối tƣợng khác nằm trong Aggregate. Đến đây đã có vài logic đƣợc đặt vào cùng nhau trong một Aggregate. Logic vốn không thuộc về bất kỳ đối tƣợng nào, vì chúng nói về sự khởi dựng của các đối tƣợng khác. Nó có vẻ để dùng cho một Factory đặc biệt đƣợc giao nhiệm vụ tạo ra toàn bộ Aggregatevà nó sẽ chứa các quy tắc, ràng buộc với invariant mà buộc phải thực hiện cho Aggregate trở nên đúng đắn. Các đối tƣợng sẽ đƣợc giữ đơn giản và sẽ chỉ phục vụ mục đích cụ thể của chúng mà bỏ qua sự lộn xộn của logic khởi dựng phức tạp.60 Factory cho Thực Thể và Factory cho Value Object là khác nhau. Giá trị của các đối tƣợng thƣờng không thay đổivà tất cả các thuộc tính cần thiết phải đƣợc sinh ra tại thời điểm khởi tạo. Khi đối tƣợng đã đƣợc tạo ra, nó phải đúng đắn và là final. Nó sẽ không thay đổi. Các Thực Thể thì không bất biến. Chúng có thể đƣợc thay đổi sau này, bằng cách thiết lập một vài thuộc tính với việc đề cập đến tất cả các invariant mà cần đƣợc tôn trọng. Sự khác biệt khác đến từ thực tế rằng Entitycần đƣợc định danh, trong khi Value Object thì không. Đây là khi Factory không thực sự cần thiết và một constructor đơn giản là đủ. Sử dụng một constructor khi: 1. Việc khởi tạo không quá phức tạp 2. Việc tạo ra một đối tƣợng không liên quan đến việc tạo ra các đối tƣợng khácvà toàn bộ thuộc tính cần thiết đƣợc truyền thông qua constructor 3. Client quan tâm đến việc cài đặt. Có thể dùng Strategy 4. Class là một loại. Không có sự phân cấp liên quan, vì vậy không cần phải lựa chọn giữa một danh sách triển khai cụ thể. Một quan sát khác là Factory cần phải tạo ra các đối tƣợng từ đầu, hoặc phải đƣợc yêu cầu đề hoàn nguyên đối tƣợng đã tồn tại trƣớc đó, có thể trong CSDL. Đƣa các Thực Thể trở lại bộ nhớ từ nơi lƣu trữ của chúng tại CSDL có liên quan đến một quá trình hoàn toàn khác so với việc tạo ra một cái mới. Một sự khác biệt rõ ràng là các đối tƣợng mới không cần một định danh mới. Chúng đã có một cái. Sự vi phạm của invariant đƣợc xử lý khác nhau. Khi một đối tƣợng mới đƣợc tạo ra từ đầu, mọi vi phạm của invariant đều kết thúc trong một ngoại lệ. Ta không thử thực hiện việc này với đối tƣợng đƣợc tái tạo từ CSDL. Các đối tƣợng cần phải đƣợc sửa chữa bằng cách nào đó,để chúng có thể hữu dụng, bằng không sẽ có mất mát dữ liệu. 2.3.3. Repository Trong thiết kế hƣớng lĩnh vực, đối tƣợng có một vòng đời bắt đầu từ khi khởi tạo và kết thúc khi chúng bị xóa hoặc lƣu trữ. Một constructor hoặc một Factory sẽ lo việc khởi tạo đối tƣợng. Toàn bộ mục đích của việc tạo ra các đối tƣợng là sử dụng chúng. Trong một ngôn ngữ hƣớng đối tƣợng, ngƣời ta phải giữ một tham61 chiếu đến một đối tƣợng để có thể sử dụng nó. Để có một tham chiếu nhƣ vậy, client hoặc là phải tạo ra các đối tƣợng hoặc có đƣợc nó từ nơi khác, bằng cách duyệt qua các liên kết đã có. Ví dụ nhƣ, để có đƣợc một Value Object của một Aggregate, client cần yêu cầu nó từ gốc của Aggregate. Vấn đề là bây giờ client cần có một tham chiếu tới Aggregate root. Đối với các ứng dụng lớn, điều này trở thành một vấn đề vì ngƣời ta phải đảm bảo client luôn luôn có một tham chiếu đến đối tƣợng cần thiết, hoặc tới chỗ nào có tham chiếu tới đối tƣợng tƣơng ứng. Sử dụng một quy định nhƣ vậy trong thiết kế sẽ buộc các đối tƣợng giữ một loạt các tham chiếu mà có thể nó không cần. Nó tăng các ghép nối, tạo một loạt các liên kết không thực sự cần thiết. Để sử dụng một đối tƣợng, đối tƣợng đó cần đƣợc tạo ra trƣớc. Nếu đối tƣợng đó là root của một Aggregate, thì nó phải là một Thực thể và rất có thể là nó sẽ đƣợc lƣu trữ trong CSDL hoặc mộtdạng lƣu trữ khác. Nếu nó là Value Object, nó có thể lấy đƣợc từ Thực thể bằng cách duyệt từ một liên kết. Nó chỉ ra rằng một thỏa thuận tuyệt vời của các đối tƣợng có thể đƣợc lấy trực tiếp từCSDL. Nó giải quyết vấn đề của việc lấy tham chiếu của đối tƣợng. Khi client muốn sử dụng một đối tƣợng, chúng truy cập CSDL, lấy đối tƣợng từ đó và dùng chúng. Đó dƣờng nhƣ là giải pháp đơn giản và nhanh nhất, tuy nhiên nó có tác động tiêu cự đến thiết kế.CSDL là một phần của lớp hạ tầng. Một giải pháp bần cùng là cho client nhận biết chi tiết cách cần thiết để truy cập CSDL. Ví dụ nhƣ, client có thể tạo truy vấn SQL để lấy những dữ liệu cần thiết. Câu truy vấn dữ liệu có thể trả về một bộ bản ghi, thậm chí phơi bày các chi tiết bên trong nó. Khi nhiều client có thể tạo đối tƣợng trực tiếp từ CSDL, nó chỉ ra rằng code nhƣ vậy sẽ đƣợc nằm rải rác khắp toàn bộ domain. Vào thời điểm đó các domain model sẽ trở nên bị tổn thƣơng.Nó sẽ phải xử lý rất nhiều chi tiết của tầng infrastructure thay vì chỉ làm việc với các khái niệm domain. Điều gì sẽ xảy ra nếu một quyết định tạo ra để thay đổi CSDL bên dƣới? Tất cả các code nằm rải rác cần đƣợc thay đổi để có thể truy cập hệ thống lƣu trữ mới. Khi client truy cập CSDLtrực tiếp, nó có thể sẽ khôi phục một đối tƣợng nằm trong một Aggregate. Nó phá vỡ sự đóng gói của Aggregate với một hậu quả không lƣờng trƣớc.Một client cần một công cụ thiết thực thu thập tham chiếu tới đối tƣợng62 domain có từ trƣớc. Nếu lớp infrastructure làm cho nó dễ dàng để làm nhƣ vậy, các lập trình viên của phía client có thểthêm nhiều liên kết có thể duyệt hơn, làm lộn xộn model. Mặt khác, họ có thể sử dụng các truy vấnđể lấy dữ liệu chính xác mà họ cần từ các CSDL, hoặc lấy một vài đối tƣợng riêng biệt hơn là phải qua các Aggregate root. Nghiệp vụ domain chuyển vào trong truy vấn và code phía client, Thực thể cùng Value Object trở thành các thùng chứa dữ liệu đơn thuần. Sự phức tạp kỹ thuần túy của việc áp dụng hầu hết việc truy cập CSDL vào lớp Hạ tầng sẽ làm mã client phình to, dẫn các lập trình viên tới việc giảm chất lƣợng tầng domain, khiến cho model không còn thích hợp. Ảnh hƣởng chung là việc tập trung vào domain bị mất đi và thiết kế bị tổn hại. Vì thế, ta sử dụng một Repository, mục đích của nó là để đóng gói tất cả các logic cần thiết để thu đƣợc các tham chiếu đối tƣợng. Các đối tƣợng domain sẽ không cần phải xử lý với infrastructuređể lấy những tham chiếu cần thiết tới các đối tƣợng khác của domain. Chúng sẽ chỉ lấy nó từ Repository và model lấy lại đƣợc sự rõ ràng và tập trung. Repository có thể lƣu trữ các tham chiếu tới một vài đối tƣợng. Khi một đối tƣợng đƣợc khởi tạo,nó có thể đƣợc lƣu lại trong Repository và đƣợc lấy ra từ đây để có thể sử dụng sau này. Nếu phía client yêu cầu đối tƣợng từ Repository và Repository không chứa chúng, nó có thể sẽ đƣợc lấy từ bộ nhớ. Dù bằng cách nào, các Repository hoạt động nhƣ một nơi lƣu trữ các đối tƣợng cho việc truy xuất đối tƣợng toàn cục. Repository có thể cũng chứa một Strategy. Nó có thể truy cập một bộ nhớ lƣu trữ hoặc cách khác dựa trên Strategy chỉ định. Nó cũng có thể sử dụng các loại bộ nhớ khác nhau cho các loại khácnhau của các đối tƣợng. Hiệu quả chung là đối tƣợng domain đƣợc tách rời khỏi các nhu cầu lƣutrữ đối tƣợng và các tham chiếu của chúng và truy cập lƣu trữ phía dƣới tầng infrastructure.63 Hình 2- 8 Repository Với mỗi loại đối tƣợng cần thiết để truy cập toàn cục, tạo một đối tƣợng có thể cung cấp một tập hợp trong bộ nhớ ảo của tất cả các đối tƣợng trong các loại đó. Cài đặt truy cập thông qua một Interface đƣợc biết ở mức toàn cục. Cung cấp các phƣơng thức để thêm hoặc xóa đối tƣợng, nhằm đóng gói việc thêm và xóa thật sự của dữ liệu trong bộ lƣu trữ dữ liệu. Cung cấp phƣơng thức lấy đối tƣợng dựa trên một vài tiêu chí và trả về toàn bộ đối tƣợng đã đƣợc khởi tạo hoặc tập hợp của đối tƣợng có thuộc tính trùng lặp với tiêu chí, qua đó đóng gói đƣợc bộ lƣu trữ thật sự và kĩ thuật truy vấn. Chỉ cung cấp các repository cho Aggregate root mà thực sự cần một truy cập trực tiếp. Giữ client tập trung vào model, ủy quyền tất cả việc lƣu trữ đối tƣợng và truy cập chúng cho một Repository. Một Repository có thể chứa thông tin chi tiết sử dụng cho việc truy cập tới infrastructure, nhƣng nó chỉ nên là một interface đơn giản. Một Repository nên có một bộ tập hợp các phƣơng thức dùng cho lấy đối tƣợng. Client gọi một phƣơng thức nhƣ vậy và truyền một hoặc nhiều tham số đại diệncho các tiêu trí dùng để lấy đối tƣợng hoặc bộ tập hợp đối tƣợng trùng với tiêu chí. Một Thực Thể có thể dễ dàng nhận diện bởi ID của chúng. Các tiêu chí lựa chọn khác có thể đƣợc tạo thành từ một tập hợp các thuộc tính của đối tƣợng. Repository sẽ so sánh tất cả đối tƣợng trái với tiêu chí và trả lại tập hợp thỏa mãn tiêu chí. Repository interface có thể chứa phƣơng thức đƣợc sử dụng cho thực hiện vài tính toán bổ sung giống nhƣ số của đối tƣợng của một kiểu nhất định.Việc cài đặt một repository có thể rất giống infrastructure, nhƣng repository interface sẽ chỉ là một model thuần túy.64 Hình 2- 9 Cài đặt repository Các lựa chọn khác là để xác định một tiêu chí lựa chọn nhƣ là một Đặc tả. Đặc tả cho phép định nghĩa một tiêu chí phức tạp hơn, chẳng hạn nhƣ phía dƣới đây: Có một mối quan hệ giữa Factory và Repository. Chúng đều là một pattern của thiết kế hƣớng lĩnhvực và chúng cùng giúp ta quản lý vòng đời của các domain đối tƣợng. Trong khi Factory liên quan tới việc khởi tạo đối tƣợng, thì Repository lo liệu các đối tƣợng đã tồn tại. Repository có thể cache đối tƣợng cục bộ, nhƣng hầu hết chúng cần lấy đối tƣợng từ một bộ lƣu trữ lâu dài nào đó. Đối tƣợng đƣợc tạo ra bằng cách sử dụng một constructor hoặc đƣợc trả về bởi một Factory khởi tạo. Với lý do đó, Repository có thể xem nhƣ là một Factory vì chúng có tạo ra đối tƣợng.65 Nókhông khởi tạo ngay từ đầu, nhƣng nó là một sự hoàn nguyên của đối tƣợng đã tồn tại. Ta không nên trộn một Repository với một Factory. Factory nên để tạo mới đối tƣợng, trong khi đó Repository nên tìm các đối tƣợng đã đƣợc khởi tạo. Khi một đối tƣợng mới đƣợc thêm vào Repository, chúng nên đƣợc khởi tạo bằng Factory trƣớc đó và sau đó chúng nên đƣợc trao lại cho Repository nhằm lƣu trữ chúng giống với ví dụ dƣới đây. Một cách khác để lƣu ý là các Factory là "domain thuần khiết", nhƣng các Repository có thể chứa các liên kết tới infrastructure, nhƣ là database. 2.3.4 Bounded Contexts Mỗi mô hình đều có một ngữ cảnh tƣơng ứng với nó. Ta làm việc với một mô hình, ngữ cảnh là ẩn. Ta không cần định nghĩa chúng. Khi ta tạo một chƣơng trình tƣơng tác với phần mềm khác, ví dụ một ứng dụng cũ, hiển nhiên là ứng dụng mới có mô hình và ngữ cảnh riêng của nó và chúng đƣợc chia riêng với mô hình và ngữ cảnh cũ. Chúng không thể gộp, trộn lẫn và không bị hiểu lầm. Tuy nhiên, khi ta làm việc với một ứng dụng doanh nghiệp lớn, ta cần định nghĩa ngữ cảnh cho từng mô hình ta tạo ra. Dự án lớn nào cũng có nhiều mô hình. Tuy vậy, mã nguồn dựa trên các mô hình riêng biệt lại đƣợc gộp lại và phần mềm trở nên nhiều lỗi, kém tin tƣởng và66 khó hiểu. Giao tiếp giữa các thành viên trong nhóm trở nên rối. Thƣờng thì việc quyết định mô hình nào áp dụng cho ngữ cảnh nào là không rõ ràng. Không có một công thức nào để chia mọi mô hình to thành nhỏ thành nhỏ hơn. Hãy thử đặt những thành phần có liên quan vào mô hình theo những khái niệm một cách tự nhiên. Một mô hình cần đủ nhỏ để nó phù hợp với một nhóm. Sự phối hợp và trao đổi nhóm sẽ ý tƣởng chính cho việc định nghĩa một mô hình là vẽ ra ranh giới giữa các ngữ cảnh, sau đó cố gắng giữ các mô hình có đƣợc sự thống nhất càng cao càng tốt. Việc giữ một mô hình "thuần khiết" khi nó mở rộng ra cả dự án doanh nghiệp là rất khó, nhƣng dễ dàng hơn khi ta hạn chế trong một mảng cụ thể. Định nghĩ một cách hiển minh ngữ cảnh trong ngữ cảnh giới hạn. Hãy xác định ranh giới giữa các điều khoản của tổ chức nhóm, dùng nó trong một phần cụ thể của mô hình, thể hiện nó một cách vật lý bằng, chẳng hạn nhƣ schema của mã nguồn. Duy trì mô hình này tƣơng thích chặt chẽ với các giới hạn nó. Tuy vậy, đừng để mất tập trung hay rối loạn vì những vấn đề bên ngoài. Một ngữ cảnh giới hạn không phải là một mô-đun. Môt ngữ cảnh giới hạn cung cấp khung logic bên trong của mô hình. Mô-đun tổ chức các thành phần của mô hình, do đó ngữ cảnh giới hạn chứa mô-đun thông suốt và hoàn chỉnh, giúp cho lập trình viên làm việc trên cùng một mô hình. Ngữ cảnh của mô hình là tập các điều kiện cần đƣợc áp dụng để đảm bảo những điều khoản của mô hình có ý nghĩa cụ thể. Việc có nhiều mô hình có cái giá phải trả. Ta cần định nghĩa ranh giới và quan hệ giữa các mô hình khác nhau. Điều này đòi hỏi nhiều công sức và có thể cần sự "phiên dịch" giữa các mô hình khác nhau. Ta không thể chuyển đối tƣợng bất kỳ giữa các mô hình khác nhau và ta không thể gọi tự do giữa các mô hình nhƣ là không có ranh giới nào. Đây không phải là một công việc quá khó và lợi ích nó đem lại đáng đƣợc đầu tƣ. Ví dụ ta muốn tạo ra một phần mềm thƣơng mại điện tử để bán phần mềm trên Internet. Phần mềm này cho phép khách hàng đăng ký và ta thu thập dữ liệu cá nhân, bao gồm số thẻ tín dụng. Dữ liệu đƣợc lƣu trong CSDL quan hệ. Khách hàng có thể đăng nhập, duyệt trang web để tìm hàng và đặt hàng. Chƣơng trình cần công67 bố sự kiện khi có đơn đặt hàng vì ai đó cần phải gửi thƣ có hạng mục đã đƣợc yêu cầu. Ta cần xây dựng giao diện báo cáo dùng cho việc tạo báo cáo để có thể theo dõi trạng thái hàng còn, khách hàng muốn mua gì, họ không thích gì... Ban đầu, ta bắt đầu bằng một mô hình phủ cả domain thƣơng mại điện tử. Ta muốn làm thế vì sau chúng, ta cũng sẽ cần làm một chƣơng trình lớn. Tuy nhiên, ta xem xét công việc này cẩn thận và phát hiện ra rằng chƣơng trình e-shop thực ra không liên quan đến chức năng báo cáo. Chúng quan tâm đến cái khác, vận hành theo một cách khác và thậm chí, không cần dùng công nghệ khác. Điểm chung duy nhất ở đây là khách hàng và dữ liệu hàng hóa đƣợc lƣu trong CSDL mà cả hai đều truy cập vào. Cách tiếp cận đƣợc khuyến nghị ở đây là tạo mô hình riêng cho mỗi domain, một domaincho e-commerce, một cho phần báo cáo. Chúng có thể tiến hóa tự do không cần quan tâm tới domain khác và có thể trở thành những chƣơng trình độc lập. Có trƣờng hợp là chƣơng trình báo cáo cần một số dữ liệu đặc thù mà chƣơng trình e-commerce lƣu trong CSDL dù cả hai phát triển độc lập. Một hệ thống thông điệp cần để báo cáo cho ngƣời quản lý kho về đơn đặt hàng để họ có thể gửi mail về hàng đã đƣợc mua. Ngƣời gửi mail sẽ dùng chƣơng trình và cung cấp cho họ thông tin chi tiết về hàng đã mua, số lƣợng, địa chỉ ngƣời mua cũng nhƣ yêu cầu giao hàng. Việc có mô hình e-shop phủ cả hai domain là không cần thiết. Sẽ đơn giản hơn nhiều cho chƣơng trình e-shop chỉ gửi Đối tƣợng Giá trị chứa thông tin mua tới kho bằng phƣơng thức thông điệp phi đồng bộ. Rõ ràng là có hai mô hình có thể phát triển độc lập và ta chỉ cần đảm bảo giao diện giữa chúng hoạt động tốt. 2.4. Quy trình phân tích và thiết kế phần mềm hƣớng lĩnh vực Một dự án theo mô hình DDD gồm các bƣớc nhƣ sau: - Mô hình và quy trình hóa tài liệu nghiệp vụ - Lựa chọn một quy trình nghiệp vụ chuẩn và làm việc với các chuyên gia về kiểm chứng các tài liệu nghiệp vụ thông qua việc sử dụng ngôn ngữ dùng chung. - Xác định tất cả các dịch vụ đƣợc yêu cầu cho quy trình nghiệp vụ đó. Những dịch vụ có thể là các bƣớc đơn lẻ hoặc là nhiều bƣớc không có Work - Flow.68 - Định danh, xác định trạng thái, hành vi của các đối tƣợng đƣợc sử dụng bởi các dịch vụ đã đƣợc xác định ở bƣớc trƣớc Điều quan trọng là giữ mô hình ở mức độ cao ban đầu tập trung vào các thành phần cốt lõi của lĩnh vực nghiệp vụ. Từ một dự án quản lý chuẩn, một thực tế khi thực hiện một dự án DDD bao gồm các giai đoạn tƣơng tự nhƣ bất kỳ dự án phát triển phần mềm khác. Các pha bao gồm: - Mô hình hóa lĩnh vực - Thiết kế - Phát triển - Unit and Integration Testing - Tinh chỉnh và cấu trúc lại mô hình nghiện vụ dựa vào việc thiết kế và phát triển (tích hợp liên tục các định nghĩa mô hình). Lặp lại các bƣớc trên bằng cách cập nhật lại các mô hình nghiệp vụ Hình 2- 10 Quy trình thiết phát triển phần mềm theo hướng DDD69 Chƣơng 3: Ứng dụng chiến lược thiết kế hƣớng lĩnh vực trong việc xây dựng phần mềm quản lý tài khoản tập trung theo hƣớng dịch vụ microservice 3.1 Mô tả bài toán quản lý tài khoản dùng chung tại trƣờng ĐHDL Hải Phòng Trƣờng Đại học Dân lập Hải Phòng đƣợc thành lập vào ngày 24 tháng 09 năm 1997 GS.TS.NGƢT Trần Hữu Nghị làm hiệu trƣởng. Cho đến nay Nhà trƣờng đã đào tạo ra hàng nghìn cử nhân, kỹ sƣ cho cả nƣớc. Với cơ sở vật chất khang trang hiện đại. Nhà trƣờng luôn chủ động tin học hóa các nghiệp vụ đào tạo chính của nhà trƣờng. Trƣờng ĐHDL Hải Phòng là một trong số ít trƣờng áp dụng thành công bài toán quản lý đào tạo tín chỉ một cách triệt để. Sau 20 năm phát triển nhà trƣờng đã không ngừng đầu tƣ và phát triển các ứng dụng phần mềm vào công tác quản lý đào tạo có những sản phẩm mua của các công ty bên ngoài, có những sản phẩm do nhà trƣờng xây dựng mỗi một phần mềm lại có hệ thống tài khoản dùng riêng. Nhiều phần mềm không còn có thể đáp ứng đƣợc với những yêu cầu thực tế của Nhà trƣờng. Mỗi một sinh viên có tới 4 đến 5 tài khoản khác nhau dẫn đến gây rất nhiều khó khăn cho sinh viên. Bên cạnh đó các ứng dụng phát triển sau không thể kế thừa hoặc tận dụng lại đƣợc các ứng dụng đã có trƣớc nên việc xây dựng phần mềm mất nhiều thời gian, công sức hơn. Trƣớc đây các phần mềm phát triển và chạy độc lập nhau thành các nguyên khối. Do đó việc trao đổi thông tin cũng nhƣ mở rộng ứng dụng là không thể. Dữ liệu ngày càng nhiều dẫn đến hệ thống chạy chậm và không linh hoạt. Sau đó ứng dụng mô hình SOA (Services Orient Achitecture) đối với các ứng dụng. Tuy nhiên với mô hình này các dịch vụ khó có thể mở rộng. Monolithic SOA Microservices Hình 3- 5 Quá trình phát triển các mô hình ứng dụng phần mềm của nhà trường70 Đề xuất giải pháp cho các vấn đề đặt ra: - Áp dụng chiến lƣợc thiết kế hƣớng miền cho việc phân tích thiết kế các bài toán đào tạo của nhà tƣờng - Tìm hiểu và phát triển các ứng dụng của nhà trƣờng tiếp cận theo mô hình Microservice (Microservice có thể từ một ứng dụng chia nhỏ thành các service nhỏ dễ dàng mở rộng thêm các dịch vụ một cách nhanh chóng. Các dịch vụ hoạt động một cách độc lập). Mô hình Microservice thay thế cho các phần mềm xây dựng theo mô hình nguyên khối (monolithic) hay mô hình kiến trúc hƣớng dịch vụ SOA (Services Orient Achitecture). - Xây dựng dịch vụ quản lý tài khoản tập trung cho tất cả các đối tƣợng (sinh viên, giảng viên, cán bộ, nhân viên..) sử dụng các dịch vụ của nhà trƣờng. Chỉ cần sử dụng một tài khoản có thể đăng nhập vào các hệ thống đã đăng ký với các quyền quy định. Dịch vụ này đƣợc sử dụng cho các dịch vụ khác trong hệ thống. Dịch vụ đƣợc xây dựng trên nền tảng Webbase dễ dàng cho việc bảo trì, bảo dƣỡng và triển khai, hỗ trợ cả các thiết bị mobile. 3.2 Tìm hiểu kiến trúc Microservices Ứng dụng quản lý tài khoản tập trung đƣợc xây dựng theo hƣớng Microservices. Microservices là kiến trúc dịch vụ siêu nhỏ “Microservice Architecture” phát triển nhanh chóng trong nhiều năm gần đây nhằm mô tả cách thiết kế phần mềm ứng dụng mà các dịch vụ có thể triển khai một cách độc lập. Mặc dù không có định nghĩa rõ ràng về kiểu kiến trúc này, ta vẫn có thể kể đến rất nhiều đặc tính chung của các tổ chức, phạm vi nghiệp vụ, tính chất quản lý phân tán cũng nhƣ dữ liệu khi nói đến microservices. Nhiều tập đoàn nhƣ Amazon, eBay, Netflix đã giải quyết vấn đề ứng dụng một khối bằng kiến trúc microservices (nhiều dịch vụ nhỏ). Ý tƣởng là chia nhỏ ứng dụng lớn ra thành các dịch vụ nhỏ kết nối với nhau. Mỗi dịch vụ nhỏ thực hiện một tập các chức năng chuyên biệt nhƣ quản lý đơn hàng, quản lý khách hàng. Mỗi dịch vụ là một ứng dụng nhỏ có kiến trúc đa diện lõi là business logic kết nối ra các adapter khác nhau. Một số dịch vụ nhỏ lộ ra giao tiếp lập trình API cho dịch vụ nhỏ khác hay ứng dụng client gọi tới. Khi71 vận hành, mỗi dịch vụ nhỏ đƣợc chạy trong một máy ảo (virtual machine) hoặc Docker container (ảo hóa tầng ứng dụng). Hình 3- 6 Microservices của một công ty điều hành taxi kiểu Uber, Hailo [13] Mỗi vùng chức năng giờ đƣợc thực thị bởi một dịch vụ nhỏ. Ứng dụng web cũng có thể chia nhỏ hơn chuyên cho từng đối tƣợng ngƣời dùng (một cho hành khách taxi, một cho tài xế). Thiết kế giao diện cho từng đối tƣợng ngƣời dùng giúp tối ƣu trải nghiệm tốt hơn, tốc độ nhanh hơn, dễ tƣơng thích hơn trong khi chức năng tối giản hơn. Mỗi dịch vụ đằng sau (back end service) lộ ra REST API (hiện nay còn nhiều lựa chọn khác nhƣ Google Protobuf, Apache Thrift, Apache Avro tốn ít băng thông hơn REST JSON) Các dịch vụ sẽ gọi / sử dụng API cung cấp bởi dịch vụ khác. Ví dụ dịch vụ quản lý tài xe sử dụng Notification Server để chủ động báo tài xế đang rảnh đón khách hàng tiềm năng. Phần giao diện (UI services) sẽ gọi đến các dịch vụ khác để lấy dữ liệu hiển thị. Hiện nay, pattern reactive cho phép dịch vụ có thể thông báo hoặc chủ động gửi dữ liệu mới để giao diện cập nhật. Đặc điểm của kết nối giữa các dịch vụ có thể là: - Synchronous (đồng bộ - gọi xong chờ)72 - Asynchronous (bất đồng bộ - gọi xong chạy tiếp. Khi có kết quả thì xử lý), Cách gọi: - REST (tập lệnh gửi qua HTTP để truy vấn, thao tác dữ liệu. Kiểu dữ liệu XML, JSON, JSONb) - RPC (remote procedure call - lệnh gọi từ xa. Kiểu dữ liệu binary, Thrift, Protobuf, Avro) - SOAP (Simple Object Access Protocol) Một số dịch API REST có thể lộ ra cho thiết bị di động của hành khách và tài xế kết nối. Ứng dụng của ngƣời dùng cuối sẽ không đƣợc kết nối trực tiếp vào dịch vụ đằng sau. Thay vào đó có một cổng API (API gateway) đứng giữa. Cổng API có một số nhiệm vụ nhƣ phân tải, lƣu tạm (cache), kiểm tra quyền truy cập, đo và theo dõi (API metering and monitoring). Kiến trúc microservices ảnh hƣởng lớn đến quan hệ ứng dụng và cơ sở dữ liệu. Thay vì dùng chung một cơ sở dữ liệu giữa các dịch vụ, mỗi dịch vụ sẽ có CSDL riêng. Cách này đi ngƣợc lại tập quán tập trung hóa cơ sở dữ liệu. Hệ quả là sẽ có dƣ thừa dữ liệu, cơ chế foreign key ràng buộc quan hệ dữ liệu không thể áp dụng với bảng ở 2 cơ sở dữ liệu tách biệt. Thiết kế này sẽ gây sốc vì trƣớc đây ta đã quá quen với mô hình client - server, ở đó cơ sở dữ liệu luôn là một trung tâm, tập hợp mọi bảng. [13] Ƣu điểm của Microservices: - Giảm thiểu sự gia tăng phức tạp rối rắm hệ thống lớn. - Chia nhỏ ứng dụng một khối cồng kềnh thành các dịch vụ nhỏ dễ quản lý, bảo trì nâng cấp, tự do chọn, nâng cấp công nghệ mới. - Mỗi dịch vụ nhỏ sẽ định ra ranh giới rõ ràng dƣới dạng RPC hay API hƣớng thông điệp. - Microservice thúc đẩy tách rạch ròi các khối chức năng (loose coupling - high cohesion), điều rất khó thực hiện với ứng dụng một khối. Nếu muốn loose coupling - high cohesion trong ứng dụng một khối, sẽ phải thiết kế theo Design Pattern (Gang Of Four) và liên tục tái cấu trúc (refactor)73 - Mỗi dịch vụ nhỏ sẽ phát triển dễ hơn, nhanh hơn, dễ viết mã kiểm thử tự động. - Một số dịch vụ có thể thuê ngoài phát triển mà vẫn bảo mật hệ thống - mã nguồn phần dịch vụ còn lại. Đội phát triển có nhiều lựa chọn công nghệ mới, framework, CSDL mới, đa dạng để nâng cấp từng dịch vụ nhỏ, chọn môi trƣờng tối ƣu nhất để chạy. Các dịch vụ có thể bật tắt để kiểm nghiệm so sánh A|B, tăng tốc quá trình cải tiến giao diện. Triển khai đều đặn khả thi với microservice. Dịch vụ nhỏ đóng gói trong Docker container có thể chuyển từ môi trƣờng phát triển sang môi trƣờng chạy thật không phải cấu hình thủ công lại, không phải copy file quá lớn. Nhƣợc điểm của microservices: Nhƣợc điểm đầu tiên của microservices cũng chính từ tên gọi của nó. Microservice nhấn mạnh kích thƣớc nhỏ gọn của dịch vụ. Một số lập trình đề xuất dịch vụ siêu nhỏ cỡ dƣới 100 dòng code. Chia quá nhiều sẽ dẫn đến manh mún, vụn vặt, khó kiểm soát. Việc lƣu dữ liệu cục bộ bên trong những dịch vụ quá nhỏ sẽ khiến dữ liệu phân tán quá mức cần thiết. Nhƣợc điểm tiếp của microservice đến từ đặc điểm hệ thống phân tán (distributed system): - Phải xử lý sự cố khi kết nối chậm, lỗi khi thông điệp không gửi đƣợc hoặc thông điệp gửi đến nhiều đích đến vào các thời điểm khác nhau. - Đảm bảo giao dịch phân tán (distributed transaction) cập nhật dữ liệu đúng đắn (all or none) vào nhiều dịch vụ nhỏ khác nhau khó hơn rất nhiều, đôi khi là không thể so với đảm bảo giao dịch cập nhật vào nhiều bảng trong một cơ sở dữ liệu trung tâm. - Theo nguyên tắc CAP (CAP theorem) thì giao dịch phân tán sẽ không thể thỏa mãn cả 3 điều kiện: consistency (dữ liệu ở điểm khác nhau trong mạng phải giống nhau), availablity (yêu cầu gửi đi phải có phúc đáp), partition tolerance (hệ thống vẫn hoạt động đƣợc ngay cả khi mạng bị lỗi). Những công nghệ cơ sở dữ liệu phi quan hệ (NoSQL) hay môi giới thông điệp (message broker) tốt nhất hiện nay cũng chƣa vƣợt qua nguyên tắc CAP.74 - Kiểm thử tự động một dịch vụ trong kiến trúc microservices đôi khi yêu cầu phải chạy cả các dịch vụ nhỏ khác mà nó phụ thuộc. Do đó khi phân rã ứng dụng một khối thành microservices cần luôn kiểm tra mức độ ràng buộc giữa các dịch vụ mềm dẻo hơn hay cứng nhắc - lệ thuộc hơn. Nếu ràng buộc ít đi, lỏng leo hơn, bạn đi đúng hƣớng và ngƣợc lại. - Nếu các dịch vụ nhỏ thiết kế phục thuộc vào nhau theo chuỗi. A gọi B, B gọi C, C gọi D. Nếu một mắt xích có giao tiếp API thay đổi, liệu các mắt xích khác có phải thay đổi theo không? Nếu có thì việc bảo trì, kiểm thử sẽ phức tạp tƣơng tự ứng dụng một khối. Thiết kế dịch vụ tốt sẽ giảm tối đa ảnh hƣởng lan truyền đến các dịch vụ khác. - Triển khai dịch vụ microservices nếu làm thủ công theo cách đã làm với ứng dụng một khối phức tạp hơn rất nhiều. Ứng dụng một khối bổ sung các server mới giống hệt nhau đằng sau bộ cần bằng tại. Trong khi ở kiến trúc microservice, các dịch vụ nhỏ nằm trên nhiều máy ảo hay Docker container khác nhau, hoặc một dịch vụ có nhiều thực thể phân tán ra nhiều. Trong dịch vụ đám mây, các máy ảo, docker container, thực thể có thể linh động bật tắt, dịch chuyển. Vậy cần thiết phải có một cơ chế phát hiện dịch vụ (service discovery mechanism) để cập nhật tự động địa chỉ IP và cổng, mô tả, phiên bản của mỗi dịch vụ. Kết luận Kiến trúc một khối sẽ hữu hiệu đối với ứng dụng đơn giản, ít chức năng. Nó bộc lộ nhiều nhƣợc điểm khi ứng dụng phát triển lớn nhiều chức năng. Kiến trúc microservices chia nhỏ kiến trúc một khối ra các dịch vụ nhỏ. Microservices sẽ hiệu quả, phù hợp cho những ứng dụng phức tạp, liên tục phát triển nếu đƣợc thiết kế đúng và tận dụng các công nghệ quản lý, vận hành tự động.75 3.3 Tìm hiểu mô hình Publisher – Subscriber Event Hình 3- 7Mô hình Publisher – Subscriber Events Hình 3- 8 Mô hình kiến trúc liên lạc76 Khi ứng dụng đƣợc chia nhỏ ra thành các Service độc lập theo kiến trúc Microservices. Để đảm bảo trao đổi dữ liệu cần có một cơ chế thực hiện để các service ít phụ thuộc nhau. Trong ứng dụng này tác giả xin đƣợc sử dụng cơ chế mô hình Publisher – Subcriber. Service này có thể đẩy (Pub) các sự kiện vào bộ đệm và các Service khác có thể lắng nghe (listener) và lấy về (Sub). Hệ thống đƣợc xây dựng tự động, là các service có thể hoàn toàn đăng ký các Publisher hay các Subscriber sự kiện. Có thể thỏa mãn cả 3 điều kiện: consistency (dữ liệu ở điểm khác nhau trong mạng phải giống nhau), availablity (yêu cầu gửi đi phải có phúc đáp), partition tolerance (hệ thống vẫn hoạt động đƣợc ngay cả khi mạng bị lỗi). 3.4 Phân tích và thiết kế yêu cầu phần mềm hƣớng lĩnh vực a) Mục đích Xây dựng, thiết kế hệ thống quản lý tài khoản tập trung. Với một tài khoản duy nhất ngƣời dùng có thể sử dụng nhiều ứng dụng. Đồng thời giúp cho việc xây dựng, tích hợp các dịch vụ mới vào hệ thống một các nhanh chóng, linh hoạt mà không phải quan tâm về việc quản lý tài khoản, hay phân quyền cho ngƣời dùng. b) Các định nghĩa, mô tả 1. Một ngƣời dùng chƣa có tài khoản khi vào ứng dụng thì phải tạo tài khoản 2. Ngƣời dùng khi tạo một tài khoản mới phải điền các thông tin cơ bản nhƣ: FirstName, LastName, Email, password. Hệ thống AMS sẽ xác định tài khoản đƣợc tạo cho ứng dụng nào và gửi vào mail cho ngƣời dùng đƣờng dẫn (URL) để kích hoạt tài khoản. Sau khi kích hoạt thành công ngƣời dùng có thể truy cập đƣợc vào ứng dụng mà hệ thống cho phép. 3. Ngƣời dùng khi đã có tài khoản trên AMS, khi vào ứng dụng đăng nhập Hệ thống AMS xác định tài khoản và ứng dụng yêu cầu xác thực. Nếu có thì AMS sẽ gửi lại App một khóa (token) cho phép tài khoản truy cập vào ứng dụng App sẽ kiểm tra Token. Nếu hợp lệ sẽ xác định các quyền của tài khoản thao tác trên ứng dụng đó. Không hợp lệ sẽ không cho phép truy cập vào ứng dụng.77 4. Khi ngƣời dùng muốn thay đổi một số thông tin cá nhân. Ngƣời dùng sẽ đăng nhập bổ sung và thay đổi một số thông tin. 5. Phân quyền cho ngƣời dùng trên AMS. Trên AMS tài khoản Admin sẽ có quyền quản lý các ngƣời dùng và phân quyền. 6. Phân quyền cho tài khoản ngƣời dùng trên các ứng dụng. Admin ứng dụng đăng nhập vào chức năng quản lý ngƣời dùng để: Tìm kiếm, đƣa danh sách hoặc tài khoản ngƣời dùng vào ứng dụng, tạo nhóm, phân quyền nhóm, phân quyền, khóa tài khoản, loại bỏ tài khoản ra khỏi ứng dụng. c) Các yêu cầu nghiệp vụ Hình 3- 9 Usecase của hệ thống d) Nghiệp vụ, chức năng (Product Backlog) - Là khách thì có các chức năng (Guest functions): o Có thể đăng ký tài khoản (Register). Khách khi vào ứng dụng nếu chƣa có tài khoản thì có thể đăng ký. Khi đăng ký cần phải điền các thông tin UserRegi sterLogi n/LogoutChange passwordChange Profi l eRecover passwordAdm i nAdd/Rem ove User Appl i cati on rol esAdd/Rem ove Appl i cati onAdd/Rem ove User Appl i cati onAdd/Rem ove Rol esGuest78 nhƣ: User_name, First_name, Last_name, Email, Password. Nếu tài khoản đã tồn tại thì thông báo yêu cầu tạo tài khoản khác. - Là ngƣời dùng thì có các chức năng (User functions) o Login/LogOut: Khi có tài khoản ngƣời dùng có thể login vào ứng dụng thông qua Username và password, hay có thể logout. o Thay đổi Profile (Change profile): User login đăng nhập vào ứng dụng thay đổi các thông tin cá nhân của mình nhƣ: FirstName, LastName, Email, Password. o Khôi phục mật khẩu (Recover password) khi bị mất: Khi ngƣời dùng quên mật khẩu có thể sử dụng chức năng này để lấy lại mật khẩu. Hệ thống sẽ gửi vào email đƣờng link thay đổi mật khẩu. - Là Admin thì có các chức năng ( Admin function) o Tạo ngƣời dùng (Create User): Chỉ có Admin mới có thể tạo tài khoản ngƣời dùng. Các thông tin gồm: Username, Firstname, Lastname, Email, Password o Tìm kiếm ngƣời dùng: Tìm kiếm theo Username, email... o Thêm, xóa, sửa ngƣời dùng theo ứng dụng: Admin thêm, xóa, sửa User cho Application. o Gán, gỡ quyền cho ngƣời dùng: Admin có thể gán, gỡ quyền của User ứng dụng. o Thêm, xóa, sửa ứng dụng (application): Admin có thể khai báo thêm, xóa, sửa một ứng dụng o Thêm, xóa, sửa nhóm (role): Admin có thể khai báo thêm, xóa, sửa quyền o Khóa tài khoản ngƣời dùng: Admin có thể khóa, mở khóa tài khoản ngƣời dùng cho ứng dụng. o Theo dõi nhật ký sử dụng: Admin có thể theo dõi nhật ký sử dụng của ngƣời dùng.79 e) Mô hình kiến trúc của hệ thống hƣớng Microservices Hình 3- 10Mô hình kiến trúc của hệ thống hướng Microservice Hình 3- 11 Mô hình DDD80 - Ruby on rails: Hệ thống đƣợc xây dựng dựa trên nền tảng công nghệ Ruby on rails. Ruby On rails là một Framework cho phép phát triển ứng dụng Web gồm 2 phần cơ bản: o Phần ngôn ngữ Ruby: “Ruby là một ngôn lập trình mã nguồn mở, linh hoạt, với một sự nổi bật về sự đơn giản dễ dùng và hữu ích. Nó có cú pháp dễ đọc và dễ dàng để viết”. o Phần Framework Rails bao gồm nhiều thƣ viện liên kết. - Cassandra: Cassandra là một quản trị hệ cơ sở dữ liệu phân tán mã nguồn mở đƣợc thiết kế để xử lý một khối lƣợng lớn dữ liệu giàn trải trên nhiều node mà vẫn đảm bảo tính sẵn sàng cao (Highly Availability), khả năng mở rộng hay thu giảm số node linh hoạt (Elastic Scalability) và chấp nhận một số lỗi (Fault Tolerant). Nó đƣợc phát triển bởi Facebook và vẫn còn tiếp tục phát triển và sử dụng cho mạng xã hội lớn nhất thới giới này. Năm 2008, Facebook chuyển nó cho cộng đồng mã nguồn mở và đƣợc Apache tiếp tục phát triển đến ngày hôm nay. Cassandra đƣợc coi là sự kết hợp của Amazon’s Dynamo và Google’s BigTable. f) ProfileService Profile Rules: + FirstName, LastName, Email không đƣợc để trống và độ dài không quá 256 ký tự + Email là duy nhất, độ dài không quá 256 kí tự. Hình 3- 12 DDD của dịch vụ Profile Entity: Profile Value Objects: FirstName, LastName, Email81 Hình 3- 13Profile Usecase - Một Profile đƣợc đăng ký thông qua Guest, hoặc Admin. - Một User đƣợc quyền sửa thông tin cá nhân của mình nhƣ thay đổi FirstName, LastName, Email... - Amin có quyền chỉnh sửa thông tin cá nhân của User. Profile Command Events: - Đăng ký một tài khoản ngƣời dùng (RegisterAccount): Khi đăng ký một tài khoản sẽ xảy ra các Event sau: o ProfileCreate:Guest/Admin({id:1,FirstName:’Do Van’, LastName: ’Hung’,Email: ’
[email protected]’}) o AccountCreate:Guest/Admin({id,Profile_id,UserName:’hungdv’,password:’123654’}) - Thay đổi thông tin Profile (ChangeProfile): Khi một User/Admin muốn thay đổi thông tin cá nhân của một tài khoản. User chỉ đƣợc phép thay đổi thông tin của mình. Các Event xảy ra: o ProfileUpdate:User/Admin({FirstName:’Nguyen Van’, LastName: ’Hung’, Email:
[email protected]}) - Xóa một Profile(Remove Profile). Admin có thể xóa một Profile ngƣời dùng: Các Event xảy ra: GuestRegi sterChangeProfi l eAdm i nUser82 o ProfileRemove:Admin({id:1}) o AccountRemove:Admin({Profile_id:1}) o AccountApplicationRoleRemove:Admin({Account_id:} g) AccountService Hình 3- 14DDD Account Account Rules: + Một Username cần phải có một Profile. + UserName không đƣợc để trống và độ dài không quá 256 ký tự + Password không đƣợc phép trùng với Username, độ dài là 6 ký tự trở lên Entity: Account Value Objects: Password Hình 3- 15 Account Usecase GuestRegi sterAccountAdm i nChangePasswordUserRem oveAccount83 Hình 3- 16 Tạo tài khoản người dùng - Guest/Admin có thể đăng ký tài khoản ngƣời dùng. Account Command Events: - Đăng ký một tài khoản ngƣời dùng (RegisterAccount): Khi đăng ký một tài khoản sẽ xảy ra các Event sau: o ProfileCreate:Guest/Admin({id:1,FirstName:’DoVan’,LastName: ’Hung’, Email:’
[email protected]’}) o AccountCreate:Guest/Admin({id,Profile_id,UserName:’hungdv’,password:’123654’}) - Thay đổi mật khẩu ngƣời dùng(ChangePassword): User/Admin có quyền thay đổi mật khẩu. Các Event sau: o AccountChangePassword:User/Admin({UserName:’hungdv’, Password:New password })84 - Xóa một tài khoản Account(Remove Account). Admin có thể xóa một tài khoản ngƣời dùng: Các Event xảy ra: o ProfileRemove:Admin({id:1}) o AccountRemove:Admin({Profile_id:1}) o AccountApplicationRole:Admin({Account_id:} h) Authenticate Service Hình 3- 17Mô hình DDD của dịch vụ Authenticate Authenticate Rules: + Một tài khoản sẽ có nhiều quyền. + Mỗi quyền đều có Validate (Yes/No) đƣợc phép hay không. + Cần phải tồn tại ngƣời dùng và quyền của ứng Value Objects: Status, Validate Hình 3- 18Authenticate Usecase Authenticate Command Events: - Khi Admin Thêm quyền cho ngƣời dùng (Gant privilege): Các Event xảy ra: o AccountApplicationRoleGrantPrivilege:Admin({Account_id:1,AppliactionRole_id:2}) - Khi Admin gỡ quyền của ngƣời dùng (Revoke privilege): Các Event xảy ra: Adm i nGrant Pri vi l egeRevoke Pri vi l ege85 o AccountApplicationRoleRevokePrivilege:Admin({Account_id:1,AppliactionRole_id:2}) i) Application Role Service Hình 3- 19Mô hình DDD của dịch vụ ApplicationRole Application Rules: + Admin có quyền thực hiện các thao tác này Entity: Application, Role, Permission Value Objects: RolePermission, ApplicationRole Hình 3- 20 Mô hình DDD của ApplicationRole Adm i nAdd/Rem ove Appl i cati onAdd/Rem ove Rol eAdd/Rem ove Perm i ssi onAdd/Rem ove Rol ePerm i ssi onAdd/Rem ove Appl i cati onRol e86 ApplicationRole Command Events: - Khi thêm một application (AddApplication). Các Event xảy ra: o ApplicationCreate:Admin({id:1,Applicationname:’Account Management System’}) - Khi xóa một Application(RemoveApplication) các Event xảy ra: o ApplicationRemove:Admin({id:1}) o ApplicationRoleRemove:Admin({Application_id:1}) - Khi thêm một Role các Event xảy ra: o RoleCreate:Admin({id:1, Rolename:’Student’}) - Xóa Role các Event xảy ra: o RoleRemove:Admin({id:1}) o RolePermissionRemove:Admin({Role_id:1}) - Thêm các quyền cho nhóm (AddRolePermission): Các Event: o RolePermissionCreate:Admin({id:, Role_id:, Permission_id:}) - Xóa một nhóm quyền (RemoveRolePermission):Các Event xảy ra: o RolePermissionRemove:Admin({id:}) - Thêm một nhóm quyền cho ứng dụng(AddApplicationRole): Các Event: o ApplicationRoleCreate:Admin({id:,Application_id:, RolePermission_id:}) - Xóa một nhóm quyền của ứng dụng (RemoveApplicationRole):Các Event xảy ra: o ApplicationRoleRemove:Admin({id:})87 3.5. Cài đặt và đánh giá phần mềm thử nghiệm Command RegisterAccount. Hình 3- 21 Register Account Command change password Hình 3- 22 Change password Command ProfileRemove88 Hình 3- 23 Xóa một Profile89 Danh sách các Events Hình 3- 24 Các Envets90 Cấu trúc thƣ mục: Hình 3- 25 Cấu trúc thư mục code chương trình91 Models: Hình 3- 26 Danh sách các Model Domain: + Profile.rb module Domain class Profile include AggregateRoot AlreadySubmitted = Class.new(StandardError) ProfileExpired = Class.new(StandardError) def submit(Id, FirstName, LastName, UserName, LastName, Email, Password) raise AlreadySubmitted if state == :submitted raise ProfileExpired if state == :expired apply Events::ProfileSubmitted.new(data: {id: id, FirstName: FirstName, LastName: LastName, Email: Email, Password: Password}) end def expire raise AlreadySubmitted unless state == :draft apply Events::ProfileExpired.new(data: {id: id}) end def apply_Profile_submitted(event) @id = event.data[:id] @Firstname = event.data[:Firstname] @Lastname = event.data[:Lastname] @Email= event.data[:Email] @state = :submitted end def apply_Profile_expired(event) @state = :expired end end92 end + Events.rb module Events ProfileCreate = Class.new(RailsEventStore::Event) AccountCreate = Class.new(RailsEventStore::Event) ProfileUpdate = Class.new(RailsEventStore::Event) ProfileRemove = Class.new(RailsEventStore::Event) AccountRemove = Class.new(RailsEventStore::Event) AccountChangePassword = Class.new(RailsEventStore::Event) AccountApplicationRoleRemove = Class.new(RailsEventStore::Event) AccountApplicationRoleGrantPrivilege = Class.new(RailsEventStore::Event) AccountApplicationRoleRevokePrivilege = Class.new(RailsEventStore::Event) ApplicationCreate = Class.new(RailsEventStore::Event) ApplicationRemove = Class.new(RailsEventStore::Event) ApplicationRoleRemove = Class.new(RailsEventStore::Event) RoleCreate = Class.new(RailsEventStore::Event) RoleRemove = Class.new(RailsEventStore::Event) RolePermissionCreate = Class.new(RailsEventStore::Event) RolePermissionRemove = Class.new(RailsEventStore::Event) ApplicationRoleCreate = Class.new(RailsEventStore::Event) ApplicationRoleRemove = Class.new(RailsEventStore::Event) end + Event_store_setup.rb module EventStoreSetup def event_store @event_store ||= RailsEventStore::Client.new.tap do |es| es.subscribe(Denormalizers::ProfileCreate.new, [Events::ProfileCreate]) es.subscribe(Denormalizers::AccountCreate.new, [Events::AccountCreate]) es.subscribe(Denormalizers::ProfileUpdate.new, [Events::ProfileUpdate]) es.subscribe(Denormalizers::ProfileRemove.new, [Events::ProfileRemove]) es.subscribe(Denormalizers::AccountRemove.new, [Events::AccountRemove]) es.subscribe(Denormalizers::AccountChangePassword.new, [Events::AccountChangePassword])93 es.subscribe(Denormalizers::AccountApplicationRoleRemove.new, [Events::AccountApplicationRoleRemove]) es.subscribe(Denormalizers::AccountApplicationRoleGrantPrivilege.new, [Events::AccountApplicationRoleGrantPrivilege]) es.subscribe(Denormalizers::AccountApplicationRoleRevokePrivilege.new, [Events::AccountApplicationRoleRevokePrivilege]) es.subscribe(Denormalizers::ApplicationCreate.new, [Events::ApplicationCreate]) es.subscribe(Denormalizers::ApplicationRemove.new, [Events::ApplicationRemove]) es.subscribe(Denormalizers::RoleCreate.new, [Events::RoleCreate]) es.subscribe(Denormalizers::RoleRemove.new, [Events::RoleRemove]) es.subscribe(Denormalizers::RolePermissionCreate.new, [Events::RolePermissionCreate]) es.subscribe(Denormalizers::RolePermissionRemove.new, [Events::RolePermissionRemove]) es.subscribe(Denormalizers::ApplicationRoleCreate.new, [Events::ApplicationRoleCreate]) es.subscribe(Denormalizers::ApplicationRoleRemove.new, [Events::ApplicationRoleRemove]) end end94 Đánh giá và kết luận Chiến lƣợc phân tích thiết kế hệ thống phần mềm theo lĩnh vực là một hƣớng đi mới và gần đây đƣợc ứng dụng rộng rãi. Thông qua luận văn tôi muốn tập trung nghiên cứu, xây dựng và phát triển một hệ thống quản lý tài khoản tập trung AMS sử dụng phân tích theo lĩnh vực DDD, cùng với việc chia hệ thống thành các nhiều các dịch vụ theo hƣớng Microservice đảm bảo cho khả năng phát triển mở rộng lâu dài. Một số điểm chính luận văn đã đạt đƣợc cụ thể nhƣ sau: - Nghiên cứu tổng quan các chiến lƣợc phân tích thiết kế phần mềm hiện nay. - Đề xuất về chiến lƣợc thiết kế hƣớng lĩnh vực và một số quy trình phát triển phần mềm theo hƣớng lĩnh vực. - Tìm hiểu mô hình phần mềm hƣớng dịch vụ Microservice, nền tảng framework Ruby on Rails. - Áp dụng vào bài toán quản lý tài khoản tập trung của trƣờng ĐH Dân lập Hải Phòng. - Xây dựng phần mềm AMS trên nền Ruby on Rails Một số hƣớng nghiên cứu tiếp theo có thể phát triển là: - Phát triển tiếp các dịch vụ sử dụng AMS - Hoàn thiện việc phân tích theo hƣớng lĩnh vực cho các dịch vụ quản lý trƣờng học.95 TÀI LIỆU THAM KHẢO Tiếng Anh: [1] Eric Evans (2003), “ Domain-Driven Design Tackling Complexity in the Heart of Software”, Addison-Wesley; ISBN: 0-321-12521-5 [2] Vaughn Vernon (2013), “Implementing Domain-Driven Design”, Addison-Wesley [3] Sam Ruby, Dave Thomas, David Heinemeier Hansson (2011), “Agile Web Development with Rails”, United States of America Tiếng Việt: [4] Lê Văn Phùng (2014), “Kỹ nghệ phần mềm”, tái bản lần 1 NXB Thông tin và truyền thông, Hà Nội. [5] Lê Văn Phùng, Lê Hƣơng Giang (2013), “Kỹ nghệ phần mềm nâng cao”, NXB Thông tin và truyền thông, Hà Nội. [6] Lê Văn Phùng (2014), “Các mô hình cơ bản trong phân tích và thiết kế hướng đối tượng”, NXB Thông tin và truyền thông, Hà Nội. [7] Nguyễn Văn Vỵ, Nguyễn Việt Hà (2009), “Giáo trình kỹ nghệ phần mềm”, NXB Giáo dục Việt Nam Internet: [8] https://viblo.asia/nghiadd/posts/mrDGMOExkzL [9] https://vi.wikipedia.org/wiki/Domain_driven_design [10] https://www.railstutorial.org/book [11] http://www.vi.w3eacademy.com/cassandra/cassandra_introduction.htm [12] https://viblo.asia/nguyen.thi.phuong.mai/posts/l5XRBVZeRqPe [13] https://techmaster.vn/posts/33594/gioi-thieu-ve-microservices