Phải làm gì khi mã được gửi để xem xét mã có vẻ quá phức tạp?


115

Mã này rất khó theo dõi nhưng dường như (hầu hết) hoạt động tốt, ít nhất là với thử nghiệm hời hợt. Có thể có một số lỗi nhỏ ở đây và ở đó nhưng rất khó để nói bằng cách đọc mã nếu chúng có triệu chứng của các vấn đề sâu hơn hoặc các bản sửa lỗi đơn giản. Tuy nhiên, việc xác minh tính chính xác tổng thể bằng cách xem xét mã là rất khó khăn và tốn thời gian, thậm chí nếu có thể.

Quá trình hành động tốt nhất trong tình huống này là gì? Nhấn mạnh vào một do-over? Làm một phần? Tái bao thanh toán trước? Sửa lỗi chỉ và chấp nhận nợ kỹ thuật ? Làm một đánh giá rủi ro trên các lựa chọn và sau đó quyết định? Thứ gì khác?


4
Xuất hiện hay là? Một phép đo nhanh các tệp nguồn sẽ xác nhận hoặc từ chối sự nghi ngờ của bạn. Sau khi đo, chỉ cần đưa ra các số đo tại phần đánh giá mã và đề xuất tái cấu trúc để giảm các số phức.
Jon Raynor



4
Vui lòng xác định "quá phức tạp". Có phải mã quá phức tạp vì nó sử dụng các mẫu thiết kế nổi tiếng mà đơn giản là không quen thuộc với nhóm của bạn hoặc do không sử dụng các mẫu mà nhóm của bạn biết đến? Những lý do chính xác để đánh giá mã "quá phức tạp" là điều cần thiết để tạo ra một đánh giá chính xác về cách đi tiếp. Một tuyên bố đơn giản như "quá phức tạp" trên một lĩnh vực kiến ​​thức sâu sắc và phức tạp như đánh giá mã cho thấy một cuộc săn lùng phù thủy của nhà phát triển với tôi.
Pieter Geerkens

7
@PieterGeerkens Hoặc, có lẽ, nó quá phức tạp vì nó giải quyết một vấn đề phức tạp?
Casey

Câu trả lời:


251

Nếu nó không thể được xem xét, nó không thể vượt qua đánh giá.

Bạn phải hiểu rằng xem xét mã không phải là để tìm lỗi. Đó là những gì QA dành cho. Xem xét mã là để đảm bảo rằng việc bảo trì mã trong tương lai là có thể. Nếu bạn thậm chí không thể làm theo mã ngay bây giờ, làm thế nào bạn có thể trong sáu tháng khi bạn được chỉ định thực hiện các cải tiến tính năng và / hoặc sửa lỗi? Tìm lỗi ngay bây giờ chỉ là một lợi ích phụ.

Nếu nó quá phức tạp, nó vi phạm rất nhiều nguyên tắc RẮN . Tái cấu trúc, tái cấu trúc, tái cấu trúc. Chia nó thành các chức năng được đặt tên đúng mà ít hơn nhiều, đơn giản hơn. Bạn có thể làm sạch nó và các trường hợp thử nghiệm của bạn sẽ đảm bảo rằng nó tiếp tục hoạt động đúng. Bạn có trường hợp thử nghiệm, phải không? Nếu không, bạn nên bắt đầu thêm chúng.


49
Điều này rất nhiều. Hãy nhớ rằng không chỉ bạn và nhà văn sẽ đọc mã này. Nó cũng sẽ là một số thực tập ngẫu nhiên trong 10 năm, vì vậy bạn muốn chắc chắn rằng anh ấy có cơ hội có thể hiểu những gì đang xảy ra.
David Grinberg

2
câu trả lời tốt. nó phụ thuộc vào mục đích của "đánh giá mã". khả năng đọc là một thứ, cấu trúc khác - nhưng chúng liên quan rất chặt chẽ với nhau. fwiw Tôi đang làm việc với một số nguồn mở được viết bởi quân đoàn MAJOR và nó gần như không thể đọc được vì tên var và fn rất tóc.

19
@DavidGrinberg Đối với tất cả các mục đích thực tế, "bạn trong sáu tháng" là một người hoàn toàn khác.
chrylis -on strike-

2
Đặt mã đi một lúc (đủ lâu để anh ta không nhớ mọi thứ). Yêu cầu các coder gốc xem xét nó. Xem nếu HE hiểu nó.
Nelson

4
Tôi không đồng ý rằng đánh giá mã "không" để tìm lỗi. Nó thường không tìm thấy lỗi, và đó là một khía cạnh rất mạnh mẽ và hữu ích của các đánh giá mã. Tốt hơn nữa, nó giúp tìm cách tránh các lỗi hoàn toàn trong mã tương lai. Vấn đề có lẽ là quá cường điệu, và lẽ ra không phải chỉ tìm thấy lỗi!
Cody Grey

45

Tất cả mọi thứ mà bạn đề cập là hoàn toàn hợp lệ để chỉ ra trong một đánh giá mã.

Khi tôi nhận được một đánh giá mã, tôi sẽ xem xét các bài kiểm tra. Nếu các xét nghiệm không cung cấp đủ bảo hiểm, đó là điều cần chỉ ra. Các thử nghiệm cần phải hữu ích để đảm bảo rằng mã hoạt động như dự định và sẽ tiếp tục hoạt động như dự định trong các thay đổi. Trong thực tế, đây là một trong những điều đầu tiên tôi tìm kiếm trong một bài đánh giá mã. Nếu bạn chưa chứng minh được rằng mã của bạn đáp ứng các yêu cầu, tôi không muốn đầu tư thời gian của mình vào việc xem xét nó.

Khi đã có đủ các thử nghiệm cho mã, nếu mã phức tạp hoặc khó theo dõi, đó cũng là thứ mà con người nên xem xét. Các công cụ phân tích tĩnh có thể chỉ ra một số biện pháp về độ phức tạp và đánh dấu các phương thức quá phức tạp cũng như tìm ra các lỗ hổng tiềm năng trong mã (và nên được chạy trước khi xem xét mã con người). Nhưng mã được đọc và duy trì bởi con người, và cần phải được viết để bảo trì trước tiên. Chỉ khi có một lý do để sử dụng mã ít bảo trì hơn thì nó mới được viết theo cách đó. Nếu bạn cần phải có mã phức tạp hoặc không trực quan, thì nó phải được ghi lại (tốt nhất là trong mã) tại sao mã lại như vậy và có những nhận xét hữu ích cho các nhà phát triển trong tương lai để hiểu tại sao và mã đang làm gì.

Lý tưởng nhất là từ chối các đánh giá mã không có các bài kiểm tra phù hợp hoặc có mã quá phức tạp mà không có lý do chính đáng. Có thể có những lý do kinh doanh để đi tiếp và vì thế bạn cần đánh giá rủi ro. Nếu bạn tiếp tục mắc nợ kỹ thuật bằng mã, hãy đặt vé vào hệ thống theo dõi lỗi của bạn ngay lập tức với một số chi tiết về những gì cần thay đổi và một số đề xuất để thay đổi nó.


30

Tuy nhiên, việc xác minh tính chính xác tổng thể bằng cách xem xét mã là rất khó khăn và tốn thời gian, thậm chí nếu có thể.

Đó không phải là điểm đánh giá mã từ xa. Cách nghĩ về đánh giá mã là tưởng tượng rằng có một lỗi trong mã và bạn phải sửa nó. Với suy nghĩ này, hãy duyệt qua mã (đặc biệt là các bình luận) và tự hỏi mình "Có dễ hiểu bức tranh lớn về những gì đang xảy ra để tôi có thể thu hẹp vấn đề không?" Nếu vậy, nó là một vượt qua. Nếu không, đó là một thất bại. Ít nhất là cần nhiều tài liệu hơn, hoặc có thể tái cấu trúc là cần thiết để làm cho mã dễ hiểu một cách hợp lý.

Điều quan trọng là không cầu toàn về điều đó trừ khi bạn chắc chắn đó là những gì chủ nhân của bạn đang theo đuổi. Hầu hết các mã hút rất nhiều đến mức nó có thể dễ dàng được cấu trúc lại 10 lần liên tiếp, mỗi lần dễ đọc hơn. Nhưng chủ nhân của bạn có thể không muốn trả tiền để có mã dễ đọc nhất thế giới.


4
Nhận xét tuyệt vời! "Hầu hết các mã hút rất nhiều đến mức nó có thể dễ dàng được tái cấu trúc 10 lần liên tiếp, dễ đọc hơn mỗi lần" Cậu bé, tôi có tội khi làm điều đó :)
Dean Radcliffe

1
"Hầu hết các mã hút rất nhiều đến mức nó có thể dễ dàng được tái cấu trúc 10 lần liên tiếp, mỗi lần dễ đọc hơn." Thật vậy, đó là cách nó trong thế giới thực.
Peter Mortensen

@PeterMortensen Thực sự đúng là bạn tìm thấy rất nhiều điều đó trong thế giới thực. Nhưng việc viết mã theo cách đó không phải là lợi ích của bất kỳ ai. Tôi nghĩ có hai lý do tại sao nó lại như vậy. Giáo dục mà các nhà phát triển nhận được đặt rất ít nỗ lực vào việc dạy cách viết mã có thể đọc được. Và trong một số doanh nghiệp, nó được coi là một sự lãng phí thời gian: "Nếu nhà phát triển đã viết mã làm việc, tại sao chúng ta phải quan tâm nếu nó có thể đọc được hay không? Chỉ cần giao hàng."
kasperd

15

Tuy nhiên, việc xác minh tính chính xác tổng thể bằng cách xem xét mã là rất khó khăn và tốn thời gian, thậm chí nếu có thể.

Nhiều năm trước, công việc của tôi là thực hiện chính xác điều đó bằng cách chấm điểm bài tập về nhà của học sinh. Và trong khi nhiều người cung cấp một số chất lượng hợp lý với một lỗi ở đây và đó, có hai người nổi bật. Cả hai luôn gửi mã không có lỗi. Một mã được gửi mà tôi có thể đọc từ trên xuống dưới với tốc độ cao và đánh dấu là chính xác 100% với nỗ lực bằng không. Mã được gửi khác là một WTF sau mã kia, nhưng bằng cách nào đó đã xoay sở để tránh bất kỳ lỗi nào. Một nỗi đau tuyệt đối để đánh dấu.

Hôm nay, người thứ hai sẽ bị từ chối mã trong một đánh giá mã. Nếu việc xác minh tính chính xác là rất khó khăn và tốn thời gian, thì đó là một vấn đề với mã. Một lập trình viên giỏi sẽ tìm ra cách giải quyết vấn đề (mất thời gian X) và trước khi đưa nó vào một bản đánh giá lại mã để nó không chỉ thực hiện công việc, mà rõ ràng là thực hiện công việc. Điều đó mất ít thời gian hơn X và tiết kiệm rất nhiều thời gian trong tương lai. Thường bằng cách phát hiện ra các lỗi trước khi chúng thậm chí đi đến giai đoạn xem xét mã. Tiếp theo bằng cách làm cho mã xem lại nhanh hơn rất nhiều. Và tất cả thời gian trong tương lai bằng cách làm cho mã dễ thích nghi hơn.

Một câu trả lời khác nói rằng mã của một số người có thể được cấu trúc lại 10 lần, mỗi lần trở nên dễ đọc hơn. Điều đó thật đáng buồn. Đó là một nhà phát triển nên tìm kiếm một công việc khác.


Mất ít thời gian hơn để tôi cấu trúc lại mã của mình 10 lần, sau đó tôi phải viết phiên bản đầu tiên của mã. Nếu ai khác biết tôi đã thực hiện tái cấu trúc này thì tôi đã thất bại.
Ian

6

Đây có phải là mã cũ đã được thay đổi một chút? (100 dòng mã được thay đổi trong 10000 dòng mã vẫn chỉ là một thay đổi nhỏ) Đôi khi, có những hạn chế về thời gian và các nhà phát triển buộc phải ở trong một khuôn khổ cũ và bất tiện, đơn giản vì việc viết lại hoàn toàn sẽ mất nhiều thời gian hơn và hết ngân sách . + thường có rủi ro liên quan, có thể tốn hàng triệu đô la khi đánh giá không chính xác. Nếu đó là mã cũ, trong hầu hết các trường hợp, bạn sẽ phải sống với nó. Nếu bạn không tự mình hiểu nó, hãy nói chuyện với họ và lắng nghe những gì họ nói, cố gắng hiểu. Hãy nhớ rằng, nó có thể khó theo dõi cho bạn, nhưng hoàn toàn tốt cho những người khác. Về phía họ, nhìn thấy nó từ cuối của họ.

Đây có phải là mã mới ? Tùy thuộc vào thời gian hạn chế, bạn nên ủng hộ để tái cấu trúc càng nhiều càng tốt. Có ổn không khi dành nhiều thời gian hơn cho các đánh giá mã nếu cần thiết. Bạn không nên timebox đến 15 phút, lấy ý tưởng và tiếp tục. Nếu tác giả dành một tuần để viết một cái gì đó, bạn có thể dành 4-8 giờ để xem lại. Mục tiêu của bạn ở đây là giúp họ tái cấu trúc. Bạn không chỉ trả lại mã nói "refactor. Now". Xem những phương pháp nào có thể được chia nhỏ, cố gắng đưa ra ý tưởng để giới thiệu các lớp mới, v.v.


2
Bạn không chỉ trả lại mã nói "refactor. Now" - tại sao? Tôi đã nhận được những nhận xét đánh giá như vậy ít nhất một lần và lần cuối cùng tôi nhớ nó hóa ra hữu ích và đúng đắn. Tôi đã phải viết lại một đoạn mã lớn từ đầu và đây là điều đúng đắn vì khi nhìn lại tôi đã thấy rằng mã cũ là một mớ hỗn độn không thể sửa chữa được. Người đánh giá chỉ đơn giản là đủ điều kiện để nhận thấy rằng (và rõ ràng là tôi không)
gnat

4
@gnat: Đối với một, vì nó thô lỗ. Bạn trông ổn hơn khi bạn giải thích những gì sai với mã và nỗ lực để giúp người khác cải thiện nó. Trong một công ty lớn làm điều đó nếu không có thể giúp bạn ra khỏi cửa một cách nhanh chóng. Đặc biệt là nếu bạn xem xét mã của một người cao cấp hơn.
Neolisk

trường hợp mà tôi đã đề cập ở trên, đó là trong một công ty lớn được thành lập, đủ cẩn thận về việc không ra khỏi cửa các nhà phát triển có trình độ nhất của họ, ít nhất là không phải trên cơ sở chia sẻ trực tiếp chuyên môn kỹ thuật của họ khi được yêu cầu
gnat

1
@gnat: Cách tiếp cận "refactor. Now" có thể hoạt động đi xuống, tức là khi một nhà phát triển cao cấp có hơn 10 năm kinh nghiệm nói rằng tái cấu trúc cho một nhà phát triển cơ sở đã được thuê 1 tháng trước mà không có kinh nghiệm hoặc tình huống tương tự. Trở lên - bạn có thể có một vấn đề. Bởi vì bạn có thể không biết nhà phát triển khác có bao nhiêu kinh nghiệm, nên an toàn khi coi sự tôn trọng là hành vi mặc định. Nó sẽ không làm tổn thương bạn chắc chắn.
Neolisk

1
@Neolisk: Một nhà phát triển có kinh nghiệm phải viết mã dưới áp lực thời gian và biết rằng nó không đủ tốt có thể chỉ quá hạnh phúc nếu bạn từ chối mã, cho anh ta thời gian và lý do để cải thiện nó. PHB quyết định nó đủ tốt khiến nhà phát triển không hài lòng; người đánh giá quyết định nó không đủ tốt để làm anh ta hạnh phúc.
gnasher729

2

Thông thường, các bản vá / thay đổi "phức tạp" là những thứ làm nhiều việc khác nhau cùng một lúc. Có mã mới, mã đã xóa, mã được cấu trúc lại, mã di chuyển, thử nghiệm mở rộng; nó làm cho nó khó nhìn thấy bức tranh lớn

Một manh mối phổ biến là bản vá rất lớn nhưng mô tả của nó rất nhỏ: "Triển khai $ FOO."

Một cách hợp lý để xử lý một bản vá như vậy là yêu cầu nó được chia thành một loạt các mảnh nhỏ hơn, khép kín. Giống như nguyên tắc trách nhiệm đơn lẻ nói rằng một chức năng chỉ nên làm một việc, một bản vá cũng chỉ tập trung vào một việc.

Ví dụ, các bản vá đầu tiên có thể chứa các phép tái cấu trúc cơ học hoàn toàn không có thay đổi chức năng, và sau đó bản vá cuối cùng có thể tập trung vào việc triển khai và thử nghiệm thực tế của $ FOO với ít phiền nhiễu và bầy đỏ hơn.

Đối với chức năng yêu cầu nhiều mã mới, mã mới thường có thể được giới thiệu trong các đoạn có thể kiểm tra, không thay đổi hành vi của sản phẩm cho đến khi bản vá cuối cùng trong chuỗi thực sự gọi mã mới (lật cờ).

Đối với việc thực hiện điều này một cách khéo léo, tôi thường coi đó là vấn đề của mình và sau đó yêu cầu sự giúp đỡ của tác giả: "Tôi gặp khó khăn khi theo dõi mọi thứ đang diễn ra ở đây. Bạn có thể chia bản vá này thành các bước nhỏ hơn để giúp tôi hiểu mọi thứ phù hợp như thế nào không cùng với nhau?" Đôi khi cần phải đưa ra đề xuất cụ thể cho các bước nhỏ hơn.

Vì vậy, bản vá lớn như "Thực hiện $ FOO" biến thành một loạt các bản vá như:

  1. Giới thiệu một phiên bản mới của Frobnicate có một cặp vòng lặp bởi vì tôi sẽ cần phải gọi nó bằng các chuỗi khác ngoài vector để thực hiện $ FOO.
  2. Chuyển tất cả những người gọi hiện có của Frobnicate để sử dụng phiên bản mới.
  3. Xóa Frobnicate cũ.
  4. Frobnicate đã làm quá nhiều. Yếu tố bước kết hợp vào phương pháp riêng của mình và thêm các bài kiểm tra cho điều đó.
  5. Giới thiệu Zerzify, với các bài kiểm tra. Chưa được sử dụng, nhưng tôi sẽ cần nó với $ FOO.
  6. Triển khai $ FOO theo Zerzify và Frobnicate mới.

Lưu ý rằng các bước 1-5 không thực hiện thay đổi chức năng cho sản phẩm. Chúng không quan trọng để xem xét, bao gồm đảm bảo rằng bạn có tất cả các bài kiểm tra phù hợp. Ngay cả khi bước 6 vẫn "phức tạp", ít nhất thì nó cũng tập trung vào $ FOO. Và nhật ký tự nhiên cung cấp cho bạn một ý tưởng tốt hơn nhiều về cách $ FOO được triển khai (và tại sao Frobnicate được thay đổi).


Một cách tiếp cận, nếu sử dụng Git, là soạn một yêu cầu kéo của nhiều lần xác nhận. Mỗi cam kết là nguyên tử và khép kín nhất có thể, và có mô tả riêng. Sau đó, thêm một ghi chú hữu ích trong cơ quan PR rằng mỗi thay đổi có thể được xem xét thủ công. Đó thường là cách tôi xử lý các PR rất lớn, như các nhà tái cấu trúc toàn cầu hoặc các thay đổi công cụ lớn, không có sẵn.
Jimmy Breck-McKye

1

Như những người khác đã chỉ ra, đánh giá mã không thực sự được thiết kế để tìm lỗi. Nếu bạn đang tìm thấy lỗi trong quá trình xem xét mã, điều đó có nghĩa là bạn không có đủ phạm vi kiểm tra tự động (ví dụ: kiểm tra đơn vị / tích hợp). Nếu không đủ độ bao phủ để thuyết phục tôi rằng mã thực hiện đúng như vậy , tôi thường yêu cầu thêm các thử nghiệm và chỉ ra loại trường hợp thử nghiệm mà tôi đang tìm kiếm và thường không cho phép mã vào cơ sở mã không có phạm vi bảo hiểm đầy đủ .

Nếu kiến ​​trúc cấp cao quá phức tạp hoặc không có ý nghĩa, tôi thường gọi một cuộc họp với một vài thành viên trong nhóm để nói về nó. Đôi khi rất khó để lặp đi lặp lại trên một kiến ​​trúc xấu. Nếu nhà phát triển là người mới, tôi thường đảm bảo rằng chúng tôi sẽ xem xét suy nghĩ của họ trước thời hạn thay vì phản ứng với yêu cầu kéo xấu. Điều này thường đúng ngay cả với các nhà phát triển dày dạn hơn nếu vấn đề không có giải pháp rõ ràng sẽ có nhiều khả năng sẽ được chọn.

Nếu độ phức tạp được phân lập ở mức phương thức thường có thể được sửa chữa lặp lại và với các thử nghiệm tự động tốt.

Một điểm cuối cùng. Là một người xem xét, bạn cần phải quyết định xem độ phức tạp của mã là do độ phức tạp thiết yếu hay ngẫu nhiên . Sự phức tạp thiết yếu liên quan đến các phần của phần mềm rất khó giải quyết. Độ phức tạp ngẫu nhiên đề cập đến tất cả các phần khác của mã chúng tôi viết quá phức tạp không có lý do và có thể dễ dàng đơn giản hóa.

Tôi thường đảm bảo rằng mã với độ phức tạp thiết yếu thực sự là như vậy và không thể đơn giản hóa hơn nữa. Tôi cũng nhắm đến phạm vi kiểm tra nhiều hơn và tài liệu tốt cho các phần này. Sự phức tạp ngẫu nhiên hầu như luôn luôn phải được dọn sạch trong quá trình yêu cầu kéo bởi vì đó là phần lớn mã chúng tôi xử lý và có thể dễ dàng gây ra cơn ác mộng bảo trì ngay cả trong thời gian ngắn.


0

Các bài kiểm tra như thế nào? Chúng phải rõ ràng, đơn giản và dễ đọc với lý tưởng chỉ có một khẳng định. Các thử nghiệm cần ghi lại rõ ràng hành vi dự định và các trường hợp sử dụng mã.

Nếu nó không được kiểm tra tốt thì đó là một nơi tốt để bắt đầu xem xét.

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.