Tôi có nên cấu trúc lại mã được đánh dấu là không thay đổi không?


148

Tôi đang làm việc với một cơ sở mã khá lớn và tôi đã được cho một vài tháng để cấu trúc lại mã hiện có. Quá trình tái cấu trúc là cần thiết bởi vì chúng tôi sẽ sớm cần thêm nhiều tính năng mới vào sản phẩm của mình và vì hiện tại chúng tôi không còn có thể thêm bất kỳ tính năng nào mà không phá vỡ thứ gì khác. Tóm lại: mã lộn xộn, khổng lồ, lỗi, mà nhiều người trong chúng ta đã thấy trong sự nghiệp của họ.

Trong quá trình tái cấu trúc, thỉnh thoảng tôi bắt gặp lớp, phương thức hoặc dòng mã có nhận xét như

Đã hết thời gian để cung cấp cho Mô-đun A một thời gian để làm công cụ. Nếu nó không đúng giờ như thế này, nó sẽ vỡ.

hoặc là

Đừng thay đổi điều này. Tin tôi đi, bạn sẽ phá vỡ mọi thứ.

hoặc là

Tôi biết sử dụng setTimeout không phải là một cách thực hành tốt, nhưng trong trường hợp này tôi đã phải sử dụng nó

Câu hỏi của tôi là: tôi có nên cấu trúc lại mã khi gặp các cảnh báo như vậy từ các tác giả (không, tôi không thể liên lạc với các tác giả)?


157
Xin chúc mừng! Bây giờ bạn là tác giả của mã.

12
Bạn không thể sửa nó cho đến khi bạn biết cả những gì nó phải làm và những gì nó thực sự làm (bạn cần biết cái sau để hiểu toàn bộ hậu quả của những thay đổi của bạn.) Vấn đề dường như là đồng bộ hóa và loại bỏ những vấn đề như vậy nên tái cấu trúc công việc số 1, nếu không mọi thứ sẽ trở nên tồi tệ hơn với mỗi thay đổi. Câu hỏi bạn nên đặt ra là làm thế nào để làm điều đó. Có một số lượng khá lớn sự phụ thuộc ngôn ngữ và nền tảng trong câu hỏi đó. ví dụ: stackoverflow.com/questions/3099794/finding-threading-bugs
sdenham

14
Theo dõi nhận xét của @ sdenham: nếu bạn chưa có các bài kiểm tra đơn vị tự động thực hiện cơ sở mã của mình, tôi khuyên bạn nên dành thời gian để tạo các bài kiểm tra đơn vị đó, thay vì lãng phí thời gian vào "săn phù thủy tái cấu trúc" với AFAICT không có mục tiêu rõ ràng trong tâm trí. Khi bạn có một bộ kiểm tra đơn vị thực hiện triệt để cơ sở mã của bạn, bạn sẽ có một cách khách quan để biết liệu mã của bạn có còn hoạt động hay không khi / khi bạn phải viết lại các bit của nó. May mắn nhất.
Bob Jarvis

17
Nếu các tác giả hoang tưởng đến mức mã sẽ bị phá vỡ nếu ai đó thở quá gần, thì có lẽ nó đã bị phá vỡ và hành vi không xác định chỉ xảy ra theo cách họ muốn vào lúc này. Điều đầu tiên trong âm thanh cụ thể giống như họ đã có một điều kiện cuộc đua mà họ đã bị loại bỏ vì vậy hầu hết thời gian là công việc. sdenham có nó đúng. Tìm hiểu những gì nó phải làm và không cho rằng đó là những gì nó thực sự làm.
Ray

7
@Ethan Nó có thể không đơn giản. Thay đổi mã có thể phá vỡ nó theo những cách không rõ ràng ngay lập tức. Đôi khi nó bị hỏng rất lâu sau khi bạn quên rằng trình tái cấu trúc hiện tại này có thể đã gây ra nó, vì vậy tất cả những gì bạn có là một lỗi "mới" với nguyên nhân bí ẩn. Điều này đặc biệt có khả năng khi nó liên quan đến thời gian.
Paul Brinkley

Câu trả lời:


225

Có vẻ như bạn đang refactoring "chỉ trong trường hợp", mà không biết chính xác các bộ phận của codebase chi tiết sẽ được thay đổi khi sự phát triển tính năng mới sẽ diễn ra. Mặt khác, bạn sẽ biết nếu có nhu cầu thực sự để cấu trúc lại các mô-đun giòn, hoặc nếu bạn có thể để chúng như vậy.

Nói thẳng ra: tôi nghĩ đây là một chiến lược tái cấu trúc cam chịu . Bạn đang đầu tư thời gian và tiền bạc của công ty vào một thứ mà không ai biết liệu nó có thực sự mang lại lợi ích hay không, và bạn đang ở bên cạnh làm cho mọi thứ tồi tệ hơn bằng cách đưa lỗi vào mã làm việc.

Đây là một chiến lược tốt hơn: sử dụng thời gian của bạn để

  • thêm kiểm tra tự động (có thể không phải kiểm tra đơn vị, nhưng kiểm tra tích hợp) vào các mô-đun có nguy cơ. Đặc biệt là những mô-đun dễ vỡ mà bạn đề cập sẽ cần một bộ kiểm tra đầy đủ trước khi bạn thay đổi bất cứ điều gì trong đó.

  • chỉ cấu trúc lại các bit bạn cần để đưa các bài kiểm tra vào vị trí. Cố gắng giảm thiểu bất kỳ thay đổi cần thiết. Ngoại lệ duy nhất là khi các bài kiểm tra của bạn phát hiện ra lỗi - sau đó sửa chúng ngay lập tức (và tái cấu trúc đến mức bạn cần làm như vậy một cách an toàn).

  • dạy cho các đồng nghiệp của bạn "nguyên tắc hướng đạo nam" (AKA "tái cấu trúc cơ hội" ), vì vậy khi nhóm bắt đầu thêm các tính năng mới (hoặc để sửa lỗi), họ nên cải thiện và cấu trúc lại chính xác các phần của cơ sở mã mà họ cần thay đổi, không ít, không nhiều

  • lấy một bản sao của cuốn sách Feather "Làm việc hiệu quả với mã kế thừa" cho nhóm.

Vì vậy, khi đến lúc bạn biết chắc chắn mình cần thay đổi và cấu trúc lại các mô-đun dễ vỡ (vì phát triển tính năng mới hoặc do các thử nghiệm bạn đã thêm trong bước 1 cho thấy một số lỗi), thì bạn và nhóm của bạn đã sẵn sàng cấu trúc lại các mô-đun, và ít nhiều an toàn bỏ qua những bình luận cảnh báo đó.

Để trả lời một số ý kiến : công bằng mà nói, nếu một người nghi ngờ mô-đun trong sản phẩm hiện có là nguyên nhân gây ra sự cố một cách thường xuyên, đặc biệt là mô-đun được đánh dấu là "không chạm", tôi đồng ý với tất cả bạn. Nó nên được xem xét, gỡ lỗi và có lẽ được tái cấu trúc trong quá trình đó (với sự hỗ trợ của các thử nghiệm tôi đã đề cập, và không nhất thiết phải theo thứ tự đó). Lỗi là một biện minh mạnh mẽ cho sự thay đổi, thường là mạnh mẽ hơn các tính năng mới. Tuy nhiên, đây là một quyết định từng trường hợp. Người ta phải kiểm tra rất cẩn thận nếu thực sự đáng để thay đổi thứ gì đó trong mô-đun được đánh dấu là "không chạm".


70
Tôi bị cám dỗ để downvote, nhưng tôi sẽ kiềm chế. Tôi đã thấy tâm lý này trên nhiều dự án dẫn đến một sản phẩm tồi tệ hơn nhiều. Một khi thất bại cuối cùng đã xảy ra, chúng thường là thảm họa và khó khắc phục hơn nhiều do sự cố thủ của chúng. Tôi thường xuyên sửa chữa bùn mà tôi thấy, và nó dường như gây ra nhiều vấn đề tồi tệ nhất khi nó sửa chữa hoặc tốt nhất là không để lại vấn đề nào; nó là một điểm cộng rất lớn VÀ mã sau đó tốt hơn cho sự phát triển trong tương lai. Một khâu trong thời gian tiết kiệm chín, nhưng một vấn đề bỏ qua có thể trở nên tồi tệ hơn.
Aaron

98
Tôi sẽ lập luận rằng bất kỳ mã nào được đánh dấu bằng một nhận xét "Đã hết thời gian để cung cấp Mô-đun Một thời gian để làm công cụ. Nếu không đúng thời gian như thế này, nó sẽ bị hỏng " đã có lỗi. Đó chỉ là may mắn của trận hòa mà con bọ không bị tấn công.
17 của ngày 26 tháng

10
@ 17of26: không nhất thiết là lỗi. Đôi khi, khi bạn làm việc với các thư viện của bên thứ 3, bạn buộc phải thực hiện tất cả các loại nhượng bộ "thanh lịch" trong mục tiêu để làm cho nó hoạt động.
whatsisname

30
@ 17of26: nếu một mô-đun bị nghi ngờ có lỗi, việc thêm các kiểm tra trước khi bất kỳ loại tái cấu trúc nào thậm chí còn quan trọng hơn. Và khi các thử nghiệm đó phát hiện ra lỗi, thì bạn cần phải thay đổi mô-đun đó, và do đó, một sự hợp pháp hóa để tái cấu trúc nó ngay lập tức. Nếu các bài kiểm tra không tiết lộ bất kỳ lỗi nào, tốt hơn hết hãy để lại mã.
Doc Brown

17
@Aaron: Tôi không hiểu tại sao bạn nghĩ rằng việc thêm các bài kiểm tra hoặc theo nguyên tắc hướng đạo của cậu bé sẽ làm giảm chất lượng sản phẩm.
Doc Brown

142

Có, bạn nên cấu trúc lại mã trước khi thêm các tính năng khác.

Vấn đề với các bình luận như thế này là chúng phụ thuộc vào các trường hợp cụ thể của môi trường mà cơ sở mã đang chạy. Thời gian chờ được lập trình tại một điểm cụ thể có thể thực sự cần thiết khi nó được lập trình.

Nhưng có bất kỳ số lượng nào có thể thay đổi phương trình này: thay đổi phần cứng, thay đổi hệ điều hành, thay đổi không liên quan trong một thành phần hệ thống khác, thay đổi trong khối lượng dữ liệu điển hình, bạn đặt tên cho nó. Không có gì đảm bảo rằng trong thời đại ngày nay vẫn cần thiết, hoặc nó vẫn còn đủ (tính toàn vẹn của thứ được cho là bảo vệ có thể đã bị phá vỡ trong một thời gian dài - nếu không có các bài kiểm tra hồi quy thích hợp bạn có thể không bao giờ nhận thấy). Đây là lý do tại sao lập trình một độ trễ cố định để cho phép một thành phần khác chấm dứt hầu như không chính xác và chỉ hoạt động một cách tình cờ.

Trong trường hợp của bạn, bạn không biết các trường hợp ban đầu và bạn cũng không thể hỏi các tác giả ban đầu. (Có lẽ bạn cũng không có kiểm tra hồi quy / tích hợp thích hợp hoặc đơn giản là bạn có thể tiếp tục và để các xét nghiệm cho bạn biết liệu bạn đã phá vỡ thứ gì chưa.)

Điều này có thể trông giống như một cuộc tranh luận về việc không thay đổi bất cứ điều gì một cách thận trọng; nhưng bạn nói rằng dù sao cũng sẽ phải có những thay đổi lớn, vì vậy nguy cơ làm đảo lộn sự cân bằng tinh tế đã từng đạt được ở vị trí này đã có sẵn. Nó là tốt hơn để phá vỡ các giỏ táo tại , khi điều duy nhất bạn đang làm là tái cấu trúc, và chắc chắn rằng nếu mọi thứ phá vỡ nó là refactoring gây ra nó, hơn là đợi cho đến khi bạn đang làm thay đổi bổ sung đồng thời và không bao giờ hãy chắc chắn


46
Câu trả lời tốt nhất ngay tại đây; quá tệ, đó là một kẻ yếu. Câu trả lời được chấp nhận ở trên không phải là lời khuyên tốt, đặc biệt là sự nhấn mạnh vào "cam chịu". Tôi đã dành những năm cuối cùng làm việc trên lớn nhất (~ 10 ^ 6LOC chỉ cho tôi phần của nó), di sản-est, mã aweful Tôi đã từng thấy, và tôi làm cho nó một thói quen để sửa chữa tàu đắm tàu tôi thấy khi có thời gian, ngay cả khi nó không phải là một phần của thành phần tôi đang làm việc. Làm điều này tôi đã tìm thấy và sửa các lỗi mà nhóm nhà phát triển thậm chí không biết đã tồn tại (mặc dù người dùng cuối của chúng tôi có thể đã bị). Trong thực tế, tôi được hướng dẫn. Kết quả là sản phẩm được cải thiện.
Aaron

10
Tôi sẽ không gọi đó là tái cấu trúc, nhưng sửa lỗi, mặc dù.
Paŭlo Ebermann

7
Cải thiện thiết kế của một cơ sở mã là tái cấu trúc. Nếu thiết kế lại cho thấy các lỗi có thể sửa được, đó là sửa lỗi. Quan điểm của tôi là cái thứ nhất thường dẫn đến cái thứ hai, và cái thứ hai thường rất khó mà không có cái thứ nhất.
Kramii

10
@Aaron bạn thật may mắn khi có sự hỗ trợ của ban quản lý / nhà phát triển trong việc đó. Trong hầu hết các môi trường, các lỗi đã biết và chưa biết do thiết kế và mã kém được chấp nhận là thứ tự tự nhiên của mọi thứ.
Rudolf Olah

5
@nocomprende Tôi sẽ lập luận rằng nếu bạn không hiểu rõ về hệ thống để viết một số bài kiểm tra cho nó, bạn sẽ không thay đổi cách thức hoạt động của nó.
Patrick M

61

Câu hỏi của tôi là: tôi có nên cấu trúc lại mã khi gặp các cảnh báo như vậy từ các tác giả không

Không, hoặc ít nhất là chưa. Bạn ngụ ý rằng mức độ kiểm tra tự động là rất thấp. Bạn cần kiểm tra trước khi bạn có thể tái cấu trúc với sự tự tin.

bây giờ chúng tôi không còn có thể thêm bất kỳ tính năng nào mà không phá vỡ thứ gì khác

Ngay bây giờ bạn cần tập trung vào việc tăng sự ổn định, không tái cấu trúc. Bạn có thể thực hiện tái cấu trúc như một phần của sự tăng độ ổn định, nhưng nó là một công cụ để đạt được mục tiêu thực sự của bạn - một cơ sở mã ổn định.

Có vẻ như điều này đã trở thành một cơ sở mã di sản, vì vậy bạn cần phải đối xử với nó một chút khác nhau.

Bắt đầu bằng cách thêm các bài kiểm tra đặc tính. Đừng lo lắng về bất kỳ thông số kỹ thuật nào, chỉ cần thêm một bài kiểm tra khẳng định hành vi hiện tại. Điều này sẽ giúp ngăn chặn công việc mới phá vỡ các tính năng hiện có.

Mỗi khi bạn sửa một lỗi, hãy thêm một trường hợp kiểm tra chứng minh rằng lỗi đã được sửa. Điều này ngăn ngừa hồi quy trực tiếp.

Khi bạn thêm một tính năng mới, hãy thêm ít nhất một số thử nghiệm cơ bản rằng tính năng mới hoạt động như dự định.

Có lẽ nhận được một bản sao của "Làm việc hiệu quả với Mã kế thừa"?

Tôi đã được đưa ra một vài tháng để cấu trúc lại mã hiện có.

Bắt đầu bằng cách kiểm tra bảo hiểm lên. Bắt đầu với những khu vực phá vỡ nhiều nhất. Bắt đầu với những khu vực thay đổi nhiều nhất. Sau đó, khi bạn đã xác định được các thiết kế xấu, hãy thay thế từng cái một.

Bạn gần như không bao giờ làm một công cụ tái cấu trúc khổng lồ, mà thay vào đó là một dòng các nhà tái cấu trúc nhỏ liên tục mỗi tuần. Một nhà tái cấu trúc lớn có nguy cơ phá vỡ mọi thứ rất lớn và thật khó để kiểm tra tốt.


10
+1 để thêm các bài kiểm tra đặc tính. Đó là cách duy nhất để giảm thiểu hồi quy khi sửa đổi mã kế thừa chưa được kiểm tra. Nếu các thử nghiệm bắt đầu thất bại một khi bạn bắt đầu thực hiện thay đổi, thì bạn có thể kiểm tra xem hành vi trước đó có thực sự đúng với thông số kỹ thuật không, hoặc nếu hành vi thay đổi mới là chính xác.
Leo

2
Đúng. Hoặc nếu không có kiểm tra thông số kỹ thuật có thể sử dụng nếu hành vi trước đó thực sự được mong muốn bởi những người trả tiền hoặc có hứng thú với phần mềm.
bdsl

Có lẽ nhận được một bản sao của "Làm việc hiệu quả với Mã kế thừa"? Anh ấy sẽ mất bao nhiêu tuần để đọc cuốn sách đó? Và khi nào: trong giờ làm việc tại nơi làm việc, vào ban đêm khi mọi người ngủ?
Billal Begueradj

23

Hãy nhớ hàng rào của GK Chesterton : đừng hạ hàng rào cản đường cho đến khi bạn hiểu tại sao nó được xây dựng.

Bạn có thể tìm (các) tác giả của mã và các ý kiến ​​được đề cập, và tham khảo ý kiến ​​của họ để có được sự hiểu biết. Bạn có thể xem các thông điệp cam kết, chuỗi email hoặc tài liệu nếu chúng tồn tại. Sau đó, bạn sẽ có thể cấu trúc lại đoạn được đánh dấu hoặc sẽ ghi lại kiến ​​thức của bạn trong các bình luận để người tiếp theo duy trì mã này có thể đưa ra quyết định sáng suốt hơn.

Mục đích của bạn là để hiểu được mã này làm gì và tại sao nó được đánh dấu bằng một cảnh báo trước đó và điều gì sẽ xảy ra nếu cảnh báo bị bỏ qua.

Trước đó, tôi sẽ không chạm vào mã được đánh dấu "không chạm".


4
OP nói "không, tôi không thể liên lạc với các tác giả".
Thất vọngWithFormsDesigner

5
Tôi không thể liên lạc với các tác giả cũng như không có tài liệu nào.
kukis

21
@kukis: Bạn không thể liên hệ với các tác giả, bất kỳ chuyên gia tên miền nào và không thể tìm thấy bất kỳ email / wiki / docs / trường hợp kiểm tra nào liên quan đến mã được đề cập? Chà, đó là một dự án nghiên cứu toàn diện về khảo cổ học phần mềm, không phải là một nhiệm vụ tái cấu trúc đơn giản.
9000

12
Không có gì lạ khi mã đã cũ và các tác giả đã rời đi. Nếu họ đã kết thúc làm việc cho một đối thủ cạnh tranh thì việc thảo luận về việc đó có thể vi phạm NDA của ai đó. Trong một số trường hợp, các tác giả không có sẵn vĩnh viễn: bạn không thể hỏi Phil Katz về PKzip vì anh ta đã chết cách đây nhiều năm.
pjc50

2
Nếu bạn thay thế "tìm tác giả" bằng "hiểu vấn đề mà mã đã giải quyết" thì đây là câu trả lời tốt nhất. Đôi khi các bit mã này là giải pháp kinh khủng nhất đối với các lỗi mất hàng tuần hoặc hàng tháng để tìm và theo dõi và xử lý, thường là các lỗi mà các loại kiểm thử đơn vị thông thường không thể tìm thấy. (Mặc dù đôi khi chúng là kết quả của các lập trình viên không biết họ đang làm gì. Nhiệm vụ đầu tiên của bạn là hiểu nó là gì)
grahamparks

6

Mã với các nhận xét như những gì bạn đã hiển thị sẽ đứng đầu trong danh sách những thứ cần cấu trúc lại của tôi nếu và chỉ khi tôi có bất kỳ lý do nào để làm như vậy . Vấn đề là, mã bị hôi thối quá tệ, bạn thậm chí còn ngửi thấy nó thông qua các bình luận. Thật vô nghĩa khi cố gắng đưa bất kỳ chức năng mới nào vào mã này, mã đó cần phải chết ngay khi cần thay đổi.

Cũng lưu ý rằng các ý kiến ​​không hữu ích trong ít nhất: Họ chỉ đưa ra cảnh báo và không có lý do. Vâng, chúng là những dấu hiệu cảnh báo xung quanh một bể cá mập. Nhưng nếu bạn muốn làm bất cứ điều gì trong vùng lân cận, có rất ít điểm để cố gắng bơi cùng cá mập. Imho, bạn nên thoát khỏi những con cá mập trước.

Điều đó nói rằng, bạn hoàn toàn cần các trường hợp thử nghiệm tốt trước khi bạn có thể dám làm việc với mã như vậy. Một khi bạn có những trường hợp thử nghiệm đó, hãy chắc chắn hiểu từng chút nhỏ bạn đang thay đổi, để đảm bảo rằng bạn thực sự không thay đổi hành vi. Làm cho nó trở thành ưu tiên hàng đầu của bạn để giữ tất cả các đặc thù hành vi của mã cho đến khi bạn có thể chứng minh rằng chúng không có bất kỳ ảnh hưởng nào. Hãy nhớ rằng, bạn đang đối phó với cá mập - bạn phải rất cẩn thận.

Vì vậy, trong trường hợp hết thời gian: Hãy để lại cho đến khi bạn hiểu chính xác mã đang chờ đợi, và sau đó khắc phục lý do tại sao thời gian chờ được đưa ra trước khi bạn tiến hành xóa nó.

Ngoài ra, hãy chắc chắn rằng sếp của bạn hiểu những gì một nỗ lực mà bạn đang bắt tay vào, và tại sao nó là cần thiết. Và nếu họ nói không, đừng làm điều đó. Bạn hoàn toàn cần sự hỗ trợ của họ trong việc này.


1
Đôi khi mã kết thúc là một mớ hỗn độn vì nó phải hoạt động chính xác trên các mẫu silicon sản xuất trước mà hành vi thực tế của nó không khớp với tài liệu. Tùy thuộc vào bản chất của cách giải quyết, thay thế mã có thể là một ý tưởng tốt nếu mã sẽ không bao giờ cần phải chạy trên các chip lỗi, nhưng thay đổi mã mà không có mức phân tích kỹ thuật cần thiết của mã mới có thể không phải là tốt ý tưởng.
supercat

@supercat Một trong những quan điểm của tôi là việc tái cấu trúc phải bảo toàn hoàn hảo hành vi. Nếu nó không bảo tồn hành vi, thì nó còn hơn cả tái cấu trúc trong cuốn sách của tôi (và cực kỳ nguy hiểm khi xử lý mã kế thừa đó).
cmaster

5

Có lẽ không phải là một ý tưởng tốt để cấu trúc lại mã với các cảnh báo như vậy, nếu mọi thứ hoạt động tốt như hiện tại.

Nhưng nếu bạn phải cấu trúc lại ...

Đầu tiên, viết một số bài kiểm tra đơn vị kiểm tra tích hợp để kiểm tra các điều kiện mà các cảnh báo đang cảnh báo bạn. Cố gắng bắt chước các điều kiện giống như sản xuất càng nhiều càng tốt . Điều này có nghĩa là phản chiếu cơ sở dữ liệu sản xuất đến một máy chủ thử nghiệm, chạy cùng các dịch vụ khác trên máy, v.v ... bất cứ điều gì bạn có thể làm. Sau đó, cố gắng tái cấu trúc của bạn (tất nhiên trên một nhánh bị cô lập). Sau đó chạy thử nghiệm trên mã mới của bạn để xem liệu bạn có thể nhận được kết quả tương tự như với bản gốc hay không. Nếu bạn có thể, thì có lẽ bạn có thể thực hiện tái cấu trúc trong sản xuất. Nhưng hãy sẵn sàng để quay trở lại những thay đổi nếu mọi thứ đi sai.


5

Tôi nói hãy tiếp tục và thay đổi nó. Dù bạn có tin hay không, không phải mọi lập trình viên đều là một thiên tài và một cảnh báo như thế này có nghĩa là nó có thể là một điểm để cải thiện. Nếu bạn thấy rằng tác giả đã đúng, bạn có thể (thở hổn hển) TÀI LIỆU hoặc GIẢI THÍCH lý do cảnh báo.


4

Tôi đang mở rộng ý kiến ​​của mình thành một câu trả lời vì tôi nghĩ rằng một số khía cạnh của vấn đề cụ thể hoặc bị bỏ qua hoặc được sử dụng để rút ra kết luận sai.

Tại thời điểm này, câu hỏi về việc có nên cấu trúc lại sớm hay không (mặc dù có thể nó sẽ được trả lời bằng một hình thức cụ thể là 'có').

Vấn đề trung tâm ở đây là (như đã lưu ý trong một số câu trả lời) các ý kiến ​​bạn trích dẫn mạnh mẽ chỉ ra rằng mã có các điều kiện chủng tộc hoặc các vấn đề đồng thời / đồng bộ hóa khác, như được thảo luận ở đây . Đây là những vấn đề đặc biệt khó khăn, vì nhiều lý do. Thứ nhất, như bạn đã tìm thấy, những thay đổi dường như không liên quan có thể gây ra vấn đề (các lỗi khác cũng có thể có hiệu ứng này, nhưng lỗi đồng thời hầu như luôn xảy ra.) Thứ hai, chúng rất khó chẩn đoán: lỗi thường xuất hiện ở một nơi xa thời gian hoặc mã từ nguyên nhân, và bất cứ điều gì bạn làm để chẩn đoán nó có thể khiến nó biến mất ( Heisenbugs). Thứ ba, lỗi đồng thời rất khó tìm thấy trong thử nghiệm. Một phần, đó là do vụ nổ tổ hợp: nó đủ tệ cho mã tuần tự, nhưng việc thêm các xen kẽ có thể có của việc thực thi đồng thời sẽ thổi nó đến điểm mà vấn đề tuần tự trở nên không đáng kể. Ngoài ra, ngay cả một trường hợp thử nghiệm tốt cũng có thể chỉ thỉnh thoảng gây ra sự cố - Nancy Leveson tính toán rằng một trong những lỗi gây chết người trong Therac 25xảy ra trong 1 trong khoảng 350 lần chạy, nhưng nếu bạn không biết lỗi là gì hoặc thậm chí có lỗi, bạn không biết có bao nhiêu lần lặp lại để thực hiện một bài kiểm tra hiệu quả. Ngoài ra, chỉ có kiểm tra tự động là khả thi ở quy mô này và có thể trình điều khiển kiểm tra áp đặt các ràng buộc thời gian tinh vi sao cho nó sẽ không bao giờ thực sự kích hoạt lỗi (Heisenbugs một lần nữa).

Có một số công cụ để kiểm tra đồng thời trong một số môi trường, chẳng hạn như Helgrind cho mã bằng cách sử dụng pthread POSIX, nhưng chúng tôi không biết chi tiết cụ thể ở đây. Kiểm tra nên được bổ sung với phân tích tĩnh (hoặc là cách khác?), Nếu có các công cụ phù hợp cho môi trường của bạn.

Để thêm vào khó khăn, trình biên dịch (và thậm chí cả bộ xử lý, trong thời gian chạy) thường được tự do sắp xếp lại mã theo cách đôi khi khiến lý do về an toàn luồng của nó rất phản trực quan (có lẽ trường hợp nổi tiếng nhất là kiểm tra hai lần khóa thành ngữ, mặc dù một số môi trường (Java, C ++ ...) đã được sửa đổi để cải thiện nó.)

Mã này có thể có một vấn đề đơn giản gây ra tất cả các triệu chứng, nhưng nhiều khả năng là bạn có một vấn đề mang tính hệ thống có thể khiến kế hoạch của bạn thêm các tính năng mới bị đình trệ. Tôi hy vọng tôi đã thuyết phục bạn rằng bạn có thể có vấn đề nghiêm trọng trong tay, thậm chí có thể là mối đe dọa hiện hữu cho sản phẩm của bạn và điều đầu tiên cần làm là tìm hiểu điều gì đang xảy ra. Nếu điều này không tiết lộ các vấn đề tương tranh, tôi khuyên bạn nên khắc phục chúng trước, trước khi bạn đặt câu hỏi liệu bạn có nên thực hiện tái cấu trúc chung hơn không, và trước khi bạn cố gắng thêm nhiều tính năng hơn.


1
Bạn thấy "điều kiện cuộc đua" ở đâu trong các bình luận? Nó thậm chí còn ngụ ý ở đâu? Bạn đang thực hiện rất nhiều giả định kỹ thuật ở đây mà không có lợi ích gì khi nhìn thấy mã.
Robert Harvey

2
@RobertHarvey "Đã hết thời gian để cung cấp Mô-đun A một thời gian để làm công cụ." - khá nhiều định nghĩa về một điều kiện cuộc đua, và thời gian chờ không phải là một cách thức để xử lý chúng. Tôi không phải là người duy nhất rút ra suy luận này. Nếu không có vấn đề gì ở đây, điều đó tốt, nhưng người hỏi cần biết, vì những bình luận này là cờ đỏ cho việc đồng bộ hóa được xử lý kém.
sdenham

3

Tôi đang làm việc với một cơ sở mã khá lớn và tôi đã được cho một vài tháng để cấu trúc lại mã hiện có. Quá trình tái cấu trúc là cần thiết bởi vì chúng tôi sẽ sớm cần thêm nhiều tính năng mới vào sản phẩm của mình [...]

Trong quá trình tái cấu trúc, thỉnh thoảng tôi bắt gặp lớp, phương thức hoặc dòng mã có nhận xét như ["đừng chạm vào cái này!"]

Có, bạn nên cấu trúc lại những phần đặc biệt . Những cảnh báo đó đã được các tác giả trước đó đặt ở đó có nghĩa là "đừng làm xáo trộn những thứ này, nó rất phức tạp và có rất nhiều tương tác bất ngờ". Khi công ty của bạn có kế hoạch phát triển phần mềm hơn nữa và thêm nhiều tính năng, họ đặc biệt giao nhiệm vụ cho bạn dọn dẹp công cụ này. Vì vậy, bạn không yên giả mạo với nó, bạn đang cố tình buộc tội với nhiệm vụ làm sạch nó lên.

Tìm hiểu những gì các mô-đun khó khăn đang làm và chia nó thành các vấn đề nhỏ hơn (những gì các tác giả ban đầu nên làm). Để có được mã duy trì khỏi một mớ hỗn độn, các phần tốt cần phải được cấu trúc lại và các phần xấu cần phải được viết lại .


2

Câu hỏi này là một biến thể khác trong cuộc tranh luận về thời điểm / cách tái cấu trúc và / hoặc dọn dẹp mã với một dấu gạch ngang "làm thế nào để kế thừa mã". Tất cả chúng ta đều có kinh nghiệm và làm việc trong các tổ chức khác nhau với các nhóm và nền văn hóa khác nhau, vì vậy không có câu trả lời đúng hay sai ngoại trừ "làm những gì bạn nghĩ bạn cần làm và làm theo cách không khiến bạn bị sa thải" .

Tôi không nghĩ rằng có nhiều tổ chức sẽ vui lòng để quy trình kinh doanh đứng về phía mình vì ứng dụng hỗ trợ cần dọn dẹp hoặc tái cấu trúc mã.

Trong trường hợp cụ thể này, các bình luận mã đang giương cờ thay đổi các phần mã này không nên được thực hiện. Vì vậy, nếu bạn tiến hành và doanh nghiệp đứng về phía mình, không những bạn không có bất cứ điều gì thể hiện để hỗ trợ cho hành động của mình, thực sự có một vật phẩm chống lại quyết định của bạn.

Vì vậy, như mọi khi, bạn nên tiến hành cẩn thận và chỉ thay đổi sau khi bạn hiểu mọi khía cạnh của những gì bạn sắp thay đổi, và tìm cách kiểm tra xem nó có chú ý rất kỹ đến năng lực và hiệu suất và thời gian vì các ý kiến ​​trong mã.

Nhưng ngay cả, quản lý của bạn vẫn cần hiểu rủi ro vốn có trong những gì bạn đang làm và đồng ý rằng những gì bạn đang làm có giá trị kinh doanh vượt xa rủi ro và bạn đã làm những gì có thể làm để giảm thiểu rủi ro đó.

Bây giờ, tất cả chúng ta hãy quay lại với TODO của chính chúng ta và những điều chúng ta biết có thể được cải thiện trong việc tạo mã của riêng chúng ta nếu chỉ có nhiều thời gian hơn.


1

Chắc chắn rồi. Đây là những dấu hiệu rõ ràng cho thấy người viết mã này không hài lòng với mã này và có khả năng chọc vào nó cho đến khi họ nhận được nó để làm việc. Có thể họ không hiểu vấn đề thực sự là gì hoặc tệ hơn là đã hiểu chúng và quá lười để sửa chúng.

Tuy nhiên, đó là một cảnh báo rằng sẽ cần rất nhiều nỗ lực để khắc phục chúng và rằng các bản sửa lỗi đó sẽ có rủi ro liên quan đến chúng.

Lý tưởng nhất, bạn sẽ có thể tìm ra vấn đề là gì và khắc phục nó đúng cách. Ví dụ:

Đã hết thời gian để cung cấp cho Mô-đun A một thời gian để làm công cụ. Nếu nó không đúng giờ như thế này, nó sẽ vỡ.

Điều này cho thấy mạnh mẽ rằng Mô-đun A không cho biết chính xác khi nào nó sẵn sàng được sử dụng hoặc khi nào nó xử lý xong. Có lẽ người viết bài này không muốn sửa chữa Mô-đun A hoặc không thể vì một số lý do. Điều này trông giống như một thảm họa đang chờ xảy ra bởi vì nó cho thấy sự phụ thuộc thời gian được xử lý bằng may mắn thay vì giải trình tự thích hợp. Nếu tôi thấy điều này, tôi sẽ rất muốn sửa nó.

Đừng thay đổi điều này. Tin tôi đi, bạn sẽ phá vỡ mọi thứ.

Điều này không cho bạn biết nhiều. Nó sẽ phụ thuộc vào những gì mã đang làm. Nó có thể có nghĩa là nó có những gì dường như là tối ưu hóa rõ ràng rằng, vì lý do này hay lý do khác, sẽ thực sự phá vỡ mã. Ví dụ, một vòng lặp có thể xảy ra để lại một biến ở một giá trị cụ thể mà một đoạn mã khác phụ thuộc vào. Hoặc một biến có thể được kiểm tra trong một luồng khác và việc thay đổi thứ tự cập nhật biến có thể phá vỡ mã khác đó.

Tôi biết sử dụng setTimeout không phải là một cách thực hành tốt, nhưng trong trường hợp này tôi đã phải sử dụng nó.

Điều này có vẻ như một dễ dàng. Bạn sẽ có thể thấy những gì setTimeoutđang làm và có lẽ tìm một cách tốt hơn để làm điều đó.

Điều đó nói rằng, nếu các loại sửa lỗi này nằm ngoài phạm vi của bộ tái cấu trúc của bạn, thì đây là những dấu hiệu cho thấy cố gắng cấu trúc lại bên trong mã này có thể làm tăng đáng kể phạm vi nỗ lực của bạn.

Tối thiểu, xem xét kỹ mã bị ảnh hưởng và xem liệu bạn ít nhất có thể cải thiện nhận xét đến mức giải thích rõ hơn vấn đề là gì không. Điều đó có thể cứu người tiếp theo khỏi phải đối mặt với cùng một bí ẩn mà bạn phải đối mặt.


2
Có thể các điều kiện đã thay đổi đến mức các vấn đề cũ không còn tồn tại nữa, và các bình luận cảnh báo đã trở thành giống như địa điểm trên các bản đồ cũ có nội dung: "Đây là những con rồng". Đi sâu vào và tìm hiểu tình huống này là gì, hoặc thấy rằng nó đã đi vào lịch sử.

2
Trong thế giới thực, một số thiết bị không cung cấp chỉ báo sẵn sàng đáng tin cậy mà thay vào đó chỉ định thời gian chưa sẵn sàng tối đa. Chỉ dẫn sẵn sàng đáng tin cậy và hiệu quả là tốt đẹp, nhưng đôi khi một người bị mắc kẹt khi sử dụng những thứ mà không có chúng.
supercat

1
@supercat Có lẽ, có thể không. Chúng tôi không thể nói từ bình luận ở đây. Vì vậy, đáng để điều tra, nếu không có gì khác, cải thiện nhận xét với các chi tiết cụ thể.
David Schwartz

1
@DavidSchwartz: Nhận xét chắc chắn có thể hữu ích hơn, nhưng đôi khi không rõ lập trình viên nên dành bao nhiêu thời gian để cố gắng vạch ra tất cả các cách chính xác mà thiết bị không tuân theo thông số kỹ thuật của nó, đặc biệt là nếu không rõ vấn đề có được dự kiến ​​không là một điều tạm thời hoặc vĩnh viễn.
supercat

1

Tác giả của các bình luận rất có thể đã không hiểu đầy đủ về bản thân mã . Họ thực sự biết những gì họ đang làm, họ sẽ viết những bình luận thực sự hữu ích (hoặc không đưa ra các điều kiện đua xe ngay từ đầu). Một nhận xét như " Hãy tin tôi, bạn sẽ phá vỡ mọi thứ. " Đối với tôi cho thấy tác giả cố gắng thay đổi điều gì đó gây ra lỗi không mong muốn mà họ không hiểu đầy đủ.

Mã này có thể được phát triển thông qua việc đoán và thử và sai mà không hiểu đầy đủ về những gì thực sự xảy ra.

Điều này có nghĩa là:

  1. Nó là rủi ro để thay đổi mã. Rõ ràng sẽ mất thời gian để hiểu, và có lẽ nó không tuân theo các nguyên tắc thiết kế tốt và có thể có các hiệu ứng và phụ thuộc mơ hồ. Nó hầu như không được kiểm tra đầy đủ và nếu không ai hiểu đầy đủ về mã này thì sẽ rất khó để viết các bài kiểm tra để đảm bảo không có lỗi hoặc thay đổi trong hành vi được đưa ra. Các điều kiện đua xe (như các ý kiến ​​ám chỉ) đặc biệt khó chịu - đây là một nơi mà các bài kiểm tra đơn vị sẽ không cứu bạn.

  2. Đó là rủi ro không thay đổi mã. Mã này có khả năng cao chứa các lỗi tối nghĩa và điều kiện đua. Nếu một lỗi nghiêm trọng được phát hiện trong các mã, hoặc một ưu tiên cao lực lượng thay đổi yêu cầu kinh doanh bạn phải thay đổi mã này trên thông báo ngắn, bạn đang ở sâu rắc rối. Bây giờ bạn có tất cả các vấn đề được nêu trong 1, nhưng dưới áp lực thời gian! Hơn nữa, các "vùng tối" như vậy trong mã có xu hướng lây lan và lây nhiễm các phần khác của mã mà nó chạm vào.

Một biến chứng nữa: Các bài kiểm tra đơn vị sẽ không cứu bạn . Thông thường, cách tiếp cận được đề xuất đối với mã kế thừa sửa lỗi đó là thêm các bài kiểm tra đơn vị hoặc tích hợp trước, sau đó cô lập và cấu trúc lại. Nhưng điều kiện đua xe không thể được nắm bắt bằng thử nghiệm tự động. Giải pháp duy nhất là ngồi xuống và suy nghĩ về mã cho đến khi bạn hiểu nó, sau đó viết lại để tránh các điều kiện đua xe.

Điều này có nghĩa là nhiệm vụ đòi hỏi nhiều hơn so với chỉ tái cấu trúc thông thường. Bạn sẽ phải lên lịch cho nó như một nhiệm vụ phát triển thực sự.

Bạn có thể đóng gói mã bị ảnh hưởng như là một phần của tái cấu trúc thông thường, do đó, ít nhất là mã nguy hiểm bị cô lập.


-1

Câu hỏi tôi sẽ hỏi là tại sao ai đó viết, ĐỪNG CHỈNH SỬA ngay từ đầu.

Tôi đã làm việc với rất nhiều mã và một số mã đó là xấu và mất rất nhiều thời gian và công sức để làm việc, trong các ràng buộc nhất định tại thời điểm đó.

Tôi đặt cược trong trường hợp này, điều này đã xảy ra và người viết bình luận nhận thấy rằng ai đó đã thay đổi nó và sau đó phải lặp lại toàn bộ bài tập và đưa nó trở lại theo cách của nó, để làm cho nó hoạt động. Sau đó, vì thất vọng, họ đã viết ... ĐỪNG CHỈNH SỬA.

Nói cách khác, tôi không muốn phải sửa lỗi này một lần nữa vì tôi có những điều tốt hơn để làm với cuộc sống của mình.

Bằng cách nói KHÔNG CHỈNH SỬA, là một cách nói rằng chúng ta biết mọi thứ mà chúng ta sẽ biết ngay bây giờ và do đó trong tương lai chúng ta sẽ không bao giờ học được điều gì mới.

Nên có ít nhất một bình luận về lý do không chỉnh sửa. Giống như nói "Không chạm" hoặc "Không nhập". Tại sao không chạm vào hàng rào? Tại sao không vào? Sẽ không tốt hơn để nói, "Hàng rào điện, Đừng chạm vào!" hoặc "Mỏ đất! Đừng vào!". Sau đó, rõ ràng tại sao, nhưng bạn vẫn có thể nhập, nhưng ít nhất biết hậu quả trước khi bạn làm.

Tôi cũng cá rằng hệ thống không có thử nghiệm nào xung quanh mã ma thuật này và do đó không ai có thể xác nhận rằng mã sẽ hoạt động chính xác sau bất kỳ thay đổi nào. Đặt các bài kiểm tra đặc tính xung quanh mã vấn đề luôn là bước đầu tiên. Xem "Làm việc với Mã kế thừa" của Michael Feathers để biết các mẹo về cách phá vỡ các phụ thuộc và kiểm tra mã, trước khi xử lý thay đổi mã.

Tôi nghĩ rằng cuối cùng, nó được rút ngắn để đặt ra các hạn chế trong việc tái cấu trúc và để sản phẩm phát triển theo cách tự nhiên và hữu cơ.


2
điều này dường như không cung cấp bất cứ điều gì đáng kể qua các điểm được thực hiện và giải thích trong 9 câu trả lời trước
gnat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.