Các thỏa thuận là một phần thiết yếu của phát triển phần mềm. Họ giảm chi phí phát triển và làm cho cuộc sống của các nhà phát triển dễ dàng hơn. Nhưng có một vấn đề - chúng thường làm phức tạp hóa mọi thứ bởi vì chúng không được ghi lại và truyền miệng một cách chính xác trong nhóm, giống như những câu chuyện cổ tích cũ. Trong khi lan rộng, các thỏa thuận thay đổi. Đột nhiên, những chi tiết mới xuất hiện và những chi tiết cũ biến mất. Cuối cùng, mọi thành viên trong nhóm đều có hình ảnh về thỏa thuận của riêng họ trong đầu và thậm chí hình ảnh đó đôi khi biến mất.
Tệ hơn nữa - khi các nhóm bắt đầu ghi lại những thỏa thuận này, họ thực hiện nó một cách bừa bãi và thường tạo ra một mớ hỗn độn các tài liệu được liên kết lỏng lẻo, một nửa trong số đó thậm chí còn không được cập nhật.
Trong bài viết này, tôi sẽ cho bạn biết cách đúng đắn để ghi lại các thỏa thuận, vì vậy họ sẽ giúp bạn.
Vì vậy, làm thế nào chúng ta có thể làm cho thỏa thuận hữu ích? Chúng tôi không chỉ phải ghi lại chúng mà còn phải làm điều đó sao cho:
chúng rất dễ sử dụng;
tuân theo các thỏa thuận này đòi hỏi nỗ lực tối thiểu;
sẽ dễ hiểu nếu những thỏa thuận này vẫn còn hiệu lực;
sẽ dễ hiểu tại sao những thỏa thuận này thậm chí còn tồn tại;
lý tưởng - chúng được tự động hóa.
Người ta có thể đưa ra rất nhiều cách để phân loại các thỏa thuận. Tôi sẽ chia chúng theo mức độ trừu tượng của chúng:
Các thỏa thuận ở các cấp độ khác nhau đòi hỏi những cách khác nhau để ghi lại chúng và mang lại những lợi ích khác nhau. Chúng ta hãy xem xét từng cấp độ.
Mục đích của các thỏa thuận này là làm cho mã thống nhất, toàn diện và dễ đọc. Dưới đây là một số ví dụ:
Chúng tôi sử dụng dấu ngoặc kép thay vì dấu ngoặc đơn.
Chúng tôi không gọi ENV trực tiếp từ mã ngoại trừ trong lớp Config
, nơi chúng tôi đưa các lệnh gọi này vào các phương thức.
Các đối tượng dịch vụ có Service
hậu tố và một call
phương thức công khai.
Những loại thỏa thuận này được tạo ra để giảm tải nhận thức của người đọc và giúp anh ta làm quen với mã chưa biết nhanh hơn. Giống như Martin đã nói, mã được đọc nhiều hơn gấp 10 lần so với viết.
Bất chấp ý kiến của bạn về khung công tác Ruby on Rails - cốt lõi của nó có một convention over configuration
, cho phép bất kỳ nhà phát triển Rails nào mở dự án của người khác và ngay lập tức điều hướng nó khá tốt.
Vậy làm thế nào để ghi lại những quy ước này? Công cụ lót! Nếu không có quy tắc nói dối phù hợp, hãy viết lời nói dối của riêng bạn. Hầu như mọi kẻ nói dối đều cho phép bạn làm điều đó: đây là một ví dụ trong ngôn ngữ Go và đây là cho ngôn ngữ Ruby .
Sử dụng kẻ nói dối cho các quy ước như vậy mang lại cho bạn ba lợi ích:
Nhà phát triển không cần phải nghĩ về chúng - kẻ nói dối sẽ đánh dấu mọi lỗi và thậm chí thường sửa chúng cho bạn.
Nếu bạn sử dụng đánh giá mã trong nhóm của mình - bạn giải phóng người đánh giá khỏi suy nghĩ về những điều này và cho họ thêm thời gian để xem xét những điều quan trọng hơn.
Nhà phát triển sẽ thấy một vấn đề ngay khi bắt đầu chu kỳ phát triển, vì vậy anh ta sẽ khắc phục nó ngay lập tức mà không mất thời gian quay lại bối cảnh sau đó. Nó trở nên rẻ hơn để giữ thỏa thuận.
Thêm một phần thưởng nữa: viết quy tắc kẻ nói dối mới là cách đào tạo tuyệt vời cho nhà phát triển cơ sở. Trong khi hoàn thành nhiệm vụ này, anh ấy sẽ học được rất nhiều điều về phân tích cú pháp mã và xây dựng AST cũng như hiểu sâu hơn về ngôn ngữ.
Đây là một loại thỏa thuận cấp cao hơn nhằm mục đích làm cho kiến trúc của bạn chu đáo, mạch lạc và thống nhất. Một vài ví dụ:
Chúng tôi sử dụng Python để viết các dịch vụ thông thường và Elixir trong các phần được tải cao của hệ thống.
Phần phụ trợ trả về lỗi ở định dạng được mô tả.
Mỗi dịch vụ được yêu cầu gửi số liệu trong prometheus, trên điểm cuối /metrics
, cổng để gửi số liệu được định cấu hình bởi biến môi trường PROMETHEUS_PORT
.
Những thỏa thuận như vậy không chỉ giảm tải nhận thức mà còn giải quyết thêm ba vấn đề:
Giảm chi phí vận hành. Nếu các dịch vụ được khởi chạy theo cùng một cách, với cùng định dạng nhật ký, xuất bản cùng số liệu, thì việc duy trì dịch vụ và đối phó với các sự cố sẽ dễ dàng hơn nhiều.
Giảm chi phí thiết kế. Nhà phát triển không cần phải thiết kế kiến trúc từ đầu mọi lúc - bạn đã nghĩ trước và bây giờ anh ta chỉ cần thiết kế một tính năng hoặc dịch vụ cụ thể mà không phải lo lắng về những điều cơ bản.
Giảm chi phí truyền thông. Nếu định dạng phản hồi hoặc sự kiện của máy chủ trong Kafka được xác định trước, các nhà phát triển không cần phải thảo luận về tương tác của họ mỗi lần, thay vào đó họ có thể chỉ cần tham khảo quy ước.
Những thỏa thuận như vậy phức tạp hơn và tôi muốn khắc phục chúng theo hai bước.
Bước 1 - Mô tả
Bản ghi quyết định kiến trúc (ADR) là một công cụ để ghi lại các thỏa thuận đó. Điểm hấp dẫn của nó là nó nắm bắt thông tin meta cùng với một thỏa thuận: tại sao một thỏa thuận như vậy được thông qua; những lựa chọn thay thế đã được thảo luận; khi nó được sửa đổi lần cuối; thỏa thuận vẫn còn hiệu lực?
Điều này cho phép thành viên mới trong nhóm hiểu lý do của các quyết định được đưa ra và không hỏi những người xung quanh về điều đó.
ADR bao gồm một số khối chính:
Thỏa thuận giải quyết vấn đề gì?
Những lựa chọn nào để giải quyết vấn đề đã được xem xét, ưu và nhược điểm của chúng là gì?
Lựa chọn nào đã được chọn cuối cùng?
Có thể có các khối bổ sung - ví dụ: tính toán chi phí triển khai.
Sẽ thuận tiện hơn nếu giữ ADR trong một hệ thống nơi người ta có thể xem lịch sử thay đổi và thảo luận. Lựa chọn của tôi là Github và Notion, mỗi cái đều có ưu và nhược điểm. Ưu điểm của Github là nó có sẵn công cụ đánh giá và lịch sử phiên bản. Notion có thể là một giải pháp tốt do sự tiện lợi khi làm việc với cơ sở dữ liệu và thẻ. Và ngoài ra - những người không phải là nhà phát triển có thể dễ dàng xử lý nó.
Nếu bạn muốn bắt đầu với ADR, tôi khuyên bạn nên xem kho lưu trữ , nơi bạn có thể tìm thấy các mẫu ADR khác nhau và các ví dụ về cách sử dụng chúng.
Bước 2 - Tự động hóa
ADR khó tự động hóa hơn so với các quy ước ở cấp độ mã: thiết kế linters vẫn chưa được phát minh (thật đáng tiếc!). Tuy nhiên, có thể tự động hóa một phần chúng, tùy thuộc vào loại thỏa thuận đó là gì.
Tạo và cập nhật các mẫu dịch vụ cho các thỏa thuận về ngôn ngữ, thư viện và dịch vụ nhúng vào cơ sở hạ tầng. Sau đó, nhà phát triển sẽ không viết các dịch vụ mới từ đầu mà sao chép nó từ mẫu và ngay lập tức nhận được Dockerfile đã định cấu hình, xuất bản số liệu, v.v.
Tương tự, bạn có thể tạo các trình tạo lớp trong một ứng dụng. Giả sử bạn đã đồng ý về một số lớp ứng dụng (bộ điều khiển => biểu mẫu => đối tượng dịch vụ). Trong trường hợp đó, bạn có thể tạo một lệnh console đơn giản để tạo tất cả các lớp cho một tính năng mới cùng một lúc.
Nếu bạn đã đồng ý về một số nguyên tắc không thể tự động hóa theo cách này, thì bạn có thể tổ chức danh sách kiểm tra được tự động thêm vào yêu cầu hợp nhất hoặc tác vụ trong trình theo dõi; do đó, nhà phát triển có thể nhanh chóng xem qua chúng trước khi chuyển giao nhiệm vụ.
Có nhiều thỏa thuận cho các quy trình trong mỗi công ty, ví dụ:
Mô tả về cách tuyển dụng trong công ty hoạt động.
Mô tả quá trình giới thiệu bản phát hành.
Yêu cầu đánh giá thiết kế cho các nhiệm vụ lớn.
Tiến hành họp nhóm hai lần một tuần để thảo luận về các nhiệm vụ và trở ngại hiện tại.
Cho đến gần đây, tôi không nghĩ đến việc ghi lại những thỏa thuận này, mặc dù chúng ảnh hưởng đáng kể đến sự thành công của công ty. Tài liệu của các thỏa thuận này không chỉ mang lại lợi ích của các loại được đề cập ở trên mà còn cho phép bạn hợp lý hóa các quy trình, chuyển chúng sang mặt phẳng hữu hình và suy nghĩ về tính hiệu quả của chúng.
Tôi lấy ý tưởng từ . Ông đã đề xuất một công cụ tương tự như ADR - Process Decision Record (PDR). Sự khác biệt duy nhất là thay vì các quyết định về kiến trúc, nó mô tả các quyết định về quy trình. Ngoài ra, anh ấy đề xuất đặt một "ngày suy nghĩ lại" trong mỗi PDR - ngày mà bạn quay lại tài liệu để xem liệu nó có giải quyết được vấn đề của bạn theo cách tốt nhất hay không, n tháng sau khi áp dụng (nhân tiện, bạn cũng có thể làm như vậy với ADR).
Đối với tự động hóa, bạn có thể làm rất ít. Bạn có thể tự động hóa một số quy trình bằng cách thiết lập quy trình làm việc trong Jira, đặt lời nhắc cho các cuộc họp hoặc tạo bot tự động chuẩn bị bản trình bày kết quả của tuần (tuy nhiên, tôi đã làm điều này ở một công ty nước ngoài).
Nhưng thông thường, bạn không thể thực sự tự động hóa các quy trình và mục tiêu chính của bạn là làm cho chúng dễ tuân theo hơn là không tuân theo. Tuy nhiên, việc ghi lại các thỏa thuận vẫn sẽ hữu ích, ngay cả khi các quy trình của bạn đã dễ thực hiện - việc chính thức hóa và hợp lý hóa sẽ cho phép bạn cải thiện chúng.
Tài liệu và quá trình tự động hóa tiếp theo mang lại nhiều lợi ích: thời gian dành cho việc phát triển giảm đi, các ứng dụng trở nên dễ hỗ trợ hơn và các quy trình trở nên thông minh hơn.
Người ta có thể nghĩ rằng tất cả điều này là quan liêu không cần thiết bởi vì "chúng tôi là những người tốt - chúng tôi có thể phát triển mã mà không cần nó." Nhưng trên thực tế, các thỏa thuận sẽ giúp bạn tiết kiệm đáng kể thời gian và tiền bạc, đồng thời bảo vệ các tế bào thần kinh của nhân viên. Chắc chắn, bạn không cần phải giải quyết tuyệt đối và từ chối bất kỳ điều gì đi ngược lại thỏa thuận - đây có thể là dấu hiệu cho thấy thỏa thuận cần được cập nhật hoặc ban đầu bạn không nghĩ đến một số khía cạnh của nó.
Nếu bạn chưa bắt đầu ghi lại các thỏa thuận trong nhóm của mình, hãy chuyển từ các mức trừu tượng thấp hơn sang các mức cao hơn: bắt đầu từ các thỏa thuận cấp mã, sau đó là cấp kiến trúc và chỉ sau đó xử lý ở cấp quy trình. Tài liệu về các thỏa thuận là một thói quen cần phát triển trong nhóm của bạn và việc bắt đầu với các khái niệm ít trừu tượng hơn sẽ dễ dàng hơn nhiều.
Ngoài ra, không phải tất cả các loại được mô tả trong bài viết. Ví dụ: bạn có thể ghi lại thỏa thuận thiết kế dưới dạng các thành phần thư viện.
Mỗi loại thỏa thuận mới đều trải qua ba giai đoạn giống nhau:
Tìm hiểu làm thế nào để ghi lại nó.
Tìm hiểu làm thế nào để tự động hóa nó.
Khi thời gian trôi qua, hãy đảm bảo nó tiết kiệm nhiều tài nguyên hơn mức cần thiết để giữ nó.
Và điều cuối cùng. Trong quá trình lập tài liệu, có thể thấy rằng một số thỏa thuận hiện có rõ ràng là không hợp lý, lãng phí thời gian của nhóm bạn và nói chung là có hại, nhưng bạn đã quen với chúng. Trong trường hợp này, bạn phải vượt qua rào cản thói quen trong tâm trí của nhóm và thuyết phục nhóm của bạn rằng việc từ chối các thỏa thuận đôi khi quan trọng hơn là chấp nhận chúng. Nhưng đó là một câu chuyện hoàn toàn khác.
Cũng được xuất bản ở đây .