Đề 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#

Luận văn thạc sĩ chuyên ngành khoa học máy tính CHƯƠNG I: KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN (REFACTORING) I.1 ĐỊNH NGHĨA KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN I.1.1 Ví dụ minh họa I.1.2 Định nghĩa kỹ thuật tái cấu trúc mã nguồn 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 I.2.2 Refactoring làm mã nguồn phần mềm dễ hiểu I.2.3 Refactoring giúp phát hiện và hạn chế lỗi I.2.4 Refactoring giúp đấy nhanh quá trình phát triển phần mềm I.3 KHI NÀO THỰC HIỆN TÁI CẤU TRÚC MÃ NGUỒN I.3.1 Refactor khi thêm chức năng I.3.2 Refactor khi cần sửa lỗi I.3.3 Refactor khi thực hiện duyệt chương trình I.4 CÁC KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN I.4.1 Danh mục các kỹ thuật tái cấu trúc mã nguồn I.5 NHẬN XÉT VÀ KẾT LUẬN CHƯƠNG II: LỖI CẤU TRÚC (BAD SMELLS) TRONG MÃ NGUỒN II.1 KHÁI NIỆM VỀ LỖI CẤU TRÚC (BAD SMELLS) II.2 LỖI CẤU TRÚC VÀ GIẢI PHÁP CẢI TIẾN II.2.1 Duplicated Code - Trùng lặp mã II.2.2 Long Method – Phương thức phức tạp II.2.3 Large Class – Qui mô lớp lớn II.2.4 Long Parameter List - Danh sách tham số quá dài II.2.5 Divergent Change – Cấu trúc lớp ít có tính khả biến II.2.6 Shotgun Surgery – Lớp được thiết kế không hợp lý và bị phân rã II.2.7 Feature Envy – Phân bố phương thức giữa các lớp không hợp lý II.2.8 Data Clumps – Gôm cụm dữ liệu II.2.9 Primitive Obsession – Khả năng thể hiện dữ liệu của lớp bị hạn chế II.2.10 Switch Statements – Khối lệnh điều kiện rẽ hướng không hợp lý II.2.11 Lazy Class – Lớp được định nghĩa không cần thiết II.2.12 Speculative Generality – Cấu trúc bị thiết kế dư thừa II.2.13 Temporary Field – Lạm dụng thuộc tính tạm thời II.2.14 Message Chains –Chuỗi phương thức liên hoàn khó kiểm soát II.2.15 Middle Man – Quan hệ ủy quyền không hợp lý/logic II.2.16 Inapproprite Intimacy - Cấu trúc thành phần riêng không hợp lý II.2.17 Alternative Classes with Different Interfaces - Đặc tả lớp không rõ ràng II.2.18 Incomplete Library Class – Sử dụng thư viện lớp chưa được hòan chỉnh II.2.19 Data Class – Lớp dữ liệu độc lập II.2.20 Refused Bequest – Quan hệ kế thừa không hợp lý/logic II.2.21 Comments – Chú thích không cần thiết II.3 NHẬN XÉT VÀ KẾT LUẬN CHƯƠNG III: NỀN TẢNG .NET VÀ NGÔN NGỮ LẬP TRÌNH C# III.1 TỔNG QUAN VỀ NỀN TẢNG .NET III.1.1 Định nghĩa .NET III.1.2 Mục tiêu của .NET III.1.3 Dịch vụ của .NET III.1.4 Kiến trúc của .NET III.2 NGÔN NGỮ LẬP TRÌNH C# III.2.1 Tổng quan về ngôn ngữ lập trình C# III.2.2 Đặc trưng của các ngôn ngữ lập trình C# III.3 MÔI TRưỜNG PHÁT TRIỂN ỨNG DỤNG VISUAL STUDIO .NET CHƯƠNG IV: Ứ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# IV.1 GIẢI PHÁP VÀ CÔNG CỤ HỖ TRỢ REFACTOR IV.1.1 Đặc tả giải pháp triển khai 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 IV.1.3 Thử nghiệm minh họa các công cụ hỗ trợ refactor trong VS.Net IV.1.4 Nhận xét và đánh giá 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# 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ế IV.2.2 Phân tích và đánh giá kết quả thực hiện IV.3 NHẬN XÉT VÀ KẾT LUẬN CHƯƠNG V: KẾT LUẬN V.1 ĐÁNH GIÁ KẾT QUẢ CỦA ĐỀ TÀI V.2 PHẠM VI ỨNG DỤNG V.3 HƯỚNG PHÁT TRIỂN V.3.1 Triển khai áp dụng trên các ngôn ngữ khác V.3.2 Thử nghiệm xây dựng một refactoring tool tích hợp vào VS.NET

pdf99 trang | Chia sẻ: lvcdongnoi | Lượt xem: 2306 | Lượt tải: 0download
Bạn đang xem trước 20 trang tài liệu Đề 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#, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
chƣơng trình tiện ích do Xtreme Simplicity phát triển có khả năng tích hợp vào Visual Studio cho phép thực hiện một số chức năng refactoring trên mã nguồn chƣơng trình C#. C# Refactory for Visual Studio .NET cung cấp một số kỹ thuật refactoring: - Change Method Signature - Copy Class - Decompose Conditional - Encapsulate Field - Extract Class - Extract Interface - Extract Method - Extract Superclass - Extract Variable - Push Up Members - Rename Local Variable - Rename Member - Rename Parameter - Rename Type Hình 4.4: Màn hình trình chức năng refactor của C# Refactory for Visual Studio .NET 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 53 ♦ .NET Refactor for C# & VB.NET [12] .NET Refactor là một tiện ích do KnownDotNet phát triển, có khả năng tích hợp vào Visual Studio .NET để hỗ trợ một số kỹ thuật refactoring trên các mã nguồn của chƣơng trình C# và VB.NET: - Extract Expression to Function - Extract Method - Extract Interface - Extract Object - Extract Superclass - Insert Const or String - Promote Local Variables - Simlify Conditional - Stub New Method - Refactor Strings - Rename Local Variable - Rename Parameters - Reorder Variables - Replace Magic Number Hình 4.5: Màn hình trình chức năng refactor của .NET Refactor for C# & VB.NET 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 54 ♦ CodeIT.Once for .NET [8] CodeIT.Once for .NET là một trong các công cụ hỗ trợ phát triển phần mềm do vbCity.com và DevCity.Net phát triển. CodeIT.Once đƣợc tích hợp vào Visual Studio và cung cấp một số chức năng refactor trên mã nguồn 2 ngôn ngữ C# và VB.NET. Danh mục các kỹ thuật refactoring hỗ trợ trong CodeIT.Once for .NET: - Add Parameter - Convert Method To Property - Convert Property To Method - Decompose Conditional - Inline Variable - Introduce Constant - Encapsulate Field - Extract Interface - Extract Method - Move Class - Promote Local Variable to Parameter - Remove Parameters - Rename Fileds - Rename Local Variables - Rename Methods - Rename Parameters - Rename Types - Reorder Parameters Hình 4.6: Màn hình trình chức năng refactor của CodeIT.Once for .NET 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 55 ♦ JetBrains ReSharper [10] Tiện ích ReSharper đƣợc công ty phát triển giải pháp và công cụ phần mềm JetBrains xây dựng có khả năng tích hợp vào Visual Studio nhằm hỗ trợ các lập trình thực hiện refactoring trên các mã nguồn chƣơng trình C#, VB/ASP.Net và XML. Danh mục các kỹ thuật refactoring hỗ trợ trong JetBrains ReSharper: - Change Method Signature - Convert Abstract Class to Interface - Convert Anonymous to Named Type - Convert Extension Method to Plain Static - Convert Interface to Abstract Class - Convert Method to Property - Convert Property to Method - Convert Static to Extension Method - Encapsulate Field - Extract Class - Extract Superclass - Extract Interface - Extract Method - Inline Method - InlineVariable - Introduce Parameter - Introduce Variable - Pull Down Members - Pull Up Members - Rename - Replace Constructor with Factory Method Hình 4.7: Màn hình trình chức năng refactor của JetBrances ReShape 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 56 ♦ DevExpress Refactor!™ Pro [9] Danh mục các kỹ thuật refactoring hỗ trợ trong DevExpress Refactor!™ Pro: - Add to Interface - Combine Conditionals - Convert Method to Property - Convert Property to Method - Decompose Conditional - Decompose Parameter - Encapsulate Field - Extract Class - Extract Interface - Extract Method - Extract Property - Introduce Constant - Introduce Parameter - Introduce Variable - Promote Local Variable to Parameter - Simplify/Split Conditional - Simplify Expression - Rename - Remove Redundant Assignment - Remove Redundant Conditional - Reorder Parameters/Variables - Replace Temp with Query Hình 4.8: Màn hình trình chức năng refactor của DevExpress Refactor!™ Pro 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 57 IV.1.3 Thử nghiệm minh họa các công cụ hỗ trợ refactor trong VS.Net Dựa trên các chức năng refactoing trong các công cụ tiện ích đƣợc tích hợp vào Visual Studio .NET. Phần nội dung dƣới dây sẽ hiện thực minh họa việc áp dụng một số kỹ thuật refactoring trong việc dò tìm và cải tiến mã xấu trong mã nguồn chƣơng trình C#: - Change Signature - Convert Method to Property - Decompose/ Simplify Conditional - Encapsulate Field - Extract Interface - Extract Method - Inline Variable - Promote Local Variable to Parameter - Rename ♦ Change Signature Change Signature cho phép thực hiện việc thay đổi tính chất/đặc trƣng của một phƣơng thức: thêm mới, xóa bới, hoán đổi trật tự hoặc thay đổi kiểu các tham số cũng nhƣ kiểu trả về của phƣơng thức Xét đoạn chƣơng trình thực hiện phƣơng thức Add để giá trị của cộng 2 số nguyên: public class Calculator { public int Add(int number1, int number2) { return number1 + number2; } } Một trong những dấu hiệu có thể nhận biết và tái cấu trúc của đoạn chƣơng trình này là chuyển đối kiểu của tham số và trả về phƣơng thức từ kiểu int sang double để có phạm vi hoạt động rộng hơn. public class Calculator { public double Add(double number1, double number2) { return number1 + number2; } } 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 58 Hình 4.9: Màn hình minh họa kỹ thuật Change Signature trong JetBrains ReSharper Hình 4.10: Màn hình kết quả minh họa kỹ thuật Change Signature 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 59 ♦ Convert Method to Property Convert Method to Property cho phép chuyển đổi các phƣơng thức truy vấn (get) và thiết lập (set) trên một trƣờng dữ liệu thành các đặc tính của trƣờng dữ liệu đó trong lớp. Xét đoạn chƣơng trình có nội dung nhƣ sau: namespace RefactoringExamples { class Foo { static int x; public static int GetX() { return x; } public static void SetX(int value) { x = value; } public static void bar() { int myX = Foo.GetX(); Foo.GetX() = myX + 1; } } } Ta thấy rằng để truy xuất và gán giá trị cho biến x trong lớp Foo phải thông qua 2 hàm là SetX() và GetX() trông rất bất tiện và không tự nhiên. Bây giờ chúng ta sẽ có một cách đơn giản hơn là chuyển đổi các phƣơng thức trên sang tính chất properties của trƣờng dữ liệu x thông qua kỹ thuật Convert Method to Property Kết quả sau khi chuyển đổi sẽ nhƣ sau: namespace RefactoringExamples { class Foo { static int x; public static int X { get { return x; } set { x = value; } } public static void bar() { int myX = Foo.X; Foo.X = myX + 1; } } } Bây giờ chƣơng trình trông gọn gàng, dễ nhìn và tự nhiên hơn khi sử dụng. 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 60 Hình 4.11: Màn hình minh họa kỹ thuật Convert Method to Property của CodeIT.Once 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 61 Hình 4.12: Màn hình minh họa kỹ thuật Convert Method to Property của ReSharper Hình 4.13: Màn hình kết quả kỹ thuật Convert Method to Property 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 62 ♦ Decompose/Simplify Conditional Decompose/Simplify Conditional cho phép thực hiện việc chuyển đổi/đơn giản hóa một biểu thức phức tạp trong thân mệnh đề điều kiện if thành một phƣơng thức có kiểu trả về kiểu luận lý (đúng hoặc sai) public class SampleApp { public const string SummerStart = "6/1/2005 12:00:00 AM"; private const string SummerEnd = "8/31/2005 12:00:00 AM"; private static float _winterRate = 5.0; private static float _summerRate = 5.4; private static double CalculateCharge(int quantity) { int charge; System.DateTime chargeDate = System.DateTime.Now; if (System.DateTime.Compare(chargeDate, SummerStart) > 0 | System.DateTime.Compare(chargeDate, SummerEnd) < 0) { charge = quantity * _winterRate; } else { charge = quantity * _summerRate; } return charge; } } Kết quả sau khi biến đổi làm cho chƣơng trình rõ ràng hơn public class SampleApp { public const string SummerStart = "6/1/2005 12:00:00 AM"; private const string SummerEnd = "8/31/2005 12:00:00 AM"; private static float _winterRate = 5.0; private static float _summerRate = 5.4; private static double CalculateCharge(int quantity) { int charge; if (IsSummerDate()) { charge = quantity * _winterRate; } else { charge = quantity * _summerRate; } return charge; } private static IsSummerDate() { System.DateTime chargeDate = System.DateTime.Now; return (System.DateTime.Compare(chargeDate, SummerStart) > 0 | System.DateTime.Compare(chargeDate, SummerEnd) < 0); } } 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 63 Hình 4.14: Màn hình minh họa kỹ thuật Decompose/Simplify Conditional Hình 4.15: Màn hình kết quả kỹ thuật Decompose/Simplify Conditional 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 64 ♦ Encapsulate Field Encapsulate Field cho phép chuyển đổi và đóng gói các trƣờng dữ liệu trong lớp. Một chƣơng trình đƣợc thiết kế nhƣ sau: public struct MyPoint { public int x; public int y; public void SetLocation() { Console.Write("Enter X position: "); x = int.Parse(Console.ReadLine()); Console.Write("Enter Y position: "); y = int.Parse(Console.ReadLine()); } public void PrintLocation() { // Print new location. Console.WriteLine("[{0}, {1}]", x, y); } } Lỗi dễ nhận thấy nhất trong thiết kế này là các trƣờng dữ liệu x, y của cấu trúc MyPoint đƣợc khai báo dƣới dạng public thay vì nên đƣợc khai báo private để đảm bảo sự đóng gói cần thiết. Sử dụng kỹ thuật Encapsulate Field để tái cấu trúc mã nguồn chƣơng trình này public struct MyPoint { private int x; public int X { get { return x; } set { x = value; } } private int y; public int Y { get { return y; } set { y = value; } } public void SetLocation() { Console.Write("Enter X position: "); X = int.Parse(Console.ReadLine()); Console.Write("Enter Y position: "); Y = int.Parse(Console.ReadLine()); } public void PrintLocation() { // Print new location. Console.WriteLine("[{0}, {1}]", X, Y); } } 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 65 Hình 4.16: Màn hình minh họa kỹ thuật Encapsulate Field của Refactor trong VS.NET Ghi chú: Áp dụng trên cả 2 biến x và y 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 66 Hình 4.17: Màn hình minh họa kỹ thuật Encapsulate Field của Visual Assit X for .NET Hình 4.18: Màn hình kết quả kỹ thuật Encapsulate Field 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 67 ♦ Extract Interface Extract Interface cho phép định nghĩa một giao diện của lớp. Một đặc tính rất ling động của C# trong việc thay thế sự đa kế thừa. Một lớp đối tƣợng TwoDShape thể hiện các đặc tính hình vẽ trong môi trƣờng 2D đƣợc lập trình nhƣ sau: class TwoDShape { public void Draw() { /* Some interesting code. */ } public Rectangle GetBoundingRect() { /* More interesting code. */ } public Color GetArgb() { /* Even more interesting code. */ } } Trong trƣờng hợp này, chúng ta có thể sử dụng đặc tính Interface(giao diện) trong ngôn ngữ C# nhằm đảm bảo một sự ràng buộc, giao kết cho lớp phải thực hiện một số các phƣơng thức bắt buộc. Ở đây chúng ta sẽ định nghĩa một interface IRender cho lớp TwoDShape, lớp này sẽ có các phƣơng thức Draw(), GetBoundingRect(), GetArgb() đƣợc khai báo trong giao diện IRender class TwoDShape : IRender { public void Draw() { /* Some interesting code. */ } public Rectangle GetBoundingRect() { /* More interesting code. */ } public Color GetArgb() { /* Even more interesting code. */ } } interface IRender { void Draw(); Color GetArgb(); Rectangle GetBoundingRect(); } Ghi chú: Interface giống nhƣ một lớp chỉ chứa các phƣơng thức trừu tƣợng, và đƣợc sử dụng thay thế cho các lớp trừu tƣợng để tạo ra các sự ràng buộc giữa những lớp và các thành phần client của nó. 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 68 Hình 4.19: Màn hình minh họa kỹ thuật Extract Interface của Refactor trong VS.NET 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 69 Hình 4.20: Màn hình minh họa kỹ thuật Extract Interface của CodeIT.Once Hình 4.21: Màn hình kết quả kỹ thuật Extract Interface 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 70 ♦ Extract Method Extract Method cho phép định nghĩa một phƣơng thức mới dựa trên việc trích xuất một tập đoạn mã giúp cho nội dung mã nguồn rõ ràng và logic hơn. Xét đoạn chƣơng trình có nội dung nhƣ sau: namespace RefactoringExamples { class Program { static void Main(string[] args) { Console.WriteLine("*** Please enter your credentials ***"); // Get user name and password. string userName; string passWord; Console.Write("Enter User Name: "); userName = Console.ReadLine(); Console.Write("Enter Password: "); passWord = Console.ReadLine(); } } } Dấu hiệu nhận biết mã xấu ở đây là nội dung phƣơng thức Main dài dòng không cần thiết, đoạn lệnh mã nguồn thực thi việc đọc username và password nên đƣợc tách thành một phƣơng thức riêng. Khi đó chƣơng trình sẽ trở nên rõ ràng và có cấu trúc logic hơn. Áp dụng kỹ thuật Extract Method để tái cấu trúc mã nguồn cho kết quả nhƣ sau: namespace RefactoringExamples { class Program { static void Main(string[] args) { Console.WriteLine("*** Please enter your credentials ***"); // Get user name and password. string userName; string passWord; GetCredentials(out userName, out passWord); } private static void GetCredentials(out string userName, out string passWord) { Console.Write("Enter User Name: "); userName = Console.ReadLine(); Console.Write("Enter Password: "); passWord = Console.ReadLine(); } } } 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 71 Hình 4.22: Màn hình minh họa kỹ thuật Extract Method của Refactor trong VS.NET Hình 4.23: Màn hình kết quả kỹ thuật Extract Method 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 72 ♦ Inline Variable Inline Variable thực hiện việc thay thế một biến tạm bởi nội dung của biểu thức đƣợc gán cho biến đó trong thân chƣơng trình. Khi đó biến tạm đó đƣợc xóa đi. Xét đoạn chƣơng trình đƣợc cho dƣới đây: class Program { private static int _quantity = 5; private static double _itemPrice = 460; static void Main(string[] args) { double basePrice = _quantity * _itemPrice; if (basePrice > 1000) return basePrice * 0.95; else return basePrice * 0.98; } } Sử dụng Inline Variable để thay những nơi biến basePrice hiện diện trong thân chƣơng trình bởi biều thức đƣợc gán cho nó _quantity * _itemPrice. Lúc này ta có thể không xóa bỏ biến basePrice. class Program { private static int _quantity = 5; private static double _itemPrice = 460; static void Main(string[] args) { //double basePrice = _quantity * _itemPrice ; if ((_quantity * _itemPrice) > 1000) return (_quantity * _itemPrice) * 0.95; else return (_quantity * _itemPrice) * 0.98; } } } Ghi chú: Inline Variable là đối nghịch của Introduce Variable. Trong kỹ thuật lập trình, chúng ta thƣờng gặp các luật “bù - trừ”. Với trƣờng hợp này, việc xóa bỏ biến để thay bằng biểu thức nhằm cho chƣơng trình rõ ràng hơn và ít tốn bộ nhớ, tuy nhiên khi thực hiện chƣơng trình phải tính toán lại. Minh họa này cho ta thấy đƣợc tác động và ảnh hƣởng lẫn nhau giữa refactoring và hiệu năng xử lý. 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 73 Hình 4.24: Màn hình minh họa kỹ thuật Inline Variable của CodeIT.Once for .NET Hình 4.25: Màn hình kết quả kỹ thuật Inline Variable 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 74 ♦ Promote Local Variable to Parameter Promote Local Variable to Parameter thực hiện việc chuyển đổi biến cục bộ thành tham số truyền vào của phƣơng thức. Xét một chƣơng trình đƣợc cho có cấu trúc nhƣ sau: class Program { public static void ParseTextFile() { string fileToParse = @"C:\myFile.txt"; StreamReader sr = File.OpenText(fileToParse); // Start parsing using StreamReader... } static void Main(string[] args) { ParseTextFile(); } } Trong trƣờng hợp này, chúng ta có thể tái cấu trúc để chƣơng trình trên trở nên đơn giản và rõ ràng hơn bằng cách xóa bỏ biến cục bộ không cần thiết dùng để lƣu giá trị tên file filetoParse. 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 class Program { public static void ParseTextFile(string fileToParse) { StreamReader sr = File.OpenText(fileToParse); // Start parsing using StreamReader... } static void Main(string[] args) { ParseTextFile(@"C:\myFile.txt"); } } 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 75 Hình 4.26: Màn hình minh họa kỹ thuật Promote Local Variable to Parameter của VS.NET Hình 4.27: Màn hình minh họa kỹ thuật Promote Local Variable to Parameter của CodeIT.Once 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 76 Hình 4.28: Màn hình minh họa kỹ thuật Promote Local Variable to Parameter của JetBrains ReSharper Hình 4.29: Màn hình kết quả kỹ thuật Promote Local Variable to Parameter 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 77 ♦ Rename Variables Rename Variables thực hiện việc thay đổi tên của biến trong thân phƣơng thức hoặc chƣơng trình Cho một đoạn chƣơng trình có cấu trúc nhƣ sau: class Program { public static void ParseTextFile() { // Open file on local disk. string fileToParse = @"C:\myFile.txt"; StreamReader sr = File.OpenText(fileToParse); // Start parsing using StreamReader... } static void Main(string[] args) { ParseTextFile(); } } 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, chúng ta nên đổi tên biến sr thành strBuffer. Sử dụng kỹ thuật Rename Variables cho ta kết quả nhƣ sau: class Program { public static void ParseTextFile() { // Open file on local disk. string fileToParse = @"C:\myFile.txt"; StreamReader strBuffer = File.OpenText(fileToParse); // Start parsing using StreamReader... } static void Main(string[] args) { ParseTextFile(); } } 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 78 Hình 4.30: Màn hình minh họa kỹ thuật Rename Variables của Refactor trong VS.NET 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 79 Hình 4.31: Màn hình minh họa kỹ thuật Rename Variables của Visual Assit X for NET Hình 4.32: Màn hình kết quả kỹ thuật Rename Variables 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 80 IV.1.4 Nhận xét và đánh giá Qua quá trình thử nghiệm và đánh giá việc dò tìm và cải tiến mã xấu trong mã nguồn C# , ta có đƣợc bảng tóm lƣợc một số chức năng refactor trong các giải pháp/công cụ đƣợc tích hợp vào Visual Studio .NET nhƣ sau STT Kỹ thuật Refactoring R e fa c to r in V S 2 0 0 5 V is u a l A s s it X C # R e fa c to ry .N E T R e fa c to r C o d e IT .O n c e R e S h a rp e r R e fa c to r! ™ P ro 1 Add Member X 2 Add to Interface X 3 Change Signature X X X 4 Combine Conditionals X 5 Convert Abstract Class to Interface X 6 Convert Anonymous to Named Type X 7 Convert EXtension Method to Plain Static X 8 Convert Interface to Abstract Class X 9 Convert Method to Property X X X 10 Convert Property to Method X X X 11 Convert Static to EXtension Method X 12 Decompose/Simplify Conditional X X X X 13 Decompose Parameter X 14 Encapsulate Field X X X X X X 15 Extract Class X X 16 Extract Interface X X X X X X 17 Extract Method X X X X X X X 18 Extract Object X 19 Extract Property X X 20 Extract Superclass X X X 21 Extract Variable X 22 Generate Method Stub X 23 Inline Method X 24 Inline Variable X X 25 Insert Cont or String X 26 Introduce Constant X X 27 Introduce Variable X X 28 Move Class X 29 Promote Local Variable to Parameter X X X X X 30 Pull Down Members X 31 Pull Up Members X X 32 Simplify Expression X 33 Remove Redundant Assignment X 34 Remove Redundant Conditional X 35 Rename Variable/Method/Parameter/Type… X X X X X X 36 Reorder Parameters/Variables X X X X 37 Replace Constructor with Factory Method X 38 Replace Magic Number X 39 Replace Temp with Query X 40 Reverse Conditional X 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 81 Dựa vào bảng dữ liệu trên, ta thấy rằng hầu hết các kỹ thuật refactoring cơ bản đã đƣợc các hãng thứ ba phát triển và tích hợp trong các công cụ hỗ trợ lập trình và phát triển phần mềm. Việc triển khai đƣợc áp dụng trên nhiều công cụ khác nhau trên cùng một kỹ thuật xác định nhằm phân tích và đánh giá kết quả. Về tổng quan các chức năng đều hoạt động chính xác trên cơ sở lý thuyết kỹ thuật refactoring và có cùng chung kết quả, tuy nhiên vẫn có sự khác nhau về tính hiệu quả của từng công cụ tiện ích: - Số lƣợng các kỹ thuật refactoring mà công cụ hỗ trợ: CodeIT.Once, JetBrains ReSharper, Refactor!™ Pro hỗ trợ nhiều kỹ thuật hơn các công cụ còn lại - Hỗ trợ tính năng tùy biến trong quá trình thực hiện: Cùng thực hiện chức năng Promote Local Variable to Parameter nhƣng CodeIT.Once cho phép tùy biến đổi tên tham số khi thực hiện còn Refactor in VS.NET thì không (lấy tên biến làm tên tham số) - Mã nguồn ngôn ngữ có khả năng hỗ trợ: Refactor in VS.NET và Refactor!™ Pro hỗ trợ tất cả các ngôn ngữ thuộc họ .NET trong khi các công cụ còn lại chủ yếu chỉ là C# và VB.NET - Khả năng nhận biết mã xấu và tính tiện dụng: Khi đánh dấu chọn và áp dung refactor trên một biến trong thân chƣơng trình. Refactor in VS.NET hiển thị tất cả các chức năng hỗ trợ bao gồm cả Extract Interface (trên thực tế kỹ thuật này không hỗ trợ trong trƣờng hợp này và khi chọn thì hệ thống báo không hợp lệ), trong khi các công cụ khác CodeIT.Once, JetBrains ReSharper và Refactor!™ Pro có thể tự động nhận biết và chỉ kích hoạt cho phép chọn các chức năng hợp lệ (chức năng Extract Interface đã bị ẩn đi). Nhƣ vậy qua kết quả nghiên cứu và ứng dụng của đề tài này, chúng ta cũng đƣa ra một đề xuất dành cho các lập trình viên và nhà phát triển trong việc xác định và chọn lựa một công cụ refactoring có chất lƣợng tốt và tiện dụng trong quá trình phát triển phần mềm: CodeIT.Once, JetBrains ReSharper hoặc Refactor!™ Pro. 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# Trên cơ sở lý thuyết của kỹ thuật tái cấu trúc mã nguồn và dấu hiệu mã xấu đã đƣợc trình bày, nội dung phần này chúng ta sẽ áp dụng một trong những công cụ hỗ trợ rafactor đƣợc đề xuất (CodeIT.Once) để tiến hành triển khai việc dò tìm và cải tiến các đoạn mã xấu trên một chƣơng trình C# thực 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 82 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ế ♦ Yêu cầu bài tóan: Lập trình một chƣơng trình truy xuất và cập nhật dự liệu thông tin thời tiết của các đài khí tƣợng. Thông tin dữ liệu thời thiết bao gồm: vị trí khu vực, nhiệt độ và độ ẩm không khí tại khu vực đó. Các đài khác nhau có thể sử dụng các đơn vị đo khác nhau(ví dụ với nhiệt độ thì Hà Nội sử dụng độ C còn NewWork dùng độ F) ♦ Cấu trúc và mã nguồn chƣơng trình ban đầu Chƣơng trình đƣợc thiết kế và cấu trúc mã nguồn ban đầu nhƣ sau WeatherData _temp: int _humidity: int _location: int _stations: event WeatherStations() Get_Temp() Set_Temp () Get_Humidity() Set_Humidity Get_Location() HanoiWeat erStation _weather:WeatherData showWe t er() NewYorkWeatherStation _weather: WeatherData showWeather() 1 1 1 1 Hình 4.33: Sơ đồ lớp của chƣơng trình khi chƣa refactoring 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. using System; using System.Collections.Generic; using System.Text; namespace RefactoringExample { public delegate void WeatherUpdated(); class WeatherData { public int _temp; public int _humidity; public string _location; protected event WeatherUpdated _stations; public WeatherUpdated WeatherStations { get { return _stations; } set { _stations = value; } } public int Get_Temp() { return _temp; } public void Set_Temp (int temperature) { _temp = temperature; foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); } public int Get_Humidity() { return _humidity; } public void Set_Humidity(int weather_humidity) { 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 83 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. _humidity = weather_humidity; foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); } public string Get_Location() { return _location; } public WeatherData(string location, int temp,int humility) { _location = location; _temp = temp; _humidity = humility; } } class HanoiWeatherStation { protected WeatherData _weather; public HanoiWeatherStation(WeatherData weather) { _weather = weather; _weather.WeatherStations += new WeatherUpdated(showWeather); } protected void showWeather() { System.Console.WriteLine("Ha Noi Weather Station:"); System.Console.WriteLine("The weather at " + _weather.Get_Location()); System.Console.Write("Temperature: " + (_weather.Get_Temp() - 273) + "C, "); System.Console.WriteLine("Humidity: " + _weather.Get_Humidity() + "%\n"); } } class NewYorkWeatherStation { protected WeatherData _weather; public NewYorkWeatherStation(WeatherData weather) { _weather = weather; _weather.WeatherStations += new WeatherUpdated(showWeather); } protected void showWeather() { System.Console.WriteLine("New York Weather Station:"); System.Console.WriteLine("The weather at " + _weather. Get_Location()); System.Console.Write("Temperature:" + (((_weather. Get_Temp() - 273) * 9 / 5) + 32) + "F, "); System.Console.WriteLine("Humidity: " + _weather. Get_Humidity() + "%"); int outdoor_temperature = _weather. Get_Temp() - 273; int outdoor_humidity = _weather. Get_Humidity(); if (outdoor_temperature 50) System.Console.WriteLine("It may start to snow!"); System.Console.WriteLine("\n"); } } public class MainEntry { public static void Main() 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 84 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. { WeatherData weather = new WeatherData("Sa Pa", 283, 40); HanoiWeatherStation hanoi = new HanoiWeatherStation(weather); NewYorkWeatherStation newYork = new NewYorkWeatherStation(weather); System.Console.WriteLine("WEATHER FORCAST INFORMATION \n"); weather.Set_Temp(289); weather.Set_Humidity(60); weather.Set_Temp(273); System.Console.Read(); } } } Và khi chạy chƣơnng trình cho ra kết quả dƣới đây: Hình 4.34: Màn hình kết quả chạy chƣơng trình khi chƣa refactoring ♦ Tiến hành tái cấu trúc mã nguồn Đầu tiên xem sơ đồ lớp, ta thấy 2 lớp HanoiWeatherStation và NewYorkWeatherStation có chung thuộc tính (_weather) và phƣơng thức (showWeather). Trong trƣờng hợp này chúng ta nên sử dụng kỹ thuật Extract Hierarchy đề tái cấu trúc sơ đồ lớp này WeatherData ...... ....... HanoiWeatherStation showWeather() NewYorkWeatherStation showWeather() 1 WeatherStation _weather: WeatherData showWeather() 1 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 85 namespace RefactoringExample { …… class WeatherStation { protected WeatherData _weather; protected void showWeather() { } } class HanoiWeatherStation : WeatherStation { public HanoiWeatherStation(WeatherData weather) { ………… } public void showWeather() { ……………… } } class NewYorkWeatherStation : WeatherStation { public NewYorkWeatherStation(WeatherData weather) { ……………… } public void showWeather() { ………… } } ……… } Bƣớc tiếp theo ta thấy rằng nên đổi tên lớp WeatherData thành WeatherSensor cho hợp lý và chính xác hơn. Sử dụng kỹ thuật Rename Class trong tiện ích CodeIT.Once để thực hiện phép thay đổi này. 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 86 namespace RefactoringExample { …… class WeatherSensor { ……….. } class HanoiWeatherStation : WeatherStation { public HanoiWeatherStation(WeatherSersor weather) { ………… } public void showWeather() { ……………… } } class NewYorkWeatherStation : WeatherStation { public NewYorkWeatherStation(WeatherSensor weather) { ……………… } public void showWeather() { ………… } } public class MainEntry { public static void Main() { WeatherSensor weather = new WeatherSensor("Sa Pa", 283, 40); ……….. } } } Trong quá trình xem lại sự thay đổi của mã nguồn chƣơng trình sau khi đổi tên lớp WeatherData, ta phát hiện ra rằng việc sử dung tên trƣờng dữ liệu _temp để lƣu dữ liệu về nhiệt độ là không chính xác và dễ nhầm lẫn -> dùng kỹ thuật Rename Field để đổi tên trƣờng dữ liệu _temp thành _temparature 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 87 class WeatherSensor { public int _temperature; public int _humidity; ……… } Nhƣ vậy trong nhóm kỹ thuật Rename, ta đã tiến hành đổi tên lớp và trƣờng dữ liệu. Ta thấy rằng nội dung của phƣơng thức showWeather là hiển thị thông tin dữ liệu thời tiết của một khu vực nên đổi tên phƣơng thức này ShowWeatherInfo namespace RefactoringExample { ……… class WeatherStation { 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 88 ……. protected void ShowWeatherInfo() { } } class HanoiWeatherStation : WeatherStation { public HanoiWeatherStation(WeatherSensor weather) { ……… _weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo); } protected void ShowWeatherInfo() { ………. } } class NewYorkWeatherStation : WeatherStation { public NewYorkWeatherStation(WeatherSensor weather) { ………. _weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo); } protected void ShowWeatherInfo() { ………. } } } Các trƣờng dữ liệu _temperature, _humidity, _location trong lớp WeartherSensor đƣợc khai báo dƣới dạng public -> tiến hành đóng gói các trƣờng dữ liệu này thông qua kỹ thuật Encapsulate Field. Đồng thời xóa bỏ các phƣơng thức getting và setting trên các trƣờng dữ liệu này. namespace RefactoringExample { ……. class WeatherSensor 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 89 { private int _temperature; public int KelvinDegrees { get { return _temperature; } set { _temperature = value; foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); } } private int _humidity; public int Humidity { get { return _humidity; } set { _humidity = value; foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); } } private string _location; public string Location { get { return _location; } } ……….. } …….. class HanoiWeatherStation : WeatherStation { ……… protected void ShowWeatherInfo() { ……… System.Console.Write("Temperature: " + (_weather.KelvinDegrees - 273) + "C, "); System.Console.WriteLine("Humidity: " + _weather.Humidity + "%\n"); } } class NewYorkWeatherStation : WeatherStation { ……….. protected void ShowWeatherInfo() { ………… System.Console.Write("Temperature:" + (((_weather.KelvinDegrees - 273) * 9 / 5) + 32) + "F, "); System.Console.WriteLine("Humidity: " + _weather.Humidity + "%"); int outdoor_temperature = _weather.KelvinDegrees - 273; int outdoor_humidity = _weather.Humidity; ……….. } } public class MainEntry { 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 90 public static void Main() { ……… weather.KelvinDegrees = 289; weather.Humidity = 60; weather.KelvinDegrees = 273; System.Console.Read(); } } } Ta thấy rằng đọan mã nguồn foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); đƣợc lặp lại lần trong nội dung lớp WeatherSensor -> áp dụng kỹ thuật Extract Method để trích xuất nó ra làm một phƣơng thức riêng. public int KelvinDegrees { ………. set { _temperature = value; NotifyWeatherStations(); } } public int Humidity { ………… set { _humidity = value; NotifyWeatherStations(); } } private void NotifyWeatherStations() { foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); } 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 91 Trong phƣơng thức ShowWeatherInfo của lớp NewYorkWeatherStation có sử dụng 2 biến tạm outdoor_temperature, outdoor_humidity. Cách sử dụng này là không cần thiết -> Sữ dụng Remove Local Variable để xóa bỏ các biến này. ……. if ((_weather.KelvinDegrees - 273) 50) System.Console.WriteLine("It may start to snow!"); ……. Lúc này ta thấy cấu trúc chƣơng trình đã chặt chẽ và dễ hiểu hơn. Và đã đến lúc chúng ta tạm hài lòng với kết quả có đƣợc sau quá trình ứng dụng kỹ thuật tái cấu trúc mã nguồn và các công cụ hỗ trợ để cải tiến các đoạn mã xấu trong chƣơng trình ban đầu. ♦ Cấu trúc và mã nguồn chƣơng trình sau khi tái cấu trúc WeatherSensor _temperature: int _humidity: int _location: string _stations event KelvinDegrees() Humidity() Location() WeatherStations() NotifyWeatherStations() HanoiWeatherStation ShowWeatherInfo() NewYorkWeatherStation ShowWeatherInfo() 1 WeatherStation _weather: WeatherSensor ShowWeatherInfo() 1 Hình 4.35: Màn hình kết quả chạy chƣơng trình sau khi refactoring 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. using System; using System.Collections.Generic; using System.Text; namespace RefactoringExample { public delegate void WeatherUpdated(); class WeatherSensor { private int _temperature; public int KelvinDegrees { get { return _temperature; } set { _temperature = value; NotifyWeatherStations(); 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 92 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. } } private int _humidity; public int Humidity { get { return _humidity;} set { _humidity = value; NotifyWeatherStations(); } } private string _location; public string Location { get { return _location;} } protected event WeatherUpdated _stations; public WeatherUpdated WeatherStations { get { return _stations; } set { _stations = value; } } private void NotifyWeatherStations() { foreach (WeatherUpdated s in _stations.GetInvocationList()) s(); } public WeatherSensor(string location, int temp, int humility) { _location = location; _temperature = temp; _humidity = humility; } } class WeatherStation { protected WeatherSensor _weather; protected void ShowWeatherInfo(){} } class HanoiWeatherStation : WeatherStation { public HanoiWeatherStation(WeatherSensor weather) { _weather = weather; _weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo); } public void ShowWeatherInfo() { System.Console.WriteLine("Hanoi Weather Station:"); System.Console.WriteLine("The weather at " + _weather.Location); System.Console.Write("Temperature: " + (_weather.KelvinDegrees - 273) + "'C, "); System.Console.WriteLine("Humidity: " + _weather.Humidity +"%\n"); } } class NewYorkWeatherStation : WeatherStation 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 93 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. { public NewYorkWeatherStation(WeatherSensor weather) { _weather = weather; _weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo); } public void ShowWeatherInfo() { System.Console.WriteLine("New York Weather Station:"); System.Console.WriteLine("The weather at " + _weather.Location); System.Console.Write("Temperature:" + (((_weather.KelvinDegrees - 273) * 9 / 5) + 32) + "'F, "); System.Console.WriteLine("Humidity: " + _weather.Humidity + "%"); if ((_weather.KelvinDegrees - 273) 50) System.Console.WriteLine("It may start to snow!"); System.Console.WriteLine("\n"); } } public class MainEntry { public static void Main() { WeatherSensor weather = new WeatherSensor("Sa Pa", 283, 40); HanoiWeatherStation hanoi = new HanoiWeatherStation(weather); NewYorkWeatherStation newYork = new NewYorkWeatherStation(weather); weather.KelvinDegrees = 289; weather.Humidity = 60; weather.KelvinDegrees = 273; System.Console.Read(); } } } Và đây là kết quả thực thi của chƣơng trình sau khi đƣợc tái cấu trúc: Hình 4.36: Màn hình kết quả chạy chƣơng trình sau khi refactoring 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 94 Trong quá trình tái cấu trúc mã nguồn, mỗi khi áp dung xong một kỹ thuật chúng ta đều phải trải qua giai đọan kiểm thử và thực thi chƣơng trình với các bộ kiểm thử để đảm bảo rằng kết quả là đồng nhất. IV.2.2 Phân tích và đánh giá kết quả thực hiện Với chƣơng trình trên chúng ta đã sử dụng một số 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: - Extract Hierarchy - Rename Class - Rename Field - Rename Method - Encapsulate Field - Extract Method - Remove Local Variable Đối chiếu kết quả trƣớc và sau khi thực hiện, ta có đánh giá nhận xét nhƣ sau: ♦ Định tính: - Sau khi thực hiện tái cấu trúc, thiết kế lớp và cấu trúc chƣơng trình rõ ràng và chặt chẽ hơn - Các đoạn mã trùng lặp và biến tạm không cần thiết đã đƣợc loại bỏ - Các tên lớp, trƣờng dữ liệu và phƣơng thức trở nên hợp lý và dễ hiểu - Dữ liệu đƣợc đóng gói và an tòan hơn ♦ Định lƣợng: Ta có bảng số liệu thống kê về các thành phần khác nhau trƣớc và sau khi thực hiện tái cấu trúc mã nguồn nhƣ sau: Thành phần so sánh Áp dụng kỹ thuật tái cấu trúc mã nguồn Trước Sau Số dòng lệnh 102 106 Số lớp đối tượng 4 5 Số trường dữ liệu/thuộc tính lớp 6 5 Số phương thức 12 11 Số biến cục bộ sử dung 2 0 Trong 5 chỉ tiêu so sánh, ta thấy rằng có 3 chỉ tiêu đƣợc cải thiện (giảm) đó là: số lƣợng thuộc tính lớp, phƣơng thức và biến cục bộ. Về số dòng mã, có sự chênh lệch không đáng kể (4) nên có thể xem nhƣ là tƣơng đƣơng. Thành phần còn lại cần xét đến là sự thay đổi về số lƣợng lớp đối tƣợng. Ta thấy rằng với bài tóan nêu ra nhƣ trên, việc tạo mới một lớp dẫn xuất WeatherStation là cần thiết giúp cho cấu trúc các lớp đối tƣợng đƣợc rõ ràng và có sự đồng nhất(thuộc tính và hành vi xử lý). Việc tạo mới WeatherStation cũng làm cho chƣơng trình có dễ dàng thay đổikhi có yêu cầu bổ sung thên các đài khí tƣợng (tạo thêm lớp mới kế thừa từ lớp dẫn xuất WeatherStation. 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 95 IV.3 NHẬN XÉT VÀ KẾT LUẬN Trên cơ sở lý thuyết đã đƣợc nghiên cứu và trình bày, chúng ta đã đề xuất một giải pháp tổng thể trong việc áp dụng kỹ thuật tái cấu trúc mã nguồn để triển khai xây dựng công cụ hỗ trợ việc dò tìm và cải tiến các đoạn mã xấu trong mã nguồn C#. Đồng thời tiến hành thử nghiệm và ứng dụng các công cụ hỗ trợ refactor hiện có để dò tìm và tái cấu trúc các đoạn mã xấu trên một chƣơng trình C# thực tế. Kết quả triển khai trên chƣơng trình thực tế đã làm sáng tỏ và chứng minh những hiệu quả mà kỹ thuật tái cấu trúc mã nguồn mang lại trong việc cải thiện chất lƣợng chƣơng trình. Đó là: - Cấu trúc chƣơng trình trở nên rõ ràng và chặt chẽ hơn. - Tính khả biến của chƣơng trình đƣợc nâng cao (dễ thay đổi và cập nhật theo yêu cầu mới) - Hạn chế và tối thiểu hóa sự trùng lặp mã lệnh và dƣ thừa dữ liệu - Trong quá trình tái cấu trúc mã nguồn, cần thực hiện các bƣớc kiểm thử -> tăng khả năng kiểm sóat và phát hiện lỗi, đảm bảo chƣơng trình họat động chính xác khi triển khai sử dụng. - V.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 96 CHƢƠNG V: KẾT LUẬN V.1 ĐÁNH GIÁ KẾT QUẢ CỦA ĐỀ TÀI Qua quá trình nghiên cứu và triển khai ứng dụng kỹ thuật tái cấu trúc mã nguồn trong việc dò tìm và cải tiến các đoạn mã xấu trong chƣơng trình C#. Đề tài đã đạt đƣợc một số kết quả: - Nắm rõ cơ sở lý thuyết của kỹ thuật tái cấu trúc mã nguồn (refactoring) - Dấu hiệu nhận biết mã xấu trong chƣơng trình và các giải pháp cải tiến dựa trên kỹ thuật tái cấu trúc mã nguồn. - Tiếp cận và đề xuất giải pháp triển khai công cụ hỗ trợ chức năng refactor trong quá trình phát triển phần mềm. - Tìm hiểu và ứng dụng các công cụ hỗ trợ chức năng refactor hiện có đƣợc tích hợp trong môi trƣờng phát triển VS.NET để dò tìm và cải tiến các đọan mã xấu trong chƣơng trình C#. - Đánh giá hiệu quả của các công cụ hỗ trợ chức năng refactor hiện có -> đƣa ra khuyến cáo dành cho các nhà lập trình và phát triển phần mềm trong việc lựa chọn và sử dụng các công cụ hỗ trợ refactor phù hợp. - Bài báo công bố các kết quả nghiên cứu và ứng dụng của đề tài V.2 PHẠM VI ỨNG DỤNG Với những kết quả đã đạt đƣợc, đề tài có ý nghĩa thực tiễn trong lãnh vực nghiên cứu và ứng dụng các công nghệ mới của ngành công nghệ phần mềm tiên tiến. Đặc biệt là tiến trình chuẩn hóa các qui trình và kiểm thử phần mềm trong tƣơng lai. Đề tài có khả năng ứng dụng trong phạm vi và lãnh vực: - Triển khai ứng dụng kỹ thuật refactoring trong việc dò tìm và cải tiến các đọan mã xấu trong chƣơng trình C# cũng nhƣ các ngôn ngữ khác thuộc họ .NET - Tài liệu tham khảo dành cho các sinh viên chuyên nghành khoa học máy tính và lập trình viên trong vấn đề tìm hiểu và ứng dụng kỹ thuật tái cấu trúc mã nguồn. - Đề xuất giải pháp và khuyến cáo dành cho các nhà lập trình và phát triển phần mềm trong việc lựa chọn và sử dụng các công cụ hỗ trợ refactor phù hợp (trên các ngôn ngữ lập trình thuộc họ .NET) - Cơ sở lý thuyết cho việc xây dựng và triển khai các công cụ dò tìm các đoạn mã xấu dựa trên kỹ thuật tái cấu trúc mã nguồn cho các ngôn ngữ lập trình. 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 97 V.3 HƢỚNG PHÁT TRIỂN V.3.1 Triển khai áp dụng trên các ngôn ngữ khác Mở rộng triển khai áp dụng kỹ thuật tái cấu trúc mã nguồn cho các ngôn ngữ khác: C++, VB.NET, Java, Delphi,… Ví dụ: Triển khai kỹ thuật Promote Local Variable to Parameter trong đoạn chƣơng trình mã nguồn VB.NET Public Class SampleApp Private Const SummerStart As Date = #6/1/2005# Private Const SummerEnd As Date = #8/31/2005# Private Shared _winterRate As Double = 5.0 Private Shared _summerRate As Double = 5.4 Private Shared Function CalculateCharge(ByVal quantity As Integer) As Double Dim charge As Integer Dim chargeDate As Date = Date.Now If Date.Compare(chargeDate, SummerStart) > 0 Or _ Date.Compare(chargeDate, SummerEnd) < 0 Then charge = quantity * _winterRate Else charge = quantity * _summerRate End If Return charge End Function Public Shared Sub Main() Console.WriteLine("Charge: " + CalculateCharge(10).ToString()) End Sub End Class Kết quả sau khi refactor: Public Class SampleApp Private Const SummerStart As Date = #6/1/2005# Private Const SummerEnd As Date = #8/31/2005# Private Shared _winterRate As Double = 5.0 Private Shared _summerRate As Double = 5.4 Private Shared Function CalculateCharge(ByVal chargeDate As Date, ByVal quantity As Integer) As Double Dim charge As Integer If Date.Compare(chargeDate, SummerStart) > 0 Or _ Date.Compare(chargeDate, SummerEnd) < 0 Then charge = quantity * _winterRate Else charge = quantity * _summerRate End If Return charge End Function Public Shared Sub Main() Console.WriteLine("Charge: " + CalculateCharge(Date.Now, 10).ToString()) End Sub End Class V.3.2 Thử nghiệm xây dựng một refactoring tool tích hợp vào VS.NET 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 98 TÀI LIỆU THAM KHẢO Tiếng Việt [1] Phạm Văn Việt, Trƣơng Lập Vĩ. Tìm hiểu ngôn ngữ C# và viết một chƣơng trình minh họa. Đồ án tốt nghiệp – Khoa CNTT – ĐH KHTN TP.HCM, 2002. Tiếng nƣớc ngoài [2] Jesse Liberty. Programming C#. O‟Reilly, 2001 [3] Joseph W. Yoder. Refactoring Principles. University of Illinois, 2004 [4] Martin Fowler. Refactoring: Improving the design of existing code. Addison Wesley,1999. Trang web [5] Bad Smells in Code [6] Building a Refactoring Plug-in for VS.NET [7] C# Refactory - C# Refactoring tool. [8] CodeIT.Once for .NET [9] DevExpress Refactor!™ Pro [10] JetBrains ReSharper- Code Refactoring [11] Nhập môn Refactoring v.com.vn/UsolV.dotNetCenter.OfficialSite/TechnicalDocuments /An_Introduction_of_Refactoring/Default.htm [12] .NET Refactor for C# & VB.NET [13] Refactoring C# Code Using Visual Studio 2005 [14] Refactoring HomePage [15] The Future of Software Development [16] Visual Assit X for Visual Studio 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 99 Ý KIẾN NHẬN XÉT VÀ ĐÁNH GIÁ GV hƣớng dẫn: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Chủ tịch hội đồng xét duyệt: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Các file đính kèm theo tài liệu này:

  • pdfỨ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#.pdf