Bài đăng này khám phá các nguyên tắc dịch chuyển sang trái và gợi ý rằng các PR xếp chồng lên nhau sẽ ngày càng trở nên hữu ích.
Quá trình xem xét mã ngang hàng là một phần thiết yếu của quá trình phát triển phần mềm. Nó giúp duy trì chất lượng phần mềm và thúc đẩy việc tuân thủ các tiêu chuẩn, yêu cầu của dự án, hướng dẫn về phong cách và tạo điều kiện học tập cũng như chuyển giao kiến thức.
Mặc dù hiệu quả cao đối với việc xem xét các thay đổi mã đủ nhỏ, nhưng nó giảm theo cấp số nhân khi quy mô của thay đổi tăng lên. Để duy trì mức độ tập trung tinh thần cần thiết để có hiệu quả, việc xem xét mã lớn rất mệt mỏi.
Thông thường, thời lượng đánh giá càng dài thì đánh giá tổng thể càng kém hiệu quả:
Vậy tại sao chúng ta không thể hạn chế kích thước của yêu cầu kéo (PR)? Mặc dù nhiều thay đổi có thể bắt đầu nhỏ, đột nhiên một thay đổi nhỏ hai dòng có thể phát triển thành cấu trúc lại 500 dòng bao gồm nhiều cuộc trò chuyện qua lại với người đánh giá.
Một số nhóm kỹ thuật cũng duy trì các nhánh tính năng hoạt động lâu dài khi chúng tiếp tục hoạt động, khiến việc xem xét trở nên khó khăn.
Vì vậy, làm thế nào để chúng ta đạt được sự cân bằng phù hợp? Đơn giản. Sử dụng các PR xếp chồng lên nhau.
Các yêu cầu kéo xếp chồng tạo ra các thay đổi nhỏ hơn, lặp đi lặp lại và được xếp chồng lên nhau thay vì gộp các thay đổi nguyên khối lớn trong một yêu cầu kéo. Mỗi PR trong ngăn xếp chỉ tập trung vào một thay đổi hợp lý, giúp quá trình xem xét trở nên dễ quản lý hơn và ít tốn thời gian hơn.
Chúng tôi cũng đã viết một bài đăng vào năm ngoái giải thích cách trợ giúp này thể hiện các thay đổi mã dưới dạng tường thuật thay vì chia nhỏ mọi thứ theo tệp hoặc tính năng.
Ngoài việc xây dựng văn hóa đánh giá mã hiệu quả hơn, có một vài lợi ích khác của PR xếp chồng:
Hãy tưởng tượng rằng bạn đang triển khai một tính năng lớn. Thay vì tạo toàn bộ tính năng và sau đó yêu cầu đánh giá mã, hãy cân nhắc tạo ra khung ban đầu và nhanh chóng đưa nó lên để nhận phản hồi.
Điều này có khả năng giúp bạn tiết kiệm vô số thời gian bằng cách nhận phản hồi sớm về thiết kế của bạn.
Các PR xếp chồng hỗ trợ thực hành dịch chuyển sang trái vì các thay đổi được tích hợp và thử nghiệm liên tục, cho phép phát hiện và khắc phục sớm các sự cố.
Các thay đổi được hợp nhất thành từng phần nhỏ để phát hiện sớm bất kỳ vấn đề nào so với việc hợp nhất một thay đổi lớn với hy vọng nó không làm giảm sản lượng!
Đánh giá mã cũng là tuyệt vời cho hậu thế. Các thay đổi mã của bạn đang thuật lại quá trình suy nghĩ của bạn đằng sau việc triển khai một tính năng, do đó, việc chia nhỏ các thay đổi sẽ tạo ra sự chuyển giao kiến thức hiệu quả hơn.
Các thành viên trong nhóm sẽ dễ dàng hiểu được các thay đổi hơn, giúp thúc đẩy việc chia sẻ kiến thức tốt hơn cho tương lai.
Chờ mã được xem xét và phê duyệt có thể là một quá trình khó chịu. Với các PR xếp chồng lên nhau, các nhà phát triển có thể làm việc trên nhiều phần của một tính năng mà không cần đợi người đánh giá phê duyệt các PR trước đó
Vì vậy, tại sao nhiều nhà phát triển không sử dụng PR xếp chồng lên nhau để đánh giá mã?
Mặc dù quy trình PR xếp chồng lên nhau này giải quyết cả các phương pháp mong muốn để giữ cho các đánh giá mã có thể quản lý được và các nhà phát triển làm việc hiệu quả, nhưng thật không may, nó không được Git hoặc GitHub hỗ trợ rất tốt.
Do đó, một số công cụ đã được phát triển trong cộng đồng nguồn mở để cho phép các kỹ sư kết hợp kỹ thuật xếp chồng này vào nền tảng Git và GitHub hiện có. Nhưng sắp xếp các PR chỉ là một phần của câu chuyện.
Khi chúng tôi nhận được phản hồi đánh giá mã và chúng tôi thực hiện các thay đổi đối với một phần của ngăn xếp, bây giờ chúng tôi phải khởi động lại và giải quyết xung đột ở tất cả các nhánh tiếp theo.
Hãy lấy một ví dụ. Hãy tưởng tượng rằng bạn đang thực hiện một thay đổi yêu cầu thực hiện thay đổi lược đồ, thay đổi phụ trợ và thay đổi giao diện người dùng.
Cùng với đó, giờ đây bạn có thể gửi một thay đổi lược đồ đơn giản để xem xét trước và trong khi thay đổi đó đang được xem xét, bạn có thể bắt đầu làm việc trên phần phụ trợ và giao diện người dùng. Sử dụng các PR xếp chồng lên nhau, tất cả 3 thay đổi này có thể được xem xét bởi 3 đánh giá khác nhau.
Trong trường hợp này, bạn có thể có một ngăn xếp giống như thế này trong đó demo/schema
, demo/backend
và demo/frontend
đại diện cho 3 nhánh xếp chồng lên nhau.
Cho đến nay, điều này có ý nghĩa, nhưng nếu bạn nhận được một số nhận xét đánh giá mã về thay đổi lược đồ yêu cầu tạo một cam kết mới thì sao? Đột nhiên lịch sử cam kết của bạn trông như thế này:
Bây giờ, bạn phải khởi động lại thủ công tất cả các nhánh tiếp theo và giải quyết xung đột ở mọi giai đoạn. Hãy tưởng tượng nếu bạn có 10 nhánh xếp chồng lên nhau, nơi bạn có thể phải giải quyết xung đột 10 lần.
Nhưng đó không phải là tất cả, việc hợp nhất một PR trong ngăn xếp có thể là một cơn ác mộng thực sự. Bạn có 3 tùy chọn squash
, merge
và rebase
để hợp nhất PR. Hãy cố gắng hiểu những gì đằng sau hậu trường trong mỗi người.
squash
, Git lấy các thay đổi từ tất cả các lần xác nhận hiện có của PR và viết lại chúng thành một lần xác nhận duy nhất. Trong trường hợp này, không có lịch sử nào được duy trì về nguồn gốc của những thay đổi đó.
Cam merge
là một loại cam kết Git đặc biệt được thể hiện bằng sự kết hợp của hai hoặc nhiều cam kết. Vì vậy, nó hoạt động rất giống với một cam kết squash
nhưng nó cũng nắm bắt thông tin về cha mẹ của nó. Trong một trường hợp điển hình, một cam kết hợp nhất có hai cha mẹ: cam kết cuối cùng trên nhánh cơ sở (nơi PR được hợp nhất) và cam kết trên cùng trên nhánh tính năng đã được hợp nhất.
Mặc dù cách tiếp cận này mang lại nhiều ngữ cảnh hơn cho lịch sử cam kết, nhưng nó vô tình tạo ra một lịch sử git phi tuyến tính có thể không mong muốn.
rebase
và merge, Git sẽ viết lại các cam kết vào nhánh cơ sở. Vì vậy, tương tự như tùy chọn cam kết squash
, nó sẽ mất mọi lịch sử liên quan đến các cam kết ban đầu.
Thông thường, nếu bạn đang sử dụng chiến lược merge
cam kết trong khi sắp xếp các PR, cuộc sống của bạn sẽ đơn giản hơn một chút, nhưng hầu hết các nhóm không khuyến khích sử dụng chiến lược đó để giữ cho lịch sử git sạch sẽ. Điều đó có nghĩa là bạn có khả năng sử dụng một cách hợp nhất squash
hoặc rebase
.
Và điều đó tạo ra xung đột hợp nhất cho tất cả các nhánh xếp chồng chưa được hợp nhất tiếp theo.
Trong ví dụ trên, giả sử chúng ta kết hợp demo/schema
nhánh đầu tiên vào dòng chính. Nó sẽ tạo một cam kết D1
mới chứa các thay đổi của A1
và A2
.
Vì Git không biết D1
đến từ đâu và demo/backend
vẫn dựa trên A2
, nên việc cố gắng khởi động lại demo/backend
trên đầu dòng chính sẽ tạo ra xung đột hợp nhất.
Tương tự như vậy, khởi động lại demo/frontend
sau khi khởi động lại demo/backend
cũng sẽ gây ra các vấn đề tương tự. Vì vậy, nếu bạn có mười nhánh xếp chồng lên nhau và bạn hợp nhất một trong số chúng, bạn sẽ phải giải quyết những xung đột này chín lần.
Chúng tôi vẫn chỉ đang làm trầy xước bề mặt; có nhiều trường hợp sử dụng khác như sắp xếp lại thứ tự các cam kết, tách, gấp và đổi tên các nhánh, có thể tạo ra chi phí quản lý rất lớn khi xử lý các PR xếp chồng lên nhau.
Đó là lý do tại sao chúng tôi xây dựng quản lý PR xếp chồng lên nhau như một phần của Aviator.
Hãy nghĩ về Aviator như một lớp nâng cao nằm trên công cụ hiện có của bạn. Aviator kết nối với GitHub, Slack, Chrome và Git CLI để cung cấp trải nghiệm nâng cao cho nhà phát triển.
Aviator CLI hoạt động trơn tru với mọi thứ khác! CLI không chỉ là một lớp trên Git mà còn hiểu ngữ cảnh của các ngăn xếp trên GitHub. Hãy xem xét một ví dụ.
Tạo một ngăn xếp khá đơn giản. Ngoại trừ trường hợp này, chúng tôi sử dụng av
CLI để tạo các nhánh nhằm đảm bảo rằng ngăn xếp được theo dõi. Chẳng hạn, để tạo nhánh lược đồ của bạn và PR tương ứng, hãy làm theo các bước bên dưới.
av stack branch demo/schema # make schema changes git commit -a -m "[demo] schema changes" av pr create
Vì Aviator cũng được kết nối với GitHub của bạn nên bạn có thể dễ dàng hình dung ngăn xếp.
Hoặc nếu bạn muốn trực quan hóa nó từ thiết bị đầu cuối, bạn vẫn có thể làm điều đó với các lệnh CLI:
Sử dụng ngăn xếp bây giờ trở thành một cuộc dạo chơi. Bạn có thể thêm các xác nhận mới vào bất kỳ nhánh nào và chỉ cần chạy av stack sync
từ bất kỳ đâu trong ngăn xếp để đồng bộ hóa tất cả các nhánh. Aviator tự động khởi động lại tất cả các nhánh cho bạn và nếu có xung đột hợp nhất thực sự, bạn chỉ cần giải quyết nó một lần.
Đây là nơi mà các công cụ Aviator dễ dàng nổi bật so với bất kỳ công cụ hiện có nào. Tại Aviator, chúng tôi đã xây dựng một trong những MergeQueue tiên tiến nhất để quản lý việc tự động hợp nhất hàng nghìn thay đổi trên quy mô lớn.
Aviator hỗ trợ tích hợp liền mạch với CLI và các PR xếp chồng lên nhau. Vì vậy, để hợp nhất một phần hoặc toàn bộ ngăn xếp PR, bạn có thể chỉ định chúng cho Aviator MergeQueue bằng CLI av pr queue
hoặc bằng cách đăng nhận xét trên GitHub: /aviator stack merge
.
Aviator tự động xử lý xác thực, cập nhật và tự động hợp nhất tất cả các ngăn xếp đã xếp hàng theo thứ tự.
Bây giờ khi các PR được hợp nhất, lần này bạn có thể chạy av stack sync --trunk
để cập nhật tất cả các PR và xóa tất cả các PR đã hợp nhất.
Các PR xếp chồng ban đầu có vẻ giống như nhiều công việc hơn do nhu cầu chia nhỏ các thay đổi thành các phần nhỏ hơn. Tuy nhiên, việc tăng hiệu quả đánh giá mã, vòng phản hồi nhanh hơn và cơ hội học tập nâng cao chắc chắn sẽ vượt xa chi phí này.
Khi chúng ta tiếp tục áp dụng các nguyên tắc dịch chuyển sang trái, các PR xếp chồng lên nhau sẽ ngày càng trở nên hữu ích.
Aviator CLI cung cấp một cách tuyệt vời để quản lý các PR xếp chồng lên nhau mà ít tẻ nhạt hơn rất nhiều. CLI là mã nguồn mở và hoàn toàn miễn phí. Chúng tôi rất muốn bạn dùng thử và chia sẻ phản hồi của bạn trên diễn đàn thảo luận của chúng tôi.
Tại Aviator, chúng tôi đang xây dựng các công cụ năng suất dành cho nhà phát triển từ những nguyên tắc đầu tiên để hỗ trợ các nhà phát triển xây dựng nhanh hơn và tốt hơn.