(Post 26/03/2010) Phương thức phát triển phần mềm linh hoạt 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 hai kỹ thuật chính đó là refactoring (tái cấu trúc mã nguồn) và testing (kiểm thử).

Bài viết này giới thiệu tổng quan về kỹ thuật refactoring và ứng dụng trong việc cải tiến các đoạn mã xấu trong các ngôn ngữ lập trình hướng đối tượng hiện đại (.NET & Java) nhằm nâng cao chất lượng của phần mềm.

TỔNG QUAN VỀ REFACTORING

Định nghĩa

Có hai khái niệm khi tiếp cận thuật ngữ refactoring:

  • Sự thay đổi cấu trúc bên trong của phần mềm, làm cho phần mềm dễ hiểu và ít tốn chi phí khi cần thay đổi cập nhật nhưng không làm thay đổi các hành vi ứng xử bên ngoài.
  • Tái cấu trúc lại phần mềm thông qua việc áp dụng các bước cải tiến mà không làm thay đổi hành vi ứng xử bên ngoài.

Như vậy refactoring làm cho chương trình dễ đọc và khi cần thiết có thể cập nhật 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. Vì vậy phần mềm sẽ thực thi và xử lý các chức năng như trước mà người dùng không cảm nhận về những sự thay đổi này.

Hiệu quả của refactoring trong qui trình phát triển phần mềm

  • Cải thiện thiết kế phần mềm: Cấu trúc chương trình trở nên rõ ràng và logic. Đảm bảo những hạn chế thấp nhất trong quá trình phát triển và cập nhật
  • Mã nguồn phần mềm dễ hiểu và tinh gọn: chuẩn hóa trong việc lập trình và cực tiểu hóa dòng lệnh
  • Thuận lợi để phát hiện và hạn chế lỗi: Cấu trúc rõ ràng, dễ phát hiện lỗi (debugging)
  • Đẩ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 (khả năng dùng lại, tăng tính tiến hóa, gần gũi với người dùng,…)

Ngày nay refactoring là một tiêu chuẩn viết mã của mọi lập trình viên họ cần được huấn luyện để tuân thủ: như quy tắc đặt tên biến, khi viết mã nguồn áp dụng pattern nào, xây dựng unit test ra sao …

Refactoring và tối ưu hóa hiệu năng xử lý có điểm chung là chỉ thay đổi cấu trúc bên trong mà không làm thay đổi hành vi của các thành phần phần mềm. Tuy nhiên mục tiêu của chúng khác nhau, tối ưu hóa hiệu năng xử lý thường làm cho đoạn chương trình khó hiểu hơn, nhưng cần phải thực hiện để tăng tốc độ xử lý các tác vụ đặc biệt.

Khi nào cần thực hiện refactoring mã nguồn của một chương trình

Một lời khuyên từ các nhà phát triển phần mềm hiện đại là trong tất cả các trường hợp, chúng ta đều phải dành thời gian cho việc refactoring. Đây là công việc mà chúng ta phải thực hiện thường xuyên trong chu kì phát triển và bảo dưỡng phần mềm trong các tình huống:

  • Khi thêm chức năng mới
  • Trong quá trình kiểm tra và sửa lỗi (debugging)
  • Khi duyệt chương trình từ mã nguồn do người khác viết

Danh mục các kỹ thuật refactoring

STT

Kỹ thuật Refactoring
Diễn giải/Mục đích sử dụng
1Add ParameterBổ sung tham số cho phương thức
2Change SignatureThay đổi tính chất/đặc trưng của phương thức
3Change Value/Reference to Reference/ValueHoán chuyển qua lại giữa giá trị và tham chiếu
4Collapse HierarchyHợp nhất thành một lớp nếu 2 lớp cha và con (kế thừa) có ít sự khác biệt.
5Convert Method/ Property to Property/ MethodChuyển đổi qua lại giữa phương thức và đặc tính lớp
6Consolidate Conditional ExpressionTạ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
7Consolidate Duplicate Conditional FragmentsHợp nhất và di chuyển các đoạn trùng lặp ra bên ngoài thân câu lệnh điều kiện
8Decompose ConditionalTạo mới phương thức từ các câu điều kiện rẽ nhánh
9Duplicate Observed DataĐa hình dữ liệu
10Encapsulate FieldChuyển đổi thuộc tính chung thành riêng
11Extract Method/Class/ Interface/ HierarchyTrích xuất và định nghĩa mới phương thức/lớp/giao diện/quan hệ kế thừa
12Form Template MethodĐồng nhất các phương thức ở lớp con và dịch chuyển lên lớp cha
13Hide DelegateTạo các phương thức trung gian
14Inline Method/Temp/ClassHợp nhất các phương thức/biến tạm/lớp lại với nhau
15Introduce Foreign MethodTạ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.
16Introduce Explaining VariableThay thế kết quả của biểu thức hoặc một phần của biểu thức vào biến tạm.
17Introduce Local ExtensionTạ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
18Introduce Null ObjectThay thế giá trị Null bởi đối tượng Null
19Move Method/FieldDịch chuyển phương thức/thuộc tính giữa các lớp
20Promote Local Variable to ParameterChuyển biến cục bộ thành tham số của phương thức
21Push Down Field/MethodPhân rã thuộc tính/phương thức về lớp con
22Pull Up Field/MethodTổng quát hóa thuộc tính/phương thức lên lớp cha
23Remove Redundant Parameter/Field/ Conditional/Middle ManXóa bỏ các dữ liệu dư thừa(tham số của phương thức, thuộc tính lớp, điều kiện rẽ nhánh, phương thức trung gian)
24Rename Parameter/ Variable/ MethodĐổi tên tham số/ biến/ phương thức
25Replace Array with ObjectThay 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
26Replace Conditional with PolymorphismThay 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
27Replace Constructor with Factory MethodThay thế hàm dựng bởi phương thức sản xuất
28Replace Data Value with ObjectThay thế giá trị dữ liệu bằng đối tượng
29Replace Inheritance/Delegation with Delegation/ InheritanceHoán chuyển qua lại giữa tính chất kế thừa và ủy quyền giữa hai lớp
30Replace Magic Number with Symbolic ConstantSử dụng biến hằng thay cho giá trị số tường minh
31Replace Parameter with MethodRút gọn tham số trong phương thức
32Replace Record with Data ClassThay thế kiểu dữ liệu bảng ghi bởi lớp dữ liệu
33Replace Subclass with FieldsBiến đổi các phương thức ở các thuộc tính siêu lớp và rút gọn các lớp con
34Replace Temp with QueryChuyển đổi biểu thức thành phương thức.
35Split Temporary VariableTạo mới các biến tạm riêng biệt tương ứng với từng đoạn mã
36Self Encapsulate FieldTạo ra các phương thức dùng để truy xuất gián tiếp các thuộc tính.

MÃ XẤU VÀ GIẢI PHÁP CẢI TIẾN

Khái niệm về mã xấu

Mã xấu hay lỗi cấu trúc là những dấu hiệu tồn tại trong mã nguồn của chương trình tiềm ẩn khả năng xảy ra lỗi trong quá trình hoạt động. Các dấu hiệu có thể là: chương trình thiết kế không logic, các phân đoạn mã nguồn có cấu trúc không đồng nhất và khó hiểu, mã nguồn trùng lắp và dư thừa, tên hàm và biến khó kiểm soát, lớp và phương thức phức tạp…

Các mã xấu thường gặp và giải pháp cải tiến

Dựa trên kinh nghiệm nhiều năm lập trình và nghiên cứu về refactoring, hai chuyên gia Kent Beck và Marting Fowler đã đề xuất một tập các mã xấu thường gặp và giải pháp cải tiến dựa trên kỹ thuật refactoring.

STT

Đặc tả mã xấu
Kỹ thuật refactoring áp dụng
1Duplicated Code
(Trùng lặp mã)
Extract Method/Class, Pull Up Method, Form Template Method, Substitute Algorithm
2Long Method
(Phương thức phức tạp)
Extract Method, Replace Temp with Query, Introduce Parameter Object, Replace Method with Method Object, Decompose Conditional
3Large Class
(Qui mô lớp lớn)
Extract Class/SubClass, Extract Interface, Duplicate Observed Data
4Long Parameter List
(Danh sách tham số quá dài)
Replace Parameter with Method, Preserve Whole Object, Introduce Parameter Object
5Divergent Change
(Cấu trúc lớp ít có tính khả biến)
Extract Class
6Shotgun Surgery
(Thiết kế lớp không hợp lý và phân rã)
Move Method,Move Field, Inline Class
7Feature Envy
(Phân bố phương thức giữa các lớp không hợp lý)
Extract Method, Move Method
8Data Clumps
(Gom cụm dữ liệu)
Extract Class, Introduce Parameter Object, Preserve Whole Object
9Primitive Obsession
(Khả năng thể hiện của lớp bị hạn chế)
Replace Data Value with Object, Replace Type Code with Class, Replace Type Code with Subclasse, Introduce Parameter Object, Replace Array with Object
10Switch Statements
(Khối lệnh rẽ hướng không hợp lý)
Extract Method, Move Method, Replace Type Code with Subclasses/State/Strateg, Replace Conditional with Polymorphism, Replace Parameter with Explicit Methods, Introduce Null Object
11Lazy Class
(Lớp được định nghĩa không cần thiết)
Collapse Hierarchy, Inline Class
12Speculative Generality
(Cấu trúc bị thiết kế dư thừa)
Collapse Hierarchy, Inline Class, Remove Parameter, Rename Method
13Temporary Field
(Đặc tả các thuộc tính không cần thiết)
Extract Class, Introduce Null Object
14Message Chains
(Chuỗi phương thức liên hoàn khó kiểm soát)
Extract Method, Move Method
15Middle Man
(Quan hệ ủy quyền không hợp lý/logic)
Remove Middle Man, Inline Classs Replace Delegation with Inheritance,
16Inapproprite Intimacy
(Cấu trúc thành phần riêng không hợp lý)
Move Method, Move Field
17Alternative Classes with Different Interfaces (Đặc tả lớp không rõ ràng)Rename Method, Move Method
18Incomplete Library Class
(Thư viện lớp chưa được hoàn chỉnh)
Introduce Foregin Method, Introduce Local Extension
19Data Class
(Lớp dữ liệu độc lập)
Encapsulate Field, Encapsulate Collection, Remove Setting Method, Move Method, Extract Method, Hide Method
20Refused Bequest
(Quan hệ kế thừa không hợp lý/logic)
Push Down Method, Push Down Field, Replace Inheritance with Delegation
21Comments
(Chú thích không cần thiết)
 

Ví dụ minh họa

Ví dụ 1: Hai lớp con Salesman và Engineer đồng kế thừa từ lớp cha Employee có phương thức getName bị trùng lặp => Sử dụng Pull Up Method

Ví dụ 2: Sử dụng kỹ thuật Extract Method để làm ngắn phương thức bằng cách tạo ra một phương thức mới từ việc trích chọn một số đoạn mã từ phương thức ban đầu.

Ví dụ 3: Phương thức của một lớp (Class 1) sử dụng nhiều chức năng (thuộc tính và phương thức) của một lớp khác (Class 2) hơn chính nó thì sử dụng Move Method để dịch chuyển phương thức đó sang lớp kia.

Ví dụ 4: Sử dụng Replace Inheritance with Delegation để tái cấu trúc một quan hệ kế thừa.

Ví dụ 5: Sử dụng kỹ thuật Promote Local Variable to Parameter để thay thế một biến cục bộ thành tham số của một phương thức.

Ví dụ 6: Một trong những nguyên tắc trong lập trình để chương trình trở nên sáng sủa và dễ hiểu là cách đặt tên biến sao cho dễ nhớ và đặc tả được mục đích sử dụng biến. Trong trường hợp này, nên dùng kỹ thuật Rename Variables để đổi tên biến sr thành strBuffer.

GIẢI PHÁP VÀ CÔNG CỤ HỖ TRỢ RERACTORING

Kịch bản giải pháp triển khai

Một kịch bản tổng thể cho việc triển khai xây dựng một tiện ích hỗ trợ kỹ thuật refactoring để dò tìm và cải tiến mã xấu có khả năng tích hợp trong các môi trường phát triển ứng dụng được đặc tả như sau:

Một số công cụ tiện ích hỗ trợ việc dò tìm và cải tiến mã xấu (plug-in)

STT
N.Ngữ hỗ trợ
Kỹ thuật refactoring áp dụng
1.NET
(C/C++, C#, VB/ASP.NET)
Refactor in Visual Studio 2003/2005
(http://msdn.microsoft.com/en-us/library/ms379618(VS.80).aspx)
2Visual Assit X for Visual Studio .NET
(http://www.wholetomato.com/default.asp)
3C# Refactory for Visual Studio .NET
(http://www.xtreme-simplicity.net/index.cfm?PageID=3)
4.NET Refactoring for C# & VB.NET
(http://www.knowdotnet.com/articles/netrefactorproducthome.html)
5CodeIT.Once for .NET
(http://submain.com/products/codeit.once.aspx)
6JetBrains ReSharper
(http://www.jetbrains.com/resharper/)
7DevExpress Refactor!™ Pro
(http://www.devexpress.com/Products/Visual_Studio_Add-in/Refactoring/)
8JustCode!
(http://www.omnicore.com/en/justcode.htm)
9JavaJetBrains IntelliJ IDE
(http://www.jetbrains.com/idea/index.html)
10Elipse IDE for Java Developers
(http://www.eclipse.org/)
11JRefactory
(http://jrefactory.sourceforge.net/)
12JBuilder
(http://www.codegear.com/products/jbuilder)

Nhiêu Lập Hòa

Tài liệu tham khảo:

  • Joseph W. Yoder. Refactoring Principles. University of Illinois, 2004
  • Martin Fowler. Refactoring: Improving the design of existing code. Addison Wesley,1999.
  • Bad Smells in Code
  • Refactoring HomePage
  • The Future of Software Development

(theo PC World VN)

FPT Aptech trực thuộc Tổ chức Giáo dục FPT có hơn 25 năm kinh nghiệm đào tạo lập trình viên quốc tế tại Việt Nam, và luôn là sự lựa chọn ưu tiên của các sinh viên và nhà tuyển dụng.
0981578920
icons8-exercise-96