Công việc bắt đầu sau khi merge

8 phút đọc

Cũng có bằng English, Español, Português, 简体中文, 日本語, 한국어, Deutsch, Français, ไทยTe Reo Māori.

Trước đây, merge từng là vạch đích. Bạn mở một pull request, ai đó review nó, nó được đưa vào, và thế là thay đổi đã hoàn tất. Các tác nhân viết code đã âm thầm dịch chuyển vạch đích đó. Khi một tác nhân nhận một issue trên Linear, viết code, và mở một merge request trong khi bạn đang họp, merge không còn là điểm kết thúc của công việc nữa — nó là điểm khởi đầu của mọi thứ mà merge đó chạm tới.

Merge không còn là vạch đích nữa

Một merge không bao giờ chỉ đơn thuần là một merge. Mỗi thay đổi đều dựa vào các hệ thống xung quanh nó: issue giờ đây lẽ ra phải được đóng lại, tài liệu từ sáng nay đã mô tả một điều gì đó không còn hoàn toàn đúng, CI đỏ hơn một chút so với hôm qua, ghi chú phát hành mà chưa ai viết, cuộc trò chuyện hỗ trợ vẫn đang chờ một bản sửa lỗi thực ra đã được triển khai từ nhiều giờ trước.

Khi một kỹ sư chỉ triển khai một vài thay đổi mỗi tuần, công việc theo sau đó vừa đủ lấp vào những khoảng trống. Bạn đóng issue trong khi pull request vẫn đang mở; bạn nhớ ra tài liệu vì vừa mới chạm vào đoạn code đó. Khi một tác nhân — hay cả một đội quân tác nhân — triển khai nhiều thay đổi mỗi ngày, những khoảng trống đó tràn ngập. Code không còn là nút thắt cổ chai nữa. Mọi thứ nằm ở phía sau code mới là nút thắt cổ chai.

Mô hình bảo trì không hề thay đổi

Việc phát triển đã trở nên nhanh hơn. Việc bảo trì thì không. Các công cụ chúng ta dùng để giữ cho một dự án nhất quán phần lớn vẫn là thủ công, và vẫn phụ thuộc vào việc ai đó nhớ ra để dùng chúng đúng lúc:

  • Một merge request được đưa vào, nhưng issue trên Linear mà nó giải quyết vẫn còn mở.
  • Tài liệu vẫn mô tả hành vi cũ, và không ai chắc chắn đó là trang nào.
  • CI đã lỗi từng đợt suốt một tuần và mọi người đã học cách bỏ qua nó.
  • Một feature flag từ ba tháng trước không có chủ sở hữu cũng không có ngày gỡ bỏ.
  • Bộ phận hỗ trợ trả lời một ticket bằng một giải pháp tạm thời cho một lỗi thực ra đã được sửa từ thứ Ba.
  • Ai đó hỏi phiên bản này đã phát hành những gì, và câu trả lời thành thật là "để tôi xem lại git log đã".

Không điều nào trong số này là mới, và không điều nào trong số này thực sự là vấn đề của tác nhân. Đó là entropy thông thường của một dự án phần mềm. Tác nhân chỉ đơn giản là đẩy nhanh tốc độ cho đến khi hệ thống không chính thức từng hấp thụ những việc này không còn theo kịp nữa.

Việc dọn dẹp theo lệnh không thể mở rộng quy mô

Giải pháp hiển nhiên là yêu cầu tác nhân dọn dẹp luôn, và bạn hoàn toàn có thể làm vậy. Nhắc @taskgoblin trên merge request và bảo nó cập nhật tài liệu, đóng issue, soạn ghi chú phát hành. Cách này hiệu quả. Nhưng nó phụ thuộc vào nguồn lực khan hiếm nhất trong toàn bộ vòng lặp: một con người nhớ để yêu cầu, mỗi lần, đúng thời điểm.

Bảo trì không phải là một tác vụ làm một lần; đó là một vòng lặp. "Kiểm tra xem tài liệu có cập nhật không" không phải việc bạn làm một lần. "Đảm bảo các issue đã merge được đóng lại" cũng không phải việc bạn làm một lần. Bất cứ điều gì chờ một người nhận ra rằng đã đến lúc chạy vòng lặp sẽ được thực hiện một cách thiếu nhất quán — vì con người vốn thiếu nhất quán trong việc nhận ra điều đó, đặc biệt là khi toàn bộ mục đích của tác nhân là để không còn phải giữ tất cả những điều này trong đầu nữa. Việc dọn dẹp theo lệnh chuyển công việc sang cho tác nhân, nhưng lại để nguyên việc lên lịch cho công việc đó ở đúng chỗ cũ: chính là bạn.

Vì sao chúng tôi xây dựng Loops

Một lượt chạy tác nhân thông thường được kích hoạt bởi một sự kiện — việc gán một issue, một lượt nhắc tên, một pull request mới. Một Loop được kích hoạt bởi thời gian. Bạn đưa cho tác nhân một chỉ thị cố định và một nhịp độ — mỗi sáng ngày làm việc, mỗi thứ Hai, ngày đầu tiên của tháng — và nó tự chạy, trong một sandbox, với cùng các công cụ và cùng quyền truy cập như bất kỳ lượt chạy nào khác.

Chỉ thị chính là toàn bộ nhiệm vụ, và những chỉ thị tốt đọc lên giống một bản mô tả công việc hơn là một điều ước: cần xem xét gì, kho lưu trữ nào, phải làm gì, không được làm gì, và — phần khiến nó an toàn để chạy không cần giám sát — phải làm gì khi không có việc gì để làm, tức là không làm gì cả.

Mỗi sáng ngày làm việc lúc 09:00, hãy xem các merge request đã được merge trong ngày qua tại group/repo, và đóng bất kỳ issue nào trên Linear mà chúng giải quyết mà vẫn còn mở. Nếu không có issue nào, thì không làm gì cả.

Đó là một vòng lặp bảo trì có chủ sở hữu. Nó không chờ bạn nhớ ra. Vì một lượt chạy theo lịch là một lượt chạy tác nhân đầy đủ, nó có thể đi trọn vẹn cả chặng đường: không chỉ đánh dấu tài liệu đã lỗi thời mà còn mở merge request để sửa nó; không chỉ nhận ra rằng các issue đã merge bị trôi dạt về trạng thái mở mà còn đóng chúng lại — rồi báo cáo đến nơi bạn thực sự sẽ nhìn thấy, dưới dạng bình luận trên issue Linear, tin nhắn trong kênh Slack bạn đã chỉ định, hoặc email nếu không có nơi nào tốt hơn.

Và vì nó tái sử dụng mọi thứ mà một lượt chạy bình thường đã làm, những trường hợp hóc búa đều đã được xử lý. Thời gian bị lỡ sẽ bị bỏ qua thay vì được chạy bù, vì vậy một bộ lập lịch bị gián đoạn trong một giờ sẽ không thức dậy rồi bắn ra hàng trăm lượt chạy bù cho bạn. Mỗi lượt chạy có ngân sách và rào chắn an toàn riêng của nó. Chúng tôi cung cấp sẵn một bộ mẫu khởi đầu dành riêng cho những vòng lặp này — giữ issue và merge đồng bộ, theo dõi CI đã đỏ quá lâu, truy tìm các feature flag đã sống lâu hơn cả chủ sở hữu của chúng, soạn ghi chú phát hành khi mọi thứ được triển khai — vì những vòng lặp hữu ích thường giống nhau ở hầu hết các nhóm. Bạn chỉ cần điền vào kho lưu trữ và kênh của mình; các rào chắn an toàn đã được viết sẵn.

Công việc của kỹ sư được nâng lên một tầm cao mới

Ẩn sau tất cả những điều này là một nỗi lo: rằng tự động hóa việc bảo trì đồng nghĩa với việc tự động hóa cả khả năng phán đoán. Không phải vậy. Nó nâng khả năng phán đoán lên một tầm cao hơn. Khi các vòng lặp tự vận hành, bạn không còn là người phải nhớ đóng issue nữa mà trở thành người quyết định vòng lặp nào nên tồn tại, rào chắn an toàn của chúng là gì, và "hoàn thành" nghĩa là gì đối với từng vòng lặp. Bạn xem xét chỉ thị cố định thay vì tự mình chạy việc vặt.

Dù sao đi nữa, đó cũng là phiên bản dày dạn kinh nghiệm hơn của công việc này. Tác nhân đã giúp việc viết code trở nên rẻ hơn; điều còn lại là quyết định điều gì nên đúng về hệ thống và đảm bảo nó luôn đúng như vậy. Loops là cách bạn giữ cho điều đó luôn đúng mà không phải mang tất cả trong đầu — tác nhân tạo ra công việc, và một vòng lặp cố định sẽ duy trì nó.