ứng dụng kỹ thuật tái cấu trúc mã nguồn để triển khai dò tìm và cải tiến các đoạn - Pdf 76

BỘ GIÁO DỤC VÀ ĐÀO TẠO
ĐẠI HỌC ĐÀ NẴNG
        
BÁO CÁO
LUẬN VĂN THẠC SĨ KỸ THUẬT
NGÀNH KHOA HỌC MÁY TÍNH

TÊN ĐỀ TÀI:

ỨNG DỤNG KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN ĐỂ
TRIỂN KHAI DÒ TÌM VÀ CẢI TIẾN CÁC ĐOẠN
MÃ XẤU TRONG CHƢƠNG TRÌNH C#
Họ tên HV : NHIÊU LẬP HÒA
Họ tên CBHD : TS.NGUYỄN THANH BÌNH
I.1 ĐỊNH NGHĨA KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN ................................ 7
I.1.1 Ví dụ minh họa................................................................................................. 7
I.1.2 Định nghĩa kỹ thuật tái cấu trúc mã nguồn ................................................... 19
I.2 HIỆU QUẢ CỦA TÁI CẤU TRÚC MÃ NGUỒN ................................................ 20
I.2.1 Refactoring cải thiện thiết kế phần mềm ....................................................... 20
I.2.2 Refactoring làm mã nguồn phần mềm dễ hiểu .............................................. 20
I.2.3 Refactoring giúp phát hiện và hạn chế lỗi ..................................................... 21
I.2.4 Refactoring giúp đấy nhanh quá trình phát triển phần mềm ......................... 21
I.3 KHI NÀO THỰC HIỆN TÁI CẤU TRÚC MÃ NGUỒN ..................................... 22
I.3.1 Refactor khi thêm chức năng ......................................................................... 22
I.3.2 Refactor khi cần sửa lỗi ................................................................................ 22
I.3.3 Refactor khi thực hiện duyệt chƣơng trình ................................................... 23
I.4 CÁC KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN .............................................. 23
I.4.1 Danh mục các kỹ thuật tái cấu trúc mã nguồn ............................................... 23
I.5 NHẬN XÉT VÀ KẾT LUẬN ................................................................................ 26

CHƢƠNG II: LỖI CẤU TRÚC (BAD SMELLS) TRONG MÃ NGUỒN ................... 27
II.1 KHÁI NIỆM VỀ LỖI CẤU TRÚC (BAD SMELLS) ........................................ 27
II.2 LỖI CẤU TRÚC VÀ GIẢI PHÁP CẢI TIẾN ..................................................... 27
II.2.1 Duplicated Code - Trùng lặp mã ................................................................. 27
II.2.2 Long Method – Phƣơng thức phức tạp ......................................................... 28
II.2.3 Large Class – Qui mô lớp lớn ...................................................................... 30
II.2.4 Long Parameter List - Danh sách tham số quá dài ....................................... 31
II.2.5 Divergent Change – Cấu trúc lớp ít có tính khả biến .................................. 32
II.2.6 Shotgun Surgery – Lớp đƣợc thiết kế không hợp lý và bị phân rã ............ 32
II.2.7 Feature Envy – Phân bố phƣơng thức giữa các lớp không hợp lý .............. 33
II.2.8 Data Clumps – Gôm cụm dữ liệu ................................................................ 34
II.2.9 Primitive Obsession – Khả năng thể hiện dữ liệu của lớp bị hạn chế ......... 34
II.2.10 Switch Statements – Khối lệnh điều kiện rẽ hƣớng không hợp lý ........... 36
II.2.11 Lazy Class – Lớp đƣợc định nghĩa không cần thiết .................................. 38

IV.1.2 Một số công cụ và tiện ích hỗ trợ việc dò tìm và cải tiến mã xấu ............. 50
IV.1.3 Thử nghiệm minh họa các công cụ hỗ trợ refactor trong VS.Net .............. 57
IV.1.4 Nhận xét và đánh giá .................................................................................. 80
IV.2 ỨNG DỤNG KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN ĐỂ DÒ TÌM VÀ
CẢI TIẾN CÁC ĐOẠN MÃ XẤU TRONG CHƢƠNG TRÌNH C#.......................... 81
IV.2.1 Thực hiện kỹ thuật tái cấu trúc mã nguồn trên chƣơng trình thực tế ......... 82
IV.2.2 Phân tích và đánh giá kết quả thực hiện .................................................... 94
IV.3 NHẬN XÉT VÀ KẾT LUẬN ............................................................................ 95

CHƢƠNG V: KẾT LUẬN ............................................................... 96
V.1 ĐÁNH GIÁ KẾT QUẢ CỦA ĐỀ TÀI ............................................................... 96
V.2 PHẠM VI ỨNG DỤNG .................................................................................... 96
V.3 HƢỚNG PHÁT TRIỂN ...................................................................................... 97
V.3.1 Triển khai áp dụng trên các ngôn ngữ khác ................................................ 97
V.3.2 Thử nghiệm xây dựng một refactoring tool tích hợp vào VS.NET ........... 97

TÀI LIỆU THAM KHẢO ................................................................................................. 98 Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
5
DANH MỤC HÌNH ẢNH

Tên hình ảnh Trang
H.3.1: Kiến trúc nền tảng .NET 46
H.3.2: Môi trường phát triển ứng dụng VS.NET 48
H.4.1: Đặc tả kịch bản giải pháp triển khai 49
H.4.2: Trình chức năng refactor tích hợp trong VS.NET 50
H.4.3: Trình chức năng refactor của Visual Assit X for VS.NET 51

H.4.34: Màn hình kết quả chạy chương trình khi chưa refactoring 84
H.4.35: Sơ đồ lớp của chương trình sau khi refactoring 91
H.4.36: Màn hình kết quả chạy chương trình sau khi refactoring 93
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
6
MỞ ĐẦU

Trong qui trình phát triển phần mềm hiện nay, một thực tế đang tồn tại ở các công
ty sản xuất phần mềm là các lập trình viên thƣờng xem nhẹ việc tinh chỉnh mã nguồn và
kiểm thử. Ngoài lý do đơn giản vì đó là một công việc nhàm chán, khó đƣợc chấp nhận
đối với việc quản lý vì sự tốn kém và mất thời gian, còn một nguyên nhân khác là chúng
ta không có những phƣơng pháp và tiện ích tốt hỗ trợ cho những việc này. Điều này dẫn
đến việc phần lớn các phần mềm không đƣợc kiểm thử đầy đủ và phát hành với các nguy
cơ lỗi tiềm ẩn.
Phƣơng thức phát triển phần mềm linh hoạt[15] bắt đầu xuất hiện vào đầu những
năm 90 với mục tiêu là phần mềm phải có khả năng biến đổi, phát triển và tiến hóa theo
thời gian mà không cần phải làm lại từ đầu. Phƣơng thức này đƣợc thực hiện dựa trên hai
kỹ thuật chính là tái cấu trúc mã nguồn (refactoring) và kiểm thử (developer testing). Vì
thế việc nghiên cứu và ứng dụng kỹ thuật tái cấu trúc mã nguồn nhằm tối ƣu hóa mã
nguồn và nâng cao hiệu quả kiểm thử là một nhu cầu cần thiết trong quá trình thực hiện
và phát triển phần mềm.
Đề tài “Ứng dụng kỹ thuật tái cấu trúc mã nguồn để triển khai dò tìm và cải
tiến các đoạn mã xấu trong chƣơng trình C#” đƣợc thực hiện với mục đích nghiên cứu
cơ sở lý thuyết kỹ thuật tái cấu trúc mã nguồn và áp dụng để triển khai việc dò tìm và cải
tiến mã xấu (lỗi cấu trúc) trong các chƣơng trình hiện đại và phổ biến hiện nay (C#).
Toàn bộ nội dung của luận văn bao gồm các chƣơng:
Chƣơng 1: Kỹ thuật tái cấu trúc mã nguồn (refectoring)
Chƣơng 2: Mã xấu (bad smells) và giải pháp cải tiến dựa trên refactoring
Chƣơng 3: Nền tảng .NET và ngôn ngữ lập trình C#

this.maxNumber = maxNumber;
}

public int[] GetPrimeNumbers() { // Use Eratosthenes's sieve
bool[] numbers = new bool[maxNumber + 1];
for (int i = 0; i < numbers.Length; ++i){
umbers[i] = true;
}
int j = 2;
while (j <= (int)Math.Sqrt(maxNumber) + 1) {
for (int k = j + j; k <= maxNumber; k += j){
numbers[k] = false;
}
j++;
while (!numbers[j]) {
j++;
if (j > maxNumber) break;
}
}
}

Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
8
List<int> l = new List<int>();
for (int k = 2; k <= maxNumber; ++k) {
if (numbers[k]) l.Add(k);
}
return l.ToArray();
}

}
}
return true;
}

Ta nhận thấy rằng phƣơng thức này quá dài, và nó xử lý rất nhiều công việc khác
nhau. Trong trƣờng hợp này, nên sử dụng kĩ thuật “Extract Method” trong các kĩ thuật
refactoring nhằm tạo ra các phƣơng thức nhỏ hơn, dễ đọc và dễ bảo trì khi có yêu cầu
thay đổi chƣơng trình.
Với đoạn mã nguồn khởi tạo list các số ban đầu ( list A ):

Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
9
bool[] numbers = new bool[maxNumber + 1];

for (int i = 0; i < numbers.Length; ++i){
numbers[i] = true;
}

Ta nên trích xuất nó thành một phƣơng thức khác, sử dụng “Extract Method”.

public int[] GetPrimeNumbers() {
bool[] numbers = InitialNumbers();
// Other codes.
}

private bool[] InitialNumbers(){
bool[] numbers = new bool[maxNumber + 1];
for (int i = 0; i < numbers.Length; ++i){

if (numbers[k]) l.Add(k);
}
return l.ToArray();
}

Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
10
Bây giờ chúng ta sẽ tinh chỉnh ở phần mã nguồn còn lại, đó là vòng lặp while

int j = 2;
while (j <= (int)Math.Sqrt(maxNumber) + 1){
for (int k = j + j; k <= maxNumber; k += j){
numbers[k] = false;
}
j++;
while (!numbers[j]){
j++;
if (j > maxNumber) break;
}
}

Với đoạn mã nguồn trên, câu lệnh if là không cần thiết, ta có thể bỏ đi, đƣa điều kiện lên
vòng while nhƣ sau:

int j = 2;
while (j <= (int)Math.Sqrt(maxNumber) + 1) {
for (int k = j + j; k <= maxNumber; k += j) {
numbers[k] = false;
}

Với đoạn mã nguồn

for (int i = 2; i * j <= maxNumber; i++) {
numbers[i * j] = false;
}

Thực hiện việc xóa bỏ các bội số của các số nguyên tố. Do đó, có thể tách chúng ra thành
một phƣơng thức. Kết quả thu đƣợc là:

public int[] GetPrimeNumbers() {
bool[] numbers = InitialNumbers();
for (int j = 2; j <= (int)Math.Sqrt(maxNumber) + 1; j++) {
if (!numbers[j]) continue;
RemoveMultiple(numbers, j);
}
return GetPrimeNumbersArray(numbers);
}

private void RemoveMultiple(bool[] numbers, int j) {
for (int i = 2; i * j <= maxNumber; i++) {
numbers[i * j] = false;
}
}

Tiếp tục với đoạn mã nguồn

private void RemoveMultiple(bool[] numbers, int j) {
for (int i = 2; i * j <= maxNumber; i++) {
numbers[i * j] = false;
}

this.maxNumber = maxNumber;
}

public int[] GetPrimeNumbers() {
bool[] numbers = InitialNumbers(); // Other codes.
}

// Other codes
private bool[] InitialNumbers() {
bool[] numbers = new bool[maxNumber + 1];
for (int i = 0; i < numbers.Length; ++i) {
numbers[i] = true;
}
return numbers;
}
}

Sẽ đƣợc chỉnh sửa thành

public class PrimeNumbersGetter {
private int maxNumber;
private bool[] numbers;

public PrimeNumbersGetter(int maxNumber) {
this.maxNumber = maxNumber;
this.numbers = new bool[maxNumber + 1];
for (int i = 0; i < numbers.Length; ++i) {
numbers[i] = true;
}
}

}
return GetPrimeNumbersArray();
}

private void RemoveMultiple(int number){
for (int i = 2; i * number <= maxNumber; i++) {
numbers[i * number - 2] = false;
}
}

private int[] GetPrimeNumbersArray() {
List<int> l = new List<int>();
for (int k = 2; k <= maxNumber; ++k) {
if (numbers[k - 2]) l.Add(k);
}
return l.ToArray();
}

Với phƣơng thức

private void RemoveMultiple(int number) {
for (int i = 2; i * number <= maxNumber; i++) {
numbers[i * number - 2] = false;
}
}
mục đích của nó là loại bỏ các số không phải là số nguyên tố, ta nên tách nó ra với việc
thêm một phƣơng thức, và đặt tên theo đúng ý nghĩa của nó.
private void RemoveMultiple(int number) {
for (int i = 2; i * number <= maxNumber; i++) {
RemoveNumber(i * number);

// Use Eratosthenes's sieve
for (int j = 2; j <= (int)Math.Sqrt(maxNumber) + 1; j++){
if (!Remains(j)) continue;
RemoveMultiple(j);
}
return GetPrimeNumbersArray();
}

private void RemoveMultiple(int number){
for (int i = 2; i * number <= maxNumber; i++) {
RemoveNumber(i * number);
}
}

private bool Remains(int number) {
return numbers[number - 2];
}

private void RemoveNumber(int number) {
numbers[number - 2] = false;
}
private int[] GetPrimeNumbersArray() {
List<int> l = new List<int>();

for (int k = 2; k <= maxNumber; ++k) {
if (Remains(k)) l.Add(k);
}
return l.ToArray();
}
}

}
}

internal class Sieve {
private int maxNumber;
private BitArray numbers;

internal Sieve(int maxNumber) {
this.maxNumber = maxNumber;
this.numbers = new BitArray(maxNumber - 1, true);
}

internal bool Remains(int number) {
return numbers[number - 2];
}
internal void RemoveNumber(int number) {
numbers[number - 2] = false;
}

internal int[] GetPrimeNumbersArray() {
List<int> l = new List<int>();

for (int k = 2; k <= maxNumber; ++k) {
if (Remains(k)) l.Add(k);
}
}
return l.ToArray();
}

Luận văn tốt nghiệp cao học – Khóa 2005 - 2008

if (!sieve.Remains(j)) continue;
RemoveMultiple(sieve, j);
}
return sieve.GetPrimeNumbersArray();
}

private void RemoveMultiple(Sieve sieve, int number) {
for (int i = 2; i * j <= maxNumber; i++) {
sieve.RemoveNumber(i * number);
}
}
}

Ta xem xét đoạn mã nguồn sau:

for (int j = 2; j <= (int)Math.Sqrt(maxNumber) + 1; j++) {
if (!sieve.Remains(j)) continue;
RemoveMultiple(sieve, j);
}

Công việc của đoạn mã nguồn là tìm các phần tử là số nguyên tố đầu tiên, sau đó
loại bỏ đi các bội số của chúng trong list A ban đầu. Ta tạo ra method
GetRemainNumbers() có chứa các số nguyên tố đầu tiên. Ta nghĩ tới việc dùng foreach
để duyệt các phần tử trong GetRemainNumbers(). Muốn sử dụng foreach thì
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
17
GetRemainNumbers() phải đƣợc cài đặt interface IEnumerable và sử dụng câu lệnh yield
return. Kết quả nhƣ sau:
public int[] GetPrimeNumbers() {

}

private IEnumerable<int> GetRemainNumbers() {
for (int k = 2; k <= maxNumber; ++k) {
if (Remains(k)) yield return k;
}
}

Trong quá trình refactor, việc đặt lại tên biến cần đƣợc chú ý, bởi vì bản thân tên
biến có thể coi nhƣ là một lời comment hiệu quả nhất nói lên công việc của đoạn mã
nguồn.Ví dụ phƣơng thức sau:

private void RemoveMultiple(Sieve sieve, int j) {
for (int i = 2; i * j <= maxNumber; i++){
sieve.RemoveNumber(i * j);
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
18
Ta nên đặt lại tên tham số truyền vào, biến j thành biến number

private void RemoveMultiple(Sieve sieve, int number) {
for (int i = 2; i * number <= maxNumber; i++) {
sieve.RemoveNumber(i * number);
}
}

Tƣơng tự nhƣ vậy, biến đếm k trong phƣơng thức GetRemainNumbers() cũng nên
chuyển thành biến đếm i.

private IEnumerable<int> GetRemainNumbers(Sieve sieve) {
for (int i = 2; i <= (int)Math.Sqrt(maxNumber) + 1; i++){
(sieve.Remains(i)) yield return i;
}
}

private void RemoveMultiple(Sieve sieve, int number) {
for (int i = 2; i * number <= maxNumber; i++) {
sieve.RemoveNumber(i * number);
}
}
}
internal class Sieve {
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
19
private int maxNumber;
private BitArray numbers;

internal Sieve(int maxNumber) {
this.maxNumber = maxNumber;
this.numbers = new BitArray(maxNumber - 1, true);
}

internal bool Remains(int number) {
return numbers[number - 2];
}

internal void RemoveNumber(int number) {
numbers[number - 2] = false;

Nhƣ vậy theo định nghĩa, mục tiêu đầu tiên của refactoring là làm cho chƣơng
trình dễ đọc và khi cần thiết có thể cập nhật thì vẫn không làm thay đổi hoặc có nhƣng
không đáng kể đến các hành vi ứng xử bên ngoài của phần mềm. Nhƣ vậy có gì khác biệt
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
20
giữa refactoring và việc tối ƣu hiệu năng xử lý. Cũng giống nhƣ refactoring, tối ƣu hiệu
năng xử lý không làm thay đổi hành vi của các thành phần nghĩa là chỉ thay đổi cấu trúc
bên trong. Tuy nhiên mục tiêu chúng khác nhau. Tối ƣu vận hành thƣờng làm cho đoạn
chƣơng trình khó hiểu hơn, nhƣng chúng ta cần phải thực hiện nó để tăng tốc độ chúng ta
cần.
Mục tiêu kế tiếp mà chúng ta cần lƣu ý đó là refactoring không làm thay đổi ứng
xử bên ngoài của phần mềm. Phần mềm sẽ thực thi và xử lý các chức năng nhƣ trƣớc.
Bất kỳ ngƣời dùng nào, kể cả ngƣời dùng cuối hay ngƣời lập trình không thể cảm nhận
về những sự thay đổi này.
I.2 HIỆU QUẢ CỦA TÁI CẤU TRÚC MÃ NGUỒN
I.2.1 Refactoring cải thiện thiết kế phần mềm
Thiết kế chƣơng trình luôn tìm ẩn nhiều rủi ro và dễ bị hƣ tổn. Khi có sự thay đổi
chƣơng trình (thay đổi hiện thực hóa mục tiêu ngắn hạn hay sự thay đổi không đƣợc hiểu
thấu đáo thiết kế chƣơng trình) thì khả năng chƣơng trình bị mất cấu trúc là hoàn toàn có
thể xảy ra. Khi việc mất cấu trúc chƣơng trình sẽ có tác động làm cho ngƣời phát triển
khó nhìn thấy thiết kế chƣơng trình, càng khó bảo trì và nhanh chóng bị hƣ tổn.
Trong quá trình thiết kế phầm mềm, nếu chúng ta áp dụng refactoring sẽ là một
giải pháp hiệu quả vì refactoring sẽ làm gọn chƣơng trình. Công việc này đƣợc thực hiện
nhằm mục đích chuyển đổi những gì thực sự không đúng chỗ về đúng vị trí. Đoạn
chƣơng trình đƣợc thiết kế hợp lý thƣờng chiếm nhiều dòng mã nguồn và khả năng trùng
lặp mã nguồn. Nhƣ vậy khía cạnh quan trọng của cải tiến thiết kế là loại bỏ những mã
nguồn lặp. Điều quan trọng của vấn đề này nằm ở những thay đổi tƣơng lai đoạn mã
nguồn. Bằng việc loại bỏ sự trùng lắp, đảm bảo rằng đoạn chƣơng trình chỉ làm một lần
và chỉ một là điều thiết yếu của thiết kế tốt. Khi đó phần mềm sẽ trở nên dễ hiểu và đảm

lỗi: „Tôi không là lập trình giỏi; tôi chỉ là lập trình tốt với thói quen .. Refacotring giúp
tôi trở nên hiệu quả trong viết chƣơng trình có độ chắc chắn”.
I.2.4 Refactoring giúp đấy nhanh quá trình phát triển phần mềm
Refactoring giúp đấy nhanh quá trình phát triển phần mềm thông qua các hiệu quả
mà nó mang lại:
- Tăng tính dùng lại: mã nguồn tốt, rõ ràng sẽ có lợi khi đƣợc sử dụng lại cho các
module khác của cùng ứng dụng hoặc đƣợc dùng nhƣ một bộ thƣ viện sử dụng
cho nhiều ứng dụng, module khác nhau.
- Tăng tính tiến hóa: một mã nguồn tốt có lợi ích và chu kỳ sống cụ thể do công
nghệ thông tin ngày càng phát triển. Mã nguồn tốt có thể có thời gian sử dụng lâu
hơn và khả năng tự phát triển, nâng cấp, kế thừa khi ứng dụng có nhu cầu phát
triển thêm mà không phải bị vứt bỏ để viết lại từ đầu.
- Tăng tính gần gũi với ngƣời dùng: có những ứng dụng hay nhƣng lại phức tạp
cho ngƣời sử dụng hay ngƣời đọc. Chẳng hạn nhƣ phần giao tiếp ngƣời dùng (user
interface) cần đƣợc cải thiện để tăng tính dễ dùng, dễ hiểu, linh hoạt hơn và làm
cho giao tiếp ngƣời dùng sử dụng đƣợc hết các khả năng của mã nguồn cung cấp.
Refactoring không hẳn làm thay đổi các cƣ xử, hoạt động bên ngài của phần mềm.
Chủ yếu là cải thiện phần cấu trúc bên trong nhằm làm tối ƣu chức năng của phần mềm
để phần mềm xử lý, nhanh hơn, tốt hơn, an toàn hơn và cố thể phù hợp với nhiều môi
trƣờng hoặc thay đổi mới cho ngƣời dùng trong quá trình sử dụng. Giảm thiểu những sai
sót và tăng thời gian sống cho phần mềm. Là một bƣớc không thể thiếu và có thể đƣợc áp
dụng trong suốt các quá trình phát triển phần mềm.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
22
Ngày nay Refactoring chính là một chuẩn mực coding của mọi lập trình viên khi
làm việc theo nhóm, khi bắt đầu làm việc ở công ty lớn, các lập trình viên sẽ đƣợc huấn
luyện và đào tạo để tuân thủ các yêu cầu làm việc: nhƣ quy tắc đặt tên biến, khi viết mã
nguồn áp dụng partern nào, xây dựng unit test ra sao ...
I.3 KHI NÀO THỰC HIỆN TÁI CẤU TRÚC MÃ NGUỒN

mã cần chỉnh sửa. Để làm đƣợc việc đó, chúng ta cần phải làm cho đoạn mã dễ đọc và
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
23
hiểu hơn. Nhƣ vậy trong quá trình sửa lỗi, chúng ta nhìn và phân tích đoạn mã nguồn để
hiểu và refactor để cải thiện sự hiểu biết của mình. Thông thƣờng chúng ta dự đoán qui
trình hoạt động của đoạn mã hiện tại để tìm lỗi. Tuy nhiên không phải lúc nào chúng ta
cũng có thể phát hiện ra lỗi từ mã nguồn vì nó không rõ đủ cho chúng ta nhìn ra có lỗi.
Một cách để nhìn vào vấn đề này đó là nếu chúng ta nhận đƣợc một báo cáo lỗi phát sinh,
đó là dấu hiệu chúng ta cần refactoring.
I.3.3 Refactor khi thực hiện duyệt chƣơng trình
Ngoài ra chúng ta còn sử dụng refactoring trong quá trình duyệt mã nguồn đƣợc
viết bởi ngƣời khác.Trong quá trình duyệt chƣơng trình, ngoài việc đọc hiểu và kiểm tra
tính chính xác của đoạn mã cũng nhƣ đề xuất các đề nghị. Khi đƣa ra ý kiến hoặc đề nghị
chúng ta xem xét hoặc chúng có thể thực hiện đƣợc dễ dàng hoặc phải refactoring. Nếu
vậy, tiến hành refactor. Khi thực hiện vài lần, chúng ta có thể nhìn thấy rõ ràng hơn
những gì đoạn mã nguồn trông giống khi thay thế. Kết quả là chúng ta có thể đạt đến ý
tƣởng ở mức hai đó là bạn không bao giờ nhận ra bạn không refactor.
I.4 CÁC KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN
Refactoring là một trong những phƣơng pháp nhằm nâng cao chất lƣợng phần
mềm đã bắt đầu đƣợc nghiên cứu và ứng dụng những năm 90 trong qui trình phát triển
phần mềm. Qua quá trình nghiên cứu và phát triển, một tập các kỹ thuật refactoring đã
đƣợc đặc tả chi tiết và phần lớn các kỹ thuật refactoring trên đã và đang dần đƣợc tích
hợp vào trong các công cụ phát triển phần mềm nhằm hỗ trợ cho các nhà phát triển trong
việc rút ngắn thời gian tạo nên các phần mềm có chất lƣợng cao và ổn định, đáp ứng tốt
các yêu cầu hoạt động của hiện tại và những thay đổi cần thiết trong tƣơng lai.
I.4.1 Danh mục các kỹ thuật tái cấu trúc mã nguồn
Dƣới đây là danh mục các kỹ thuật tái cấu trúc mã nguồn đƣợc liệt kê theo nhóm:
STT Kỹ thuật Refactoring Diễn giải/Mục đích sử dụng
Composing Methods – Định nghĩa phương thức

11 Move Field Hoán đổi/dịch chuyển thuộc tính giữa các lớp
12 Extract Class
Tạo một lớp mới và dịch chuyển các thuộc tính
và phương thức có liên quan từ lớp cũ sang
13 Inline Class
Hợp nhất các lớp riêng có quan hệ thành một
lớp chung
14 Hide Delegate
Tạo các phương thức trung gian truy cập gián
tiếp đến lớp khác
15 Remove Middle Man
Tường minh các phương thức truy cập ở mỗi
lớp (ngược với Hide Delegate)
16 Introduce Foreign Method
Tạo ra một phương thức trong một lớp client
có tham số là một đại diện của một lớp server.
17 Introduce Local Extension
Tạo một lớp mới chứa các phương thức mở
rộng đi kèm với một lớp con hoặc một lớp bao
Organizing Data – Tổ chức dữ liệu
18 Self Encapsulate Field
Tạo ra các phương thức truy xuất và thiết lập
giá trị các thuộc tính và sử dụng chúng thay vì
truy xuất trực tiếp.
19 Replace Data Value with Object Thay thế giá trị dữ liệu bằng đối tượng
20 Change Value to Reference Chuyển đổi giá trị thành tham chiếu
21 Change Reference to Value Chuyển đổi tham chiếu thành giá trị
22 Replace Array with Object
Thay thế mảng bởi đối tượng với phần tử của
mảng tương ứng với thuộc tính của đối tượng

lớp và rút gọn các lớp con
Simplifying Conditional Expressions – Đơn giản hóa các biểu thức điều kiện
34 Decompose Conditional
Tạo mới các phương thức từ mệnh đề và thân
xứ lý của câu lệnh điều kiện.
35 Consolidate Conditional Expression
Tạo mới một phương thức từ việc hợp nhất các
biểu thức điều kiện
36
Consolidate Duplicate Conditional
Fragments
Hợp nhất và di chuyển các phân đoạn trùng
lặp ra bên ngoài thân câu lệnh điều kiện
37 Remove Control Flag
Sử dụng câu lệnh break hoặc return thay thế
cho biến cờ hiệu trong các thân vòng lặp
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa
25
38
Replace Nested Conditional with
Guard Clauses
Thay thế các điều kiện rẽ nhánh bởi các mệnh
đề so khớp
39
Replace Conditional with
Polymorphism
Thay thế phép so sánh điều kiện bởi tính chất
đa hình của phương thức
40 Introduce Null Object Thay thế giá trị NULL bởi một đối tượng NULL

Thay thế hàm dựng bởi phương thức sản xuất
54 Encapsulate Downcast Định dạng kiểu trả về trong thân phương thức
55 Replace Error Code with Exception
Tạo mới một phương thức từ một phân đoạn
mã để kiểm soát các trường hợp (lỗi) ngoại lệ
56 Replace Exception with Test
Kiểm tra các trường hợp (lỗi) ngoại lệ có khả
năng phát sinh
Dealing with Generalization – Liên hệ tổng quát hóa
57 Pull Up Field Dịch chuyển thuộc tính lên lớp cha
58 Pull Up Method Dịch chuyển phương thức lên lớp cha
59 Pull Up Constructor Body
Tạo một hàm dựng chung ở lớp cha, và gọi lại
nó từ các phương thức ở lớp con.
60 Push Down Method Dịch chuyển phương thức về lớp con
61 Push Down Field Dịch chuyển thuộc tính về lớp con
62 Extract Subclass
Trích xuất/chia tách thành các lớp con với tập
các chức năng riêng
63 Extract Superclass
Định nghĩa mới một lớp cha và di chuyển các
chức năng chung đến lớp này từ các lớp con
64 Extract Interface
Định nghĩa một giao diện từ việc trích chọn
một tập con các thành viên trong lớp
65 Collapse Hierarchy
Hợp nhất thành một lớp nếu 2 lớp cha và con
(quan hệ kế thừa) có ít sự khác biệt.
66 Form Template Method
Đồng nhất các phương thức ở lớp con và dịch


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status