Cách tốt nhất để xử lý tái cấu trúc một tập tin lớn là gì?


41

Tôi hiện đang làm việc trong một dự án lớn hơn, không may có một số tệp có hướng dẫn chất lượng phần mềm không phải lúc nào cũng tuân theo. Điều này bao gồm các tệp lớn (đọc 2000-4000 dòng) rõ ràng chứa nhiều chức năng riêng biệt.

Bây giờ tôi muốn cấu trúc lại các tệp lớn này thành nhiều tệp nhỏ. Vấn đề là, vì chúng quá lớn, nhiều người (bao gồm cả tôi) trên các nhánh khác nhau đang làm việc trên các tệp này. Vì vậy, tôi không thể thực sự phân nhánh từ phát triển và tái cấu trúc, vì việc hợp nhất các phép tái cấu trúc này với các thay đổi của người khác sẽ trở nên khó khăn.

Tất nhiên chúng tôi có thể yêu cầu tất cả mọi người hợp nhất trở lại để phát triển, "đóng băng" các tệp (tức là không cho phép bất kỳ ai chỉnh sửa chúng nữa), tái cấu trúc và sau đó "giải phóng". Nhưng điều này cũng không thực sự tốt, vì điều này sẽ yêu cầu mọi người về cơ bản dừng công việc của họ trên các tệp này cho đến khi tái cấu trúc được thực hiện.

Vì vậy, có cách nào để tái cấu trúc, không yêu cầu bất kỳ ai khác ngừng hoạt động (lâu dài) hoặc hợp nhất lại các nhánh tính năng của họ để phát triển?


6
Tôi nghĩ điều này cũng phụ thuộc vào ngôn ngữ lập trình được sử dụng.
Robert Andrzejuk

8
Tôi thích đăng ký "gia tăng nhỏ". Trừ khi ai đó không giữ bản sao repo của họ mới, thực tế này sẽ giảm thiểu xung đột hợp nhất cho mọi người.
Matt Raffel

5
Bài kiểm tra của bạn trông như thế nào? Nếu bạn định cấu trúc lại một đoạn mã lớn (và có thể quan trọng!), Hãy đảm bảo bộ kiểm tra của bạn ở trong tình trạng thực sự tốt trước khi bạn cấu trúc lại. Điều này sẽ làm cho nó dễ dàng hơn nhiều để đảm bảo rằng bạn đã lấy nó ngay trong các tệp nhỏ hơn.
corsiKa

1
Có rất nhiều cách tiếp cận bạn có thể thực hiện với điều này và cách tiếp cận tốt nhất sẽ phụ thuộc vào tình huống của bạn.
Stephen

3
Tôi đã tham gia dự án trong đó tệp lớn nhất dài 10 nghìn dòng chứa trong số các lớp khác, bản thân nó dài 6k dòng và mọi người đều sợ chạm vào nó. Ý tôi là câu hỏi của bạn rất hay Chúng tôi thậm chí đã phát minh ra một trò đùa rằng lớp học duy nhất này là một lý do tốt để mở khóa bánh xe cuộn trong nhà của chúng tôi.
ElmoVanKielmo

Câu trả lời:


41

Bạn đã hiểu chính xác rằng đây không phải là một vấn đề kỹ thuật xã hội: nếu bạn muốn tránh xung đột hợp nhất quá mức, nhóm cần cộng tác theo cách tránh những xung đột này.

Đây là một phần của một vấn đề lớn hơn với Git, trong đó việc phân nhánh rất dễ dàng nhưng việc hợp nhất vẫn có thể mất rất nhiều nỗ lực. Các nhóm phát triển có xu hướng ra mắt rất nhiều chi nhánh và sau đó ngạc nhiên rằng việc hợp nhất chúng là khó khăn, có thể vì họ đang cố gắng mô phỏng Dòng chảy Git mà không hiểu bối cảnh của nó.

Nguyên tắc chung để hợp nhất nhanh chóng và dễ dàng là ngăn chặn sự khác biệt lớn tích lũy, đặc biệt là các nhánh tính năng nên tồn tại rất ngắn (giờ hoặc ngày, không phải tháng). Một nhóm phát triển có khả năng tích hợp nhanh chóng các thay đổi của họ sẽ thấy ít xung đột hợp nhất hơn. Nếu một số mã chưa sẵn sàng sản xuất, có thể tích hợp nó nhưng hủy kích hoạt nó thông qua cờ tính năng. Ngay sau khi mã được tích hợp vào nhánh chính của bạn, nó có thể truy cập được vào loại tái cấu trúc mà bạn đang cố gắng thực hiện.

Đó có thể là quá nhiều cho vấn đề trước mắt của bạn. Nhưng có thể khả thi khi yêu cầu các đồng nghiệp hợp nhất các thay đổi của họ ảnh hưởng đến tệp này cho đến cuối tuần để bạn có thể thực hiện tái cấu trúc. Nếu họ chờ đợi lâu hơn, họ sẽ phải tự giải quyết các xung đột hợp nhất. Điều đó không phải là không thể, đó chỉ là công việc có thể tránh được.

Bạn cũng có thể muốn ngăn chặn việc phá vỡ một lượng lớn mã phụ thuộc và chỉ thực hiện các thay đổi tương thích API. Ví dụ: nếu bạn muốn trích xuất một số chức năng thành một mô-đun riêng biệt:

  1. Trích xuất các chức năng vào một mô-đun riêng biệt.
  2. Thay đổi các chức năng cũ để chuyển tiếp các cuộc gọi của họ sang API mới.
  3. Theo thời gian, mã phụ thuộc cổng vào API mới.
  4. Cuối cùng, bạn có thể xóa các chức năng cũ.
  5. (Lặp lại cho các chức năng tiếp theo)

Quá trình nhiều bước này có thể tránh được nhiều xung đột hợp nhất. Cụ thể, sẽ chỉ có xung đột nếu người khác cũng thay đổi chức năng bạn trích xuất. Chi phí của phương pháp này là chậm hơn nhiều so với thay đổi mọi thứ cùng một lúc và bạn tạm thời có hai API trùng lặp. Điều này không tệ cho đến khi một cái gì đó khẩn cấp làm gián đoạn quá trình tái cấu trúc này, sự trùng lặp bị lãng quên hoặc mất hiệu lực, và bạn kết thúc với một loạt các khoản nợ công nghệ.

Nhưng cuối cùng, bất kỳ giải pháp nào cũng sẽ yêu cầu bạn phối hợp với nhóm của bạn.


1
@Laiv Thật không may, đó là tất cả những lời khuyên cực kỳ chung chung, nhưng một số ý tưởng ngoài không gian nhanh nhẹn như Tích hợp liên tục rõ ràng có giá trị của chúng. Các nhóm làm việc cùng nhau (và tích hợp công việc của họ thường xuyên) sẽ có thời gian dễ dàng thực hiện các thay đổi xuyên suốt lớn hơn so với các nhóm chỉ hoạt động cùng nhau. Điều này không nhất thiết là về SDLC nói chung, nói thêm về sự hợp tác trong nhóm. Một số cách tiếp cận làm việc cùng với khả thi hơn (nghĩ Nguyên tắc mở / đóng, microservice) nhưng nhóm của OP chưa có.
amon

22
Tôi sẽ không đi xa để nói rằng một nhánh tính năng cần phải có thời gian tồn tại ngắn - chỉ đơn thuần là nó không nên tách khỏi nhánh mẹ của nó trong thời gian dài. Thường xuyên hợp nhất các thay đổi từ nhánh cha vào nhánh tính năng hoạt động trong những trường hợp mà nhánh tính năng cần gắn bó lâu hơn. Tuy nhiên, đó là một ý tưởng tốt để giữ cho các nhánh tính năng xung quanh không còn cần thiết nữa.
Dan Lyons

1
@Laiv Theo kinh nghiệm của tôi, sẽ hợp lý khi thảo luận về thiết kế sau tái cấu trúc với nhóm trước, nhưng thường thì dễ nhất nếu một người thực hiện thay đổi mã. Nếu không, bạn sẽ quay trở lại vấn đề mà bạn phải hợp nhất công cụ. Các dòng 4k nghe có vẻ nhiều, nhưng nó thực sự không dành cho các phép tái cấu trúc được nhắm mục tiêu như lớp trích xuất . (Tôi muốn Shill cuốn sách Refactoring Martin Fowler của khó khăn như vậy ở đây nếu tôi đã đọc nó.) Nhưng 4k dòng rất nhiều chỉ không mong muốn tái cấu trúc như “chúng ta hãy xem làm thế nào tôi có thể cải thiện điều này”.
amon

1
@DanLyons Về nguyên tắc bạn đúng: điều đó có thể lan truyền một số nỗ lực hợp nhất. Trong thực tế, việc sáp nhập Git phụ thuộc rất nhiều vào cam kết tổ tiên chung mới nhất của các chi nhánh được sáp nhập. Hợp nhất chủ → tính năng không cung cấp cho chúng ta một tổ tiên chung mới trên chủ, nhưng tính năng hợp nhất → chủ có. Với chủ nhân lặp đi lặp lại → tính năng hợp nhất, có thể xảy ra việc chúng ta phải giải quyết các xung đột tương tự hết lần này đến lần khác (nhưng hãy xem git rerere để tự động hóa việc này). Rebasing hoàn toàn vượt trội ở đây bởi vì mẹo của chủ nhân trở thành tổ tiên chung mới, nhưng việc viết lại lịch sử có những vấn đề khác.
amon

1
Câu trả lời là OK đối với tôi ngoại trừ những lời ca ngợi về git làm cho nó quá dễ dàng để phân nhánh, và do đó devs phân nhánh quá thường xuyên. Tôi nhớ rất rõ thời SVN và thậm chí CVS khi phân nhánh rất khó (hoặc ít nhất là cồng kềnh) đến mức mọi người thường tránh nó nếu có thể, với tất cả các vấn đề liên quan. Trong git, là một hệ thống phân tán , có nhiều nhánh thực sự không có gì khác với việc có nhiều kho lưu trữ riêng biệt (ví dụ, trên mỗi dev). Giải pháp nằm ở chỗ khác, dễ phân nhánh không phải là vấn đề. (Và vâng, tôi thấy rằng đó chỉ là một bên ... nhưng vẫn vậy).
AnoE

30

Thực hiện tái cấu trúc trong các bước nhỏ hơn. Giả sử tệp lớn của bạn có tên Foo:

  1. Thêm một tệp trống mới Barvà cam kết nó vào "thân cây".

  2. Tìm một phần nhỏ của mã Foocó thể được chuyển đến Bar. Áp dụng di chuyển, cập nhật từ thân cây, xây dựng và kiểm tra mã và cam kết với "thân cây".

  3. Lặp lại bước 2 cho đến khi FooBarcó kích thước bằng nhau (hoặc bất kỳ kích thước nào bạn thích)

Bằng cách đó, lần tới khi đồng đội của bạn cập nhật các nhánh của họ từ thân cây, họ sẽ nhận được các thay đổi của bạn trong "các phần nhỏ" và có thể hợp nhất từng phần một, điều này dễ dàng hơn nhiều so với việc phải hợp nhất một phần tách trong một bước. Điều tương tự cũng xảy ra khi ở bước 2 bạn gặp xung đột hợp nhất vì có người khác cập nhật trung kế ở giữa.

Điều này sẽ không loại bỏ xung đột hợp nhất hoặc nhu cầu giải quyết chúng theo cách thủ công, nhưng nó hạn chế mỗi xung đột trong một khu vực nhỏ của mã, dễ quản lý hơn.

Và tất nhiên - truyền đạt việc tái cấu trúc trong đội. Thông báo cho bạn bè của bạn những gì bạn đang làm, để họ biết lý do tại sao họ phải mong đợi xung đột hợp nhất cho tệp cụ thể.


2
Điều này đặc biệt hữu ích với rereretùy chọn
gits

@ D.BenKnoble: cảm ơn vì sự bổ sung đó. Tôi phải thừa nhận, tôi không phải là chuyên gia về git (nhưng vấn đề được mô tả không phải là cụ thể đối với git, nó áp dụng cho bất kỳ VCS nào cho phép phân nhánh và câu trả lời của tôi phải phù hợp với hầu hết các hệ thống đó).
Doc Brown

Tôi đã tìm ra dựa trên thuật ngữ; trong thực tế, với git, kiểu hợp nhất này vẫn chỉ được thực hiện một lần (nếu chỉ cần kéo và hợp nhất). Nhưng người ta luôn có thể kéo và chọn cherry, hoặc hợp nhất các cam kết riêng lẻ hoặc rebase tùy theo sở thích của nhà phát triển. Phải mất nhiều thời gian hơn nhưng chắc chắn là có thể thực hiện được nếu việc hợp nhất tự động dường như thất bại.
D. Ben Knoble

18

Bạn đang nghĩ đến việc chia nhỏ tệp như một thao tác nguyên tử, nhưng có những thay đổi trung gian bạn có thể thực hiện. Các tập tin dần dần trở nên khổng lồ theo thời gian, nó có thể dần dần trở nên nhỏ theo thời gian.

Chọn một phần không phải thay đổi trong một thời gian dài ( git blamecó thể giúp với điều này) và tách phần đó ra trước. Nhận thay đổi đó được hợp nhất vào các chi nhánh của mọi người, sau đó chọn phần dễ nhất tiếp theo để phân chia. Thậm chí có thể tách một phần là một bước quá lớn và bạn chỉ nên thực hiện sắp xếp lại trong tệp lớn trước.

Nếu mọi người không thường xuyên hợp nhất trở lại để phát triển, bạn nên khuyến khích điều đó, sau khi họ hợp nhất, hãy tận dụng cơ hội đó để tách ra những phần họ vừa thay đổi. Hoặc yêu cầu họ thực hiện việc tách ra như một phần của đánh giá yêu cầu kéo.

Ý tưởng là từ từ tiến tới mục tiêu của bạn. Sẽ có cảm giác như tiến độ chậm, nhưng rồi đột nhiên bạn sẽ nhận ra mã của mình tốt hơn rất nhiều. Phải mất một thời gian dài để biến một tàu biển.


Các tập tin có thể đã bắt đầu lớn. Các tập tin có kích thước có thể được tạo ra một cách nhanh chóng. Tôi biết những người có thể viết 1000 s LoC trong một ngày hoặc một tuần. Và OP đã không đề cập đến các bài kiểm tra tự động, điều này cho tôi thấy rằng họ đang thiếu.
ChuckCottrill

9

Tôi sẽ đề xuất một giải pháp khác hơn bình thường cho vấn đề này.

Sử dụng điều này như là một sự kiện mã nhóm. Yêu cầu mọi người đăng ký mã của họ, những người có thể, sau đó giúp đỡ những người khác vẫn đang làm việc với tệp. Khi mọi người có liên quan đã kiểm tra mã của họ, hãy tìm một phòng hội thảo có máy chiếu và làm việc cùng nhau để bắt đầu di chuyển mọi thứ xung quanh và vào các tệp mới.

Bạn có thể muốn đặt một lượng thời gian cụ thể cho việc này, để cuối cùng nó không phải là một cuộc tranh luận đáng giá trong một tuần. Thay vào đó, đây thậm chí có thể là một sự kiện 1-2 giờ hàng tuần cho đến khi tất cả các bạn có được mọi thứ trông như thế nào. Có lẽ bạn chỉ cần 1-2 giờ để cấu trúc lại tập tin. Bạn sẽ không biết cho đến khi bạn cố gắng, có khả năng.

Điều này có lợi cho tất cả mọi người trên cùng một trang (không có ý định chơi chữ) với việc tái cấu trúc, nhưng nó cũng có thể giúp bạn tránh các lỗi cũng như nhận thông tin từ người khác về các nhóm phương pháp có thể để duy trì, nếu cần.

Làm theo cách này có thể được coi là có một đánh giá mã tích hợp, nếu bạn làm điều đó. Điều này cho phép số lượng nhà phát triển phù hợp đăng nhập vào mã của bạn ngay khi bạn đăng ký và sẵn sàng để họ xem xét. Bạn vẫn có thể muốn họ kiểm tra mã cho bất cứ điều gì bạn bỏ lỡ, nhưng phải mất một thời gian dài để đảm bảo quá trình xem xét ngắn hơn.

Điều này có thể không hoạt động trong tất cả các tình huống, nhóm hoặc công ty, vì công việc không được phân phối theo cách làm cho điều này xảy ra dễ dàng. Nó cũng có thể được (không chính xác) được hiểu là lạm dụng thời gian dev. Mã nhóm này cần mua từ người quản lý cũng như chính người tái cấu trúc.

Để giúp bán ý tưởng này cho người quản lý của bạn, hãy đề cập đến bit xem lại mã cũng như mọi người biết nơi bắt đầu từ đâu. Ngăn chặn các nhà phát triển mất thời gian tìm kiếm một loạt các tệp mới có thể đáng để tránh. Ngoài ra, ngăn chặn các nhà phát triển nhận được POed về nơi mọi thứ kết thúc hoặc "hoàn toàn mất tích" thường là một điều tốt. (Càng ít meltdowns càng tốt, IMO.)

Khi bạn nhận được một tệp được cấu trúc lại theo cách này, bạn có thể dễ dàng nhận được sự chấp thuận hơn cho nhiều người tái cấu trúc hơn, nếu nó thành công và hữu ích.

Tuy nhiên, bạn quyết định làm refactor của bạn, chúc may mắn!


Đây là một gợi ý tuyệt vời nắm bắt một cách thực sự tốt để đạt được sự phối hợp nhóm sẽ rất quan trọng để làm cho nó hoạt động. Ngoài ra, nếu một số chi nhánh không thể được hợp nhất trở lại mastertrước tiên, ít nhất bạn đã có mọi người trong phòng để giúp giải quyết việc sáp nhập vào các chi nhánh đó.
Colin Young

+1 để đề xuất mã mob
Jon Raynor

1
Điều này chính xác giải quyết các khía cạnh xã hội của vấn đề.
ChuckCottrill

4

Khắc phục sự cố này yêu cầu mua từ các nhóm khác vì bạn đang cố gắng thay đổi tài nguyên được chia sẻ (chính mã). Điều đó đang được nói, tôi nghĩ rằng có một cách để "di cư" khỏi việc có các tập tin nguyên khối khổng lồ mà không làm phiền mọi người.

Tôi cũng khuyên bạn không nên nhắm mục tiêu tất cả các tệp lớn cùng một lúc trừ khi số lượng tệp khổng lồ đang tăng lên không kiểm soát được ngoài kích thước của các tệp riêng lẻ.

Tái cấu trúc các tệp lớn như thế này thường xuyên gây ra sự cố không mong muốn. Bước đầu tiên là ngăn chặn các tệp lớn tích lũy chức năng bổ sung ngoài những gì hiện đang là chủ hoặc trong các nhánh phát triển .

Tôi nghĩ rằng cách tốt nhất để làm điều này là với các hook hook chặn một số bổ sung nhất định cho các tệp lớn theo mặc định, nhưng có thể được ghi đè bằng một nhận xét kỳ diệu trong thông điệp cam kết, như @bigfileokhoặc một cái gì đó. Điều quan trọng là có thể ghi đè chính sách theo cách không gây đau đớn nhưng có thể theo dõi. Lý tưởng nhất là bạn có thể chạy hook hook cục bộ và nó sẽ cho bạn biết cách ghi đè lỗi cụ thể này trong chính thông báo lỗi . Ngoài ra, đây chỉ là sở thích của tôi, nhưng nhận xét ma thuật không được nhận dạng hoặc nhận xét ma thuật loại bỏ các lỗi không thực sự phát ra trong thông điệp cam kết sẽ là cảnh báo hoặc lỗi thời gian cam kết để bạn không vô tình huấn luyện mọi người loại bỏ các móc nối bất kể dù họ có cần hay không.

Hook hook có thể kiểm tra các lớp mới hoặc thực hiện phân tích tĩnh khác (ad hoc hoặc không). Bạn cũng có thể chỉ cần chọn một dòng hoặc số ký tự lớn hơn 10% so với tệp hiện tại và nói rằng tệp lớn không thể phát triển vượt quá giới hạn mới. Bạn cũng có thể từ chối các cam kết riêng lẻ phát triển tệp lớn bằng quá nhiều dòng hoặc quá nhiều ký tự hoặc w / e.

Khi tệp lớn dừng tích lũy chức năng mới, bạn có thể cấu trúc lại mọi thứ từ nó một lần (và giảm các ngưỡng được thực thi bởi các hook hook đồng thời để ngăn không cho nó phát triển trở lại).

Cuối cùng, các tệp lớn sẽ đủ nhỏ để có thể loại bỏ hoàn toàn các hook hook.


-3

Đợi đến khi về quê. Tách tập tin, cam kết và hợp nhất thành chủ.

Những người khác sẽ phải kéo các thay đổi vào các nhánh tính năng của họ vào buổi sáng như mọi thay đổi khác.


3
Tuy nhiên, điều đó có nghĩa là họ sẽ phải hợp nhất các phép tái cấu trúc của tôi với những thay đổi của họ mặc dù ...
Hoff


1
Chà, họ thực sự phải đối phó với bất kỳ sự hợp nhất nào nếu tất cả họ đang thay đổi những tập tin này.
Laiv

9
Điều này có vấn đề "Bất ngờ, tôi đã phá vỡ tất cả các công cụ của bạn." OP cần phải mua và phê duyệt trước khi thực hiện việc này và thực hiện nó vào thời gian đã lên lịch mà không ai khác có tệp "đang thực hiện" sẽ giúp ích.
máy tính

6
Vì tình yêu của cthulhu, đừng làm điều này. Đó là về cách tồi tệ nhất bạn có thể làm việc trong một nhóm.
Cuộc đua nhẹ nhàng với Monica
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.