D) CÁC CÁCH BIỂU DIỄN CỦA MÔ HÌNH PHÂN TÍCH
b. Thiết kế hướng đối tượng
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 rã thành các đối tượng, mỗi đối tượng có nhsững thông tin trạng thái riêng của nó. Thiết kế hướng đối tượng là dựa trên việc che dấu thông tin, nhìn hệ thống phần mềm như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 hướng 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ó.
Mặc dù mới phát triển từ những năm 90 của thế kỷ XX nhưng đã có rất nhiều phương pháp phát triển hướng đối tượng ra đời. Một ngôn ngữ chuẩn như UML và nhiều công cụ mạnh (Jbuilder, Rational Rose) đã được phát triển để trợ giúp chophương pháp này.
6.1.4. Chất lượng thiết kế và các giải pháp đảm bảo chất lượng
Như đã đề cập ở trên, rất khó đểxác định được thế nào là thiết kế tốt, điều nàyphụ thuộc vào ứng dụng và vào yêu cầu dự án. Một thiết kế tốt phải là một thiết kế mà nó cho phép sản sinh
ra mã nguồnhữu hiệu; nó có thể là một thiết kế tối thiểu mà theo đó việc thực hiệncàng chặt chẽ càng tốt; hoặc nó là thiết kế bảo dưỡng được tốt nhất hay chỉ là tiêu chuẩn tốt cho người dùng. Một thiết kế bảo dưỡng tốt có thể thích nghi với việc thay đổi hoặc thêm các chức năng mới.
tất cả các bộ phận của nó đều phải tham gia vào việc thực hiện này. Nếu một thành phần không trực tiếp tham gia vào chức năng logicđó thì mức độ kết dính của nó là thấp.
Theo một số chuyên gia, có bảy mức kết dính theo thứ tự tăng dần sau đây:
- Kết dính gom góp (kết dính ngẫu nhiên): Các thành phần trong một module được nhóm
lại với nhau một cách ngẫu nhiên, không có tính logic (ví dụ: module bao gồm tất cả các chức năng; kho chứa dữ liệu được sử dụng bởi các thành phần khác nhau).
- Kết dính hội hợp logic:Các thành phần cùng thực hiện các chức năng tương tự chẳng hạn
như vào/ra dữ liệu, xử lý lỗi… được đặt vào cùng một thành phần.
- Kết dính theo thời điểm: Tất cả các thành phần cùng kích hoạt một lúc, chẳng hạn như
khởi sự và kết thúcđược bó lại với nhau.
- Kết dính thủ tục: Các phần tử trong thành phần được ghép lại trong một dãy điều khiển.
- Kết dính truyền thông: Tất cả các phần tử của thành phần cùng thao tác trên một dữ liệu vào và đưa cùng một dữ liệu ra.
- Kết dính tuần tự: Trong một thành phần, đầu ra của phần tử này là đầu vào của phần tử
khác.
- Kết dính chức năng: Mỗi phần của thành phần đều cần thiết để thi hành cùng một chức
năng nào đó.
Trong bảy mức độ kết dính nói trên, chỉ có mức độ kết dính cuối cùng là được khuyến khích sử dụng vì nhóm các thành phần được sử dụng cho một chức năng của hệ thống, mỗi thay đổi trong thành phần này kéo theo việc thay đổi và kiểm định lại các module thuộc các chức năng
khác có liên quan.
b. Sự ghép nối
Sự ghép nối (coupling) chỉ ra độ ghép nối giữa các đơn vị của chương trình. Hệ thống có ghép nối cao sẽ có độ ghép nối mạnh giữa các đơn vị, nói cách khác là các đơn vị phụ thuộc lẫn nhau. Hệ thống nối ghép lỏng lẻo làm cho các đơn vị là độc lập hoặc tương đối độc lập với nhau.
Sự ghép nối của một thành phần với các thành phần khác thể hiện bằng số lượng mối liên kết phụ thuộc giữa nó với các thành phần khác. Các module là được ghép nối chặt chẽ nếu chúng
dùng các biến chung và nếu chúng trao đổi các thông tin điều khiển (ghép nối chung nhau và ghép nối điều khiển). Ghép nối lỏng lẻo đạt được khi các thông tin biểu diễn được giữ trong thành phần này và chỉ giao tiếp với các thành phần khác thông qua danh sách tham số. Việc tối thiểu hóa sự ghép nối không phải lúc nào cũng thực hiện được. Dưới đây là các loại ghép nối được trình bày theo trình tự từ tốt đến xấu:
- Không có liên kết trực tiếp:Các module không có mối liên hệ trực tiếp với nhau, không có sựtrao đổi thông tin. Việc nâng cấp module này không ảnh hưởng tới module khác.
- Ghép nối dữ liệu:Hai module chỉ trao đổi các dữ liệu đơn giản (không có cấu trúc) và
thông qua giao diện. Ví dụ: một module gọi module khác thông qua các tham trị. Trong trường
- Ghép nối nhãn: Các module trao đổi dữ liệu dạng có cấu trúc thông qua giao diện (interface). Ví dụ trường hợp truyền các tham số. Trong trường hợp này, các module có thể thay đổi cấu trúc dữ liệu (thông qua việc khai báo kiểu). Khi thực hiện chương trình, nó có thể lưu các tham chiếu (con trỏ, địa chỉ đối tượng).
- Ghép nối điều khiển: Giao diện cho phép chi phối cách thực hiện bên trong module.
Trong trường hợp này, các module đưa ra các thông tin có liên quan đến module khác, hạn chế việc nâng cấp sửa đổi các module.
- Ghép nối mở rộng: Hai module trao đổi thông tin với nhau bởi các phần tử trung gian
của môi trường bên ngoài ứng dụng. Ví dụ: Hai ứng dụng trong hệ quản trị của trường học là đăng ký học và tính toán kết quả cần trao đổi thông tin qua người sử dụng trung gian (giáo viên, điểm thi). Trong trường hợp này, kênh trao đổi thông tin không được xác định, nó có thể bị bỏ sót trong quá trình nâng cấp.
- Ghép nối chung: Hai module dùng chung các biến toàn cục. Ví dụ như việc trao đổi
thông tin qua các biến toàn cục bằng cấu trúc COMMON trong ngôn ngữ Fortran, biến Public
trong Visual Basic. Càng nhiều biến toàn cục được sử dụng chung, càng khó nâng cấp cấu trúc.
- Ghép nối nội dung: Một module biết và mở rộng nội dung của một module khác (truy
cập vào các biến private, vào cấu trúc logic…). Ví dụ: Sử dụng các giá trị hằng số; khai thác thông tin không được công khai qua dữ liệu của giao diện (một module sử dụng kết quả của việc sắp xếp dữ liệu trong module khác). Trong trường hợp này, khi nội dung của module được triển khai, không thể mở rộnghoặcnâng cấp module.
c. Tính hiểu được
Tính hiểu được liên quan tới một số các đặc trưng thành phần sau đây:
- Tính kết dính: Có thể hiểu được thành phần đó mà không cần tham khảo đến một thành phần nào khác hay không?
- Đặt tên: Phải chăngmọi tên được dùng trong thành phần đó đều có nghĩa? Tên cónghĩa là những tên phản ánh cácthực thể trong thế giới thực được mô hình hóa bởi thành phần đó.
- Soạn tư liệu:Thành phần có được soạn thảo tư liệu sao cho ánh xạ giữa các thực thể của thế giới thực và thành phần đó là rõ ràng?
- Độ phức tạp: Độ phức tạp của các thuật toán được dùng để thực hiện thành phần đó như thế nào? Độ phức tạp cao ám chỉ nhiều quan hệ giữa các thành phần khác nhau của thành phần thiết kế và một cấutrúc logic phức tạp mà nó liên quanđến độ sâu lồng nhau của phát biểu. Các thành phần phức tạp là khó hiểu, vì thế người thiết kế nên làm cho thiết kế thành phần càng đơn
hỏi người đọc thiết kế phải nhìn nhiều lớp đối tượng khác nhau trong cây thừa kế thì độ dễ hiểu của thiết kế là được rút gọn.
d. Sự thích nghi được
Nếu một thiết kế nhằm tăng tính bảo trì thì nó phải sẵn sàng thích nghi được, nghĩa là các thành phần trong hệ thống được ghép nối với nhau một cách lỏng lẻo để khi có thay đổi hoặc bổ sung các thành phần mới thì các thành phần còn lại ít bị can thiệp nhất.
Bên cạnh đó, cũngphải soạn thảo tốt tài liệu thiết kế, dễ hiểu và đồng nhất với việc xây dựng phần mềm, có mối quan hệ rõ ràng giữa các mức khác nhau của thiết kế. Người đọc bản thiết kế có thể tìm được các biểu diễn liên quan trong lược đồ cấu trúc hay có thể thấy được sự biển đổi của dòng dữ liệu.
Cần phải luôn luôn kết hợp chặt chẽ những thay đổi thiết kế trong toàn bộ tư liệu thiết kế, nếu không tư liệu thiết kế đó có thể trở nên không nhất quán và những thay đổi tiếp sau là khó thực hiện.
e. Một số hướng dẫn thiết kế
- Linh hoạt đối với những yêu cầu thay đổi không định trước.
- Dễ thử nghiệm.
- Sáng sủa, dễ đọc.
- Kích thước module nhỏ.
- Tính độc lập module (tính mở/đóng giứa các module).
- Phải có mối quan hệ chặt chẽ giữa thiết kế và yêu cầu.
- Mỗi module hoàn toàn độc lập, thực hiện một chức năng duy nhất và thực hiện trọn vẹn chức năng đó.
- Mọi thứ trong module ràng buộc với nhau qua việc xử lý nối tiếp nhau trên cùng một dòng dữ liệu.
- Mọi thứ trong module được điều khiển bởi cùng một dữ liệu vào, hay cùng một phức hợp thiết bị, hay cùng thực hiện từng phần của cùng một kết xuất.
- Module có thể hiểu được hoàn toàn dựa vào những tham biến truyền và nhận từ nó.
- Khi thiết kế cố gắng giảm thiểu cấu trúc bằng việc tản ra nhiều ở độ sâu thấp và cố gắng co cụm khi chiều sâu tăng thêm (hình 6.4).
Hình 6.4. Hướng dẫn thiết kế tránh chia nhỏ module và cố gắng co cụm khi tăng chiều sâu
- Giữ phạm vi hiệu quả của một module bên trong phạm vi kiểm soát của module đó: + Phạm vi hiệu quả của module m được định nghĩa là tất cả các module khác bị ảnh hưởng bởi một quyết định thực hiện trong module m.
+ Phạm vi kiểm soát của module m là tất cả các module thuộc cấp của m (tính tới mức dưới cùng).
Hình 6.5. Phạm vi hiệu quả trong việc kiểm soát module
- Ước lượng giao diện module để giảm độ phức tạp, dư thừa và tăng tính nhất quán. - Xác định các module có chức năng dự kiến được.
- Cố gắng giữ các module một đầu vào và một đầu ra, tránh các "mối nối mang khả năng gây lỗi”.
6.2.1. Khái niệm –tầm quan trọng của thiết kế kiến trúc
a. Khái niệm
Kiến trúc phần mềm (software architecture) là một cấu trúc tổng thể của phần mềm, qua đó cung cấpsự tích hợp về mặt khái niệm của một hệ thống. Hiểu một cách đơn giản, kiến trúc là cấu trúc phân cấp của các thành phần chương trình, qua đó thể hiện sự tương tác giữa chúng với nhau và với cấu trúc dữ liệu mà chúng sử dụng. Theo nghĩa rộng, kiến trúc biểu diễn các thành phần lớn, cốt lõi của hệ thống và mối quan hệ giữa chúng với nhau được nhìn theo những quan điểm khác nhau.
b. Vai trò và tầm quan trọng của kiến trúc
Bass (Software Engineering, 8th Edition) và các đồng nghiệp đã thảo luận về những ưu điểm của việc thiết kếkiến trúc một cách rõ ràng và việc tài liệu hóa kiến trúc phần mềm:
- Là công cụ giao tiếp giữa những người có liên quan (Stackeholder communication):
Kiến trúc là một cách giới thiệu hệ thống ở mức cao, có thể sử dụng nó như một tiêu điểm thảo luận bởi các nhómkhác nhau có liên quan trong dự án.
- Phân tích hệ thống (System Analysis): Tạo ra một kiến trúc hệ thống rõ ràng ở giai đoạn đầu của quá trình phát triển hệ thống. Quyết định thiết kế hệ thống sẽ giúp ta đáp ứng tốt hơn những yêu cầu phi chức năng của hệ thống.
- Tái sử dụng ở quy mô lớn (Large-scale reuse): một mô hình kiến trúc hệ thống là một bản mô tả chắc chắn, dễ sử dụng về cách tổ chức hệ thống và sự tác động qua lại giữa các thành phần. Kiến trúc hệ thống của các hệ thống có yêu cầu tương tự thường giống nhau, vì vậy chúng ta có thể sử dụng lại phần lớn kiến trúc này.
Hofmeister (Software Engineering, 8th Edition) và các đồng nghiệp đã thảo luận về việc thiết kế kiến trúc trong giai đoạn thiết kế phần mềm để xem xét những khía cạnh thiết kế quan trọng trong giai đoạn đầu của tiến trình. Họ gợi ý rằng kiến trúc phần mềm có thể được sử dụng như một bản kế hoạch dự án, có thể dùng để đàm phán về những yêu cầu hệ thống và có thể dùng nó để thảo luận với khách hàng, những người phát triển hệ thống và các nhà quản lý. Họ cũng gợi ý rằng nó là một công cụ thiết yếu cho công việc quản lý phức tạp, bỏ qua sự chi tiết hóa và cho phép người thiết kế tập trung vào hệ thống ở mức trìu tượng.
c. Kiến trúc và đặc điểm của hệ thống
Kiến trúc hệ thống ảnh hưởng tới sự thực thi, tính hiệu quả, tính phân tán và bảo trì của hệ thống. Kiểu và cấu trúc được lựa chọn cho một ứng dụng cũng có thể phụ thuộc vào những yêu cầu phi chức năng của hệ thống:
- Tính hiệu năng (Performance): Nếu hiệu năng là một yêu cầu quan trọng đối với hệ thống thì kiến trúc nên được thiết kế để tập trung vào những chức năng quan trọng với một số lượng nhỏ những hệ thống con, giảm thiểu các mối liên lạc trao đổi thông tin có thể giữa những hệ thống con này. Điều này có nghĩa là nên sử dụng những thành phần lớn (large_grain) hơn là những thành phần nhỏ (fine_grain) để giảm sự tương tác qua lại giữa các thành phần.
- Tính bảo mật (security): Nếu bảo mật là một yêu cầu quan trọng, nên sử dụng kiến trúc phân tầng, như vậy những thông tin quan trọng nhất sẽ được bảo vệ trong tầng sâu nhất và việc
kiểm tra tính an toàn phải được tiến hành một cách chắc chắn đối với những tầng này.
- Tính an toàn (safety): Nếu an toàn là một yêu cầu quan trọng, hệ thống nên được thiết kế sao cho những chức năng đòi hỏi tính an toàn cao nằm tập trung trong một hệ thống con hoặc nằm trong một số ít những hệ thống con. Việc này sẽ giảm được chi phí và những vấn đề phát sinh trong việc thẩm định (validation) tính an toàn, đồng thời có thể giảm được chi phí để mua và bảo trì các công cụ bảo vệ có liên quan.
- Tính sẵn sàng (availability): Nếu tính sẵn sàng là một yêu cầu quan trọng, kiến trúc nên được thiết kế có nhiều thành phần dư thừa để nó có thể thay thế và cập nhật các thành phần mà
không cần phải dừng hệ thống.
- Tính bảo trì (maintainability): Nếu tính bảo trì là một yêu cầu quan trọng, kiến trúc hệ thống nên được thiết kế bằng việc sử dụng những thành phần nhỏ (fine_grain), những thành phần chứa chính nó (self-contained) có thể dễ dàng thay đổi. Nên sử dụng phương án chia dữ liệu theo khách hàng, chứ không nên phân chia theo cấu trúc dữ liệu.
Có thể nhận thấy sự xung đột trong các kiến trúc trên một cách rõ ràng. Ví dụ: sử dụng những thành phần kích thước lớn để tăng hiệu suất nhưng giảm tính bảo trì; đưa ra những dữ liệu dư thừa (dự trữ) để nâng cao tính sẵn sàng nhưng lại làm cho tính bảo mật khó kiểm soát hơn; tập trung vào những tính năng liên quan đến độ an toàn có nghĩa là tăng nhu cầu trao đổi thông tin, vì thế làm giảm hiệu suất của hệ thống. Nếu hai yếu tố mâu thuẫn nhau đều quan trọng với hệ thống thì cần phải có sự thỏa thuận để tìm ra giải pháp chung.
6.2.2. Các quyết định thiết kế kiến trúc
Thiết kế kiến trúc là một công việc sáng tạo, đòi hỏi phải đưa ra được một cách tổ chức hệ