Nguyên lý thiết kế Package

Nếu tôi hỏi bạn: “tại sao phải phân loại các class vào các package” bạn có thể sẽ trả lời: “để dễ quản lý”. Tất nhiên câu trả lời này là đúng, nhưng chưa giúp ích được gì nhiều. Và câu chuyện của chúng ta sẽ còn kéo dài hơn thế.

Phân loại là công việc mà chúng ta rất hay làm trong đời sống. Ví dụ, một người giữ xe thường sắp xe ga, xe số riêng, ngoài mục đích dễ tìm xe còn mục đích kinh tế: xe ga đắt tiền nên sẽ cần phải để mắt hơn.

Công việc phát triển phần mềm cũng tương tự như vậy. Nhiệm vụ của package không phải là để dễ tìm class. Tất nhiên với package thì việc tìm class có thể tiện lợi hơn đôi chút nhưng nó không quá quan trọng, nhất là các IDE ngày nay đều hỗ trợ tìm class trong nháy mắt. Một phần mềm hạng trung khoảng trăm class đã có thể rất phức tạp. Sở dĩ chúng phức tạp vì chúng có những mối quan hệ phụ thuộc lẫn nhau. Kiểm soát tốt những sự phụ thuộc này là mục tiêu sống còn của phần mềm. Công việc này quả thực là rất khó khăn với một số lượng lớn class. Do đó, chúng ta cần gom class vào các package. Số lượng package hiển nhiên sẽ ít hơn rất nhiều so với số lượng class. Việc kiểm soát sự phụ thuộc giữa một số lượng ít các package rõ ràng là thuận tiện hơn. Hơn nữa nó cũng giúp chúng ta có một cái nhìn khái quát về tổng thể phần mềm hơn là đi sâu vào class, vì class là quá nhỏ, quá chi tiết.

Nhưng chia class vào package như thế nào cho hiệu quả?

Granularity. Mỗi package cần phải đủ nhỏ vì nếu nó quá to thì sẽ rất tội cho những package khác chỉ phụ thuộc vào một phần của nó.

Stability. Mỗi khi có sự thay đổi xảy ra thì số lượng package bị tác động càng ít càng tốt.

Uncle Bob đưa ra 6 nguyên lý để đảm bảo tính hiệu quả của việc chia class.

1. The Reuse/Release Equivalence Principle [Granularity]

The granule of reuse is the granule of release.

Một phần mềm tốt thì cần phải dễ reuse. Một người nào đó muốn reuse các class của chúng ta, nhưng vì các class này lại được đóng vào các package, cho nên người ấy sẽ phải phụ thuộc vào nguyên các package ấy. Số lượng các class dư thừa (đối với người ấy) cần phải ít nhất có thể. Lý tưởng là zero (equivalence). Đây chính là nội dung của nguyên lý Reuse/Release Equivalence.

2. The Common Reuse Principle [Granularity]

The classes in a component are reused together. If you reuse one of the classes in a component, you reuse them all.

Cái người mà đang muốn reuse các class của chúng ta, anh ấy muốn số lượng package phải phụ thuộc là ít nhất có thể. Dễ thấy, muốn đáp ứng điều này, chúng ta nên nhét những class muốn được reuse cùng nhau vào chung một package, càng nhiều càng tốt. Lý tưởng là package đầy ắp các class muốn reuse cùng nhau.

Chúng ta có thể thấy nguyên lý Reuse/Release Equivalence và Common Reuse liên quan với nhau rất chặt chẽ. Thỏa mãn được nguyên lý này sẽ thường kéo theo thỏa mãn nguyên lý kia.

Bạn có thể hỏi: “làm sao biết trước cái người đó là ai và anh ta muốn reuse các class nào?” Good question! Và câu trả lời là kinh nghiệm! Chỉ có kinh nghiệm mới giúp chúng ta lường trước được những kiểu cách reuse mà thôi.

3. The Common Closure Principle [Granularity]

The classes in a component should be closed together against the same kinds of changes. A change that affects a component affects all the classes in that component and no other components.

Bắt đầu từ nguyên lý này, chúng ta sẽ không nói về reuse nữa, mà sẽ nói về sự thay đổi. Một lần nữa, kinh nghiệm có vai trò tuyệt đối ở đây bởi chúng ta cần phải đoán trước những kiểu thay đổi có thể xảy ra. Đoán được chúng rồi, ta sẽ thiết kế package để khi có thay đổi xảy ra, thì số lượng package bị thay đổi là ít nhất có thể. Lý tưởng là một package cho mỗi một sự thay đổi.

Muốn làm được như thế, thì package cần phải Single Responsibility, như class vậy.

4. The Acyclic Dependencies Principle [Stability]

Allow no cycles in the component dependency graph.

Nguyên lý này là hiển nhiên và tương tự như với class. Để xuất hiện một chu trình của những sự phụ thuộc là điều tối kị, vì một thay đổi ở một package sẽ kéo theo tất cả các package khác thuộc chu trình bị thay đổi theo.

5. The Stable-Dependencies Principle [Stability]

Depend in the direction of stability.

Một package hay biến động thì nên hạn chế để package khác phụ thuộc vào nó. Nói cách khác, các package nên phụ thuộc theo chiều hướng từ biến động tới ổn định.

6. The Stable-Abstractions Principle [Stability]

A component should be as abstract as it is stable.

Nguyên lý này thực chất là bổ trợ thêm cho nguyên lý 5. Một package ổn định thì nên có tính trừu tượng cao (chứa nhiều abstract class). Ngược lại, một package hay biến động thì không nên trừu tượng để có thể dễ thay đổi.

Tài liệu tham khảo:

  1. Granularity
  2. Stability
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s