Nguyên tắc về cách hiểu
Có một vài ràng buộc khắt khe trong cách chúng ta hiểu về Tái Cấu Trúc. Đầu tiên, tái cấu trúc nghĩa là thay đổi hành vi bên trong của một phần mềm để phần mềm trở nên dễ hiểu và dễ sửa đổi hơn mà không phải thay đổi hành vi nhìn thấy từ bên ngoài.
Để rõ hơn, điều này có nghĩa là tái cấu trúc sẽ làm cho mã trở nên sạch hơn. Nếu bạn đã thực hành có chủ đích một vài kỹ thuật tái cấu trúc, bạn sẽ thấy chúng giúp bạn làm sạch mã một cách hiệu quả. Bạn biết có vấn đề gì, bạn biết phải làm gì, và bạn biết phải làm như thế nào. Nếu nhìn rộng ra, chúng ta có thể coi rằng chỉ những thay đổi nào không làm thay đổi hành vi của phần mềm nhưng lại làm cho phần mềm dễ hiểu và dễ sửa hơn mới được gọi là tái cấu trúc. Một ví dụ đối lập đó là các phép tối ưu hiệu năng, chúng không làm thay đổi hành vi của phần mềm, nhưng chúng thường làm cho mã trở nên khó hiểu hơn, tất nhiên bạn vẫn phải tối ưu hiệu năng, nhưng đó không gọi là tái cấu trúc.
Một ý nữa để nhấn mạnh rằng tái cấu trúc không làm thay đổi hành vi của phần mềm. Phần mềm vẫn có cùng chức năng như trước. Và bất cứ người dùng nào cũng có thể nói rằng mọi chuyện vẫn như cũ. Điều này dẫn chúng ta đến với ẩn dụ của Kent Beck về hai chiếc mũ.
Hai chiếc mũ
Bạn phải luôn hiểu rằng khi thực hành tái cấu trúc, bạn phân biệt rành mạch hai hoạt động khác nhau: thêm chức năng, và tái cấu trúc. Khi bạn thêm chức năng, bạn không thay đổi mã hiện có; chỉ thêm khả năng mới mà thôi. Bạn làm việc đó bằng cách bổ sung kiểm thử và tập trung vượt qua kiểm thử. Khi bạn tái cấu trúc, bạn không thêm chức năng mới và tập trung vào tái cấu trúc. Bạn không bổ sung bất cứ kiểm thử nào (trừ khi bổ sung một phép thử còn thiếu); bạn chỉ thay đổi mã nguồn khi thực sự cần, để đáp ứng sự thay đổi từ giao diện mã nguồn.
Bạn sẽ đội lần lượt hai chiếc mũ và thường xuyên tráo đổi. Bạn thêm chức năng, và nhận ra rằng sẽ dễ hơn nếu tái cấu trúc một chút, vậy nên bản đổi mũ và tái cấu trúc. Một khi mã đã tốt hơn, bạn đổi mũ tiếp và bổ sung chức năng. Rồi lại đổi mũ tiếp và tái cấu trúc. Tất cả có thể diễn ra chỉ trong vòng mười phút, nhưng bạn phải luôn nhận thức rõ ràng mình đang đội chiếc mũ nào.
Nguyên tắc về động cơ
Tái cấu trúc không phải viên đạn bạc để giải quyết mọi vấn đề. Nó là một công cụ giá trị, nhưng cho những mục đích cụ thể.
Cải thiện thiết kế của phần mềm
Không thực hành tái cấu trúc, thiết kế của chương trình sẽ ngày càng xấu đi. Cứ mỗi khi mã nguồn được sửa đổi cho những mục đích ngắn hạn, mã sẽ dần mất đi kết cấu tổng thể. Sẽ ngày càng khó nhận ra được thiết kế đằng sau của mã, và như thế mọi chuyện càng tệ đi nhanh hơn. Tái cấu trúc giúp giỡ lại đôi chút. Tái cấu trúc thường xuyên sẽ giúp giữ cho mã nguồn được sắc sảo.
Những thiết kế tệ thường khiến mã trở nên dài dòng, bởi hay có những khối mã nhỏ lặp lại ở đâu đó. Và khử những mã lặp này là một trong những nhiệm vụ quan trọng của thiết kế. Khử mã lặp không giúp chương trình chạy nhanh hơn, bởi những thao tác của chương trình hầu như giữ nguyên. Nhưng càng nhiều mã thì càng khó sửa đổi mã. Mã cần phát ngôn mỗi thứ một lần và chỉ một lần. Nhiệm vụ của thiết kế, và trong trường hợp cải thiện thiết kế có sẵn thì tái cấu trúc chính là công cụ để thực hiện.
Khiến phần mềm trở nên dễ hiểu hơn
Lập trình, theo khía cạnh nào đó thì là đối thoại với máy tính. Bạn muốn máy tính làm điều gì đó, và máy tính cần làm đúng như thế. Ở chỗ trống giữa điều bạn muốn và điều sẽ diễn ra chính là mã nguồn. Nhưng không chỉ có máy tính, rồi sẽ có ai đó cũng đọc mã nguồn của bạn, để thực hiện một vài thay đổi cần thiết. Có khi đó mới là người đọc quan trọng nhất. Không ai lo lắng nếu máy tính phải chạy thêm vài vòng lặp, nhưng sẽ rất nhiều người quan tâm nếu ai đó mất cả tuần để thực hiện một thay đổi mà lẽ ra chỉ mất một giờ, nếu anh ta hiểu được mã nguồn của bạn.
Chúng ta có xu hướng viết để mã hoạt động được, mà quên nghĩ về những người đọc mã sau này. Tái cấu trúc là thao tác giúp bạn thay đổi nhịp điệu quen thuộc đó. Bạn tái cấu trúc một khối mã nguồn hoạt động tốt nhưng không được cấu trúc tốt. Bạn bỏ ra một chút thời gian, và mã nguồn trở nên rõ ý hơn, cứ như là mã nói lên chính ý bạn muốn nói.
Một khi mã nguồn đã rõ ràng hơn, bạn sẽ không còn phải chiến đấu để hiểu được các chi tiết vụn vặt, bạn sẽ dần nhìn ra được thiết kế và như thế làm cho mã sạch hơn đã trở thành nền tảng để bạn xây dựng nên kiến trúc tốt hơn.
Tái cấu trúc giúp dễ tầm lỗi hơn
Dĩ nhiên mã dễ hiểu hơn thì dễ tầm lỗi hơn, nhưng không phải bao giờ chúng ta cũng có mã sạch. Một vài người trong chúng ta có thể tìm ra lỗi giữa một “nùi” mã, một số khác thì không. Khi thực hành tái cấu trúc, chúng ta ngâm rất sâu vào ý nghĩa của mã cũng như cấu trúc của chương trình, và như thế lỗ hổng trong mã cứ như thể tự hiện lên trong tâm trí.
Tái cấu trúc giúp lập trình nhanh hơn
Tái cấu trúc giúp tăng chất lượng mã, cải thiện thiết kế, tăng tính dễ đọc, giảm lỗi. Chúng ta nghĩ gì mà lại cho rằng những điều đó không làm cho chúng ta viết mã nhanh hơn?
Lưu ý rằng một trong những điểm cộng lớn nhất của thiết kế tốt đó là giúp phát triển nhanh chóng. Với thiết kế tốt, bạn đi rất nhanh. Còn nếu không thì ngược lại, bạn sẽ dành thời gian đáng lẽ để phát triển tính năng mới hay cải thiện chất lượng cho công việc tìm và sửa lỗi. Thời gian bạn bỏ ra để sửa đổi mã sẽ ngày càng dài, chức năng mới sẽ ngày càng cần nhiều mã, ngày càng nhiều lỗi, ngày càng có nhiều bản vá và ngày càng cần nhiều thời gian để vá.
Thiết kế tốt giúp chúng ta giữ được tốc độ phát triển nhanh và ổn định. Tái cấu trúc giúp cải thiện thiết kế và giữ cho thiết kế không bị suy hại. Tái cấu trúc giúp chúng ta phát triển nhanh hơn.
Khi nào cần tái cấu trúc
Nhiều nhóm phát triển đặt một khung thời gian nhất định cho tái cấu trúc. Có thể là định kỳ hàng tháng, hàng quý, hay khi phát triển xong một cụm chức năng lớn. Đó không phải là chiến thuật tốt. Tái cấu trúc không nên được thực hiện vào một khung giờ bên lề. Nó nên được thực hiện mọi lúc, trong những ngăn xếp thời gian nhỏ. Chúng ta không quyết định tái cấu trúc, tái cấu trúc không phải là một mục tiêu. Bạn muốn làm một thứ gì đó, và tái cấu trúc giúp bạn làm thứ đó.
Quy tắc số ba
Đây là tên một quy tắc để ra quyết định khi nào cần tái cấu trúc. Lần đầu tiên bạn làm chức năng gì đó, bạn cứ làm thôi. Lần thứ hai bạn làm một thứ tương tự, bạn biết và bạn sợ mã lặp, nhưng bạn vẫn làm. Lần thứ ba bạn làm một thứ tương tự, đó là lúc bạn tái cấu trúc.
Tái cấu trúc khi thêm chức năng
Thời điểm tái cấu trúc thường gặp nhất là khi bổ sung chức năng vào phần mềm. Tái cấu trúc vào lúc này có thể giúp chúng ta hiểu thêm về mã của những gì cần phải sửa đổi. Bên cạnh việc bạn làm cho mã hiện có trở nên tốt hơn, bạn cũng làm cho chức năng bạn sắp viết thêm vào trở nên tốt hơn.
Đôi khi, bạn còn không thể thêm chức năng (một cách dễ dàng) nếu không tái cấu trúc, đó là bởi thiết kế hiện tại không sẵn sàng để thêm chức năng mới. Bạn sửa “lỗi” thiết kế đó bằng tái cấu trúc. Dĩ nhiên ai đó rồi sẽ tạ ơn bạn, nhưng trước mắt thì bạn thực hiện tái cấu trúc đó để khiến bởi vì đó là cách nhanh nhất và dễ nhất để bạn thực hiện được công việc của mình.
Tái cấu trúc khi sửa lỗi
Bạn cần tái cấu trúc khi thực hiện sửa lỗi, và phần lớn là để mã dễ hiểu hơn. Thông thường hoạt động đó khiến bạn nhanh chóng tìm được vấn đề. Cần nhớ rằng, sự hiện diện của lỗi là một dấu hiệu cho thấy bạn cần tái cấu trúc, bởi vì mã đã không đủ rõ ràng để ai đó có thể nhìn vào và phát hiện ra ngay vấn đề.
Tái cấu trúc khi review mã
Chúng ta nên thường xuyên review và nhờ người khác review mã. Review chéo giúp phát tán tri thức cho cả nhóm phát triển, giúp lập trình viên có kinh nghiệm truyền đạt tri thức cho những người non tay hơn, giúp mọi người hiểu thêm về nhiều khía cạnh các nhau trong hệ thống phần mềm. Không chỉ thế review cũng rất quan trọng để viết mã sạch. Mã nguồn của bạn dễ hiểu đối với bạn, nhưng nhóm của bạn thì không thấy thế. Đó là lẽ tự nhiên, và review tạo cơ hội để mọi người nảy ra những đề xuất hữu ích.
Khi review, trước tiên bạn đọc mã, cố gắng hiểu ý định của mã đó, và đưa ra gợi ý. Bạn đề nghị với tác giả của mã những gợi ý của mình, rằng có thể dễ đọc hơn ở chỗ này dễ triển khai hơn ở chỗ kia. Hãy thảo luận, và sau đó bạn hãy thực hiện những tái cấu trúc đã chốt. Làm như thế rồi thì ý định của mã nguồn sẽ hiển hiện trước mắt bạn, bạn không còn cần phải tưởng tượng nữa, điều đó có thể sẽ tạo điều kiện cho bạn đưa ra được những gợi ý ở tầm cao hơn, thứ mà bạn có thể sẽ không thể nghĩ ra được trước đó.
Bạn chỉ cần một nhóm hai người để review mã. Bạn bình phẩm và đưa ra gợi ý, hai bạn cùng đưa ra quyết định về những thay đổi có thể thực hiện. Và hai bạn cùng thực hiện.
Với những review phạm vi rộng, chúng ta có thể tổ chức một nhóm review lớn. Lúc này đọc mã nguồn một cách trực tiếp có thể không phải là cách tốt. Các lược đồ UML và các bản CRC sẽ hữu ích hơn. Chúng ta thực hiện review mã nguồn với cá nhân, và review thiết kế với nhóm.
Nói như thế nào với sếp
Đây là rào cản cuối cùng, làm thế nào để nói chuyện với sếp về tái cấu trúc. Nếu sếp của bạn quen thuộc với công việc phát triển thì trao đổi về vấn đề này sẽ không quá khó. Nếu sếp của bạn là người truy cầu chất lượng, bạn hãy đề xuất về hoạt động tái cấu trúc khi review mã. Khó vô số tài liệu, sách, nghiên cứu, kinh nghiệm… đều đã chỉ ra rằng review mã có tác dụng tốt thế nào trong việc giảm lỗi và tăng tốc độ phát triển. Điều đó sẽ có sức thuyết phục rất lớn với sếp của bạn.
Tất nhiên sẽ có những sếp nói rằng chúng ta còn có cả tiến độ và deadline nữa. Bác Bob có đưa ra một lời khuyên gây tranh cãi trong tình huống này: Thế thì bạn cứ yên lặng mà làm thôi!
Đây không phải là chống đối. Các nhà phát triển phần mềm là những chuyên gia trong nghành của mình. Công việc của chúng ta là xây dựng phần mềm một cách hiệu quả nhất có thể. Chúng ta có kinh nghiệm rằng tái cấu trúc là một công cụ hỗ trợ rất lớn trong việc tạo ra phần mềm chất lượng cao và nhanh chóng. Nếu chúng ta cần thực hiện chức năng mới, chúng ta biết rằng nếu tái cấu trúc trước rồi sau đó mới thêm chức năng sẽ nhanh hơn. Nễu cần sửa lỗi, chúng ta cần hiểu cách hoạt động — và tái cấu trúc cũng lại là cách nhanh nhất để thực hiện việc này. Sếp của chúng ta muốn chúng ta thực hiện công việc theo cách nhanh nhất có thể. Cách nhanh nhất là tái cấu trúc; thế nên chúng ta tái cấu trúc.