Phần 0 · Chương 0.4
Những yêu cầu bạn có thể kiểm chứng
Bạn sẽ tạo ra: Một lát cắt SRS với đầy đủ ID, độ ưu tiên và phương pháp kiểm chứng · khoảng 100 phút, bao gồm bài tập
Tài liệu gốc: SRS — Đặc tả yêu cầu phần mềm (tiếng Anh)
Chương 0.3 để lại cho chúng ta những bản đồ hành trình cùng các khoảnh khắc ★ của chúng — thứ tư duy sản phẩm sắc bén nhất mà chúng ta làm ra được cho đến giờ. Nhưng chúng vẫn là những câu chuyện — mà chuyện kể thì không gác cổng cho một bản phát hành. Khi ai đó hỏi "phần kết nối lại xong chưa?", một bản đồ hành trình chỉ trả lời bằng cảm giác. Thứ chúng ta cần là một câu văn chính xác đến mức một cỗ máy, một đồng đội, hay chính phiên bản đa nghi của chúng ta trong tương lai đều có thể trả lời có hoặc không — và chứng minh được. Đó chính là một yêu cầu hệ thống, và chương này sẽ chuyển hóa các bản đồ của chúng ta thành một cuốn sổ cái đầy những câu như thế. Luận đề, nói thẳng từ đầu: một yêu cầu không kèm kế hoạch kiểm thử chỉ là một ý kiến.
Giải phẫu một yêu cầu
Đây là một dòng trong SRS của Relay, được chọn vì bạn đã gặp nó hai lần rồi — chính là đường hầm của Tuan, nay được mài giũa đến độ chính xác:
FR-MSG-04 · The system shall accept a client-supplied idempotency key on
send. A repeated key within 24 hours shall return the original message
with 201-equivalent semantics and shall not create a duplicate.
Priority: P1 · Verification: T
(Dịch nghĩa: hệ thống phải chấp nhận một idempotency key do client cung cấp khi gửi;
một key lặp lại trong vòng 24 giờ phải trả về đúng tin nhắn gốc với ngữ nghĩa tương
đương 201 và không được tạo bản trùng.)
Bốn thành phần, mỗi thành phần gánh một việc thật. ID là một địa chỉ vĩnh viễn: FR (functional requirement — yêu cầu chức năng), MSG (họ yêu cầu về nhắn tin), 04 (không bao giờ tái sử dụng, kể cả khi yêu cầu này một ngày nào đó bị gỡ bỏ — một ID có thể mang hai nghĩa xuyên suốt lịch sử tài liệu còn tệ hơn không có ID). Câu phát biểu dùng shall — động từ chịu lực của nghề viết đặc tả: không phải "should" (một nguyện vọng), không phải "will" (một lời tiên đoán) — mà là một nghĩa vụ, với đối tượng cụ thể và kết quả đo được. Độ ưu tiên buộc dòng này vào lộ trình giao hàng. Và phương pháp kiểm chứng trả lời câu hỏi phân định giữa kỹ nghệ và mơ ước: làm sao chúng ta biết?
SRS dùng bốn phương pháp kiểm chứng, và biết chọn giữa chúng là một kỹ năng đáng luyện. T — kiểm thử tự động: một phép kiểm tự động có thể đậu hoặc rớt; FR-MSG-04 là T, vì một đoạn script có thể gửi cùng một key hai lần rồi đếm số tin nhắn. D — trình diễn: một con người cho thấy nó chạy; FR-DSH-01 — dashboard phải hiện API key của môi trường development ngay màn hình đầu tiên sau đăng ký — là D, vì "màn hình đầu tiên" là thứ để nhìn, không phải để assert. I — thanh tra: bạn soi một hiện vật; bản đặc tả OpenAPI công bố của EIR-API-07 được kiểm chứng bằng cách đọc, không phải bằng cách chạy. Và A — phân tích: phương pháp tinh tế nhất. FR-MSG-06, nguyên văn trọn vẹn: "An acknowledged message shall not be lost" — một tin nhắn đã được xác nhận không được phép thất lạc. Không một lần chạy test nào chứng minh nổi một mệnh đề phủ định trên mọi tương lai — kiểm chứng nó đòi hỏi lập luận về thiết kế cộng với bằng chứng fault-injection, và đó chính xác là nghĩa của "phân tích". Khi bạn không gọi tên nổi phương pháp nào trong bốn cho một dòng nháp, nghĩa là bạn chưa viết ra một yêu cầu.
Kỷ luật của cuốn sổ cái
SRS của Relay hiện chứa 224 yêu cầu. Con số ấy đáng để bạn giật mình trong đúng năm giây — cho đến khi bạn thấy nửa còn lại của kỷ luật: mỗi yêu cầu mang một độ ưu tiên từ P1 đến P5, và các độ ưu tiên không phải cảm tính, chúng là phase. P1 là vòng lặp cốt lõi — sản phẩm không tồn tại nếu thiếu nó; P2 là bề mặt nền tảng; P3 là phân tích và đo đếm (nay có thêm media); P4 là trải nghiệm lập trình viên; P5 được ghi nhận nhưng chưa xếp lịch. Trong 224 dòng, đúng 57 dòng là P1. SRS nói không vòng vo: Phase 1 là cột mốc đầu tiên thực tế, và mọi thứ phía sau nó được xếp thứ tự, chứ không làm đồng thời. Một tài liệu yêu cầu không có độ ưu tiên chỉ là một danh sách điều ước được định dạng đẹp đẽ.
Và những P1 ấy từ đâu ra? Hãy nhìn dấu vân tay của chúng. Thứ tự do server ấn định, gửi đẳng xâm (idempotent), backfill khi kết nối lại, cách ly tenant — đó chính là các khoảnh khắc ★ của chương 0.3 khoác lên mình những chiếc ID. Những chặng chúng ta gắn sao là những chặng nhận độ ưu tiên cao nhất — đúng như sứ mệnh của những ngôi sao.
Truy vết thứ nhất: đường hầm của Tuan hóa thành ba ID
Hãy lần theo một ★ xuống tận đáy. Khoảnh khắc mất sóng của Tuan, bằng ngôn ngữ hành trình, đòi hỏi: retry phải an toàn, bắt kịp phải chính xác, kết nối lại không được nướng cạn pin. Trong SRS, những câu ấy có địa chỉ. Cú retry an toàn là FR-MSG-04 ở trên. Cú bắt kịp chính xác là FR-RTM-03 — khi kết nối lại với một resume cursor, hệ thống phải giao mọi tin nhắn có số thứ tự lớn hơn cursor, cho mọi channel mà người dùng là thành viên (P1, T). Còn viên pin là FR-SDK-04 — tự động kết nối lại với exponential backoff kèm jitter, trần 30 giây (P4, T — SDK ship ở Phase 4, và bản thân điều đó là một quyết định xếp thứ tự: giao thức hỗ trợ resume từ ngày đầu; bộ máy client bóng bẩy đến sau).
Truy vết thứ hai: ngày thứ Ba của Priya, và dòng quan trọng nhất của cả tài liệu
Khoảnh khắc ★ tái dựng của Priya đòi hỏi một bộ lịch sử phân biệt được "chưa từng gửi", "đã bị xóa" và "đã bị sửa". Riêng chặng ấy biện minh cho cả một chòm sao nhỏ: FR-MSG-07 (lịch sử chỉnh sửa bất biến, mọi phiên bản trước đều có dấu thời gian), FR-MSG-08 (xóa sinh ra tombstone, đúng chỗ, đúng thứ tự), FR-MSG-10 (phản hồi lịch sử bao gồm cả tombstone), và FR-MOD-01 (người kiểm duyệt truy xuất được lịch sử đầy đủ qua API key, không bị giới hạn bởi membership). Bốn ID, một ngày thứ Ba.
Nhưng SRS dành ngôn từ mạnh nhất cho một dòng khác. Nó chú giải FR-TEN-05 là yêu cầu quan trọng nhất trong tài liệu này:
FR-TEN-05 · No API operation shall return, modify, or reveal the
existence of data belonging to another tenant, under any input.
Priority: P1 · Verification: T, A
(Dịch nghĩa: không một thao tác API nào được phép trả về, sửa đổi, hay để lộ sự tồn tại của dữ liệu thuộc về một tenant khác, dưới bất kỳ đầu vào nào.)
Hãy để ý mọi điều mà một dòng này dạy ta. Vi phạm được phân loại Sev-0 — không phải mức nghiêm trọng gán sau khi sự cố xảy ra, mà là một lời hứa được đưa ra từ trước. Phương pháp kiểm chứng là cả T lẫn A: một bộ tấn công cross-tenant tự động chạy trên mọi endpoint ở mọi lần build, và bản thân thiết kế được phân tích để sự cách ly mang tính cấu trúc thay vì được vá-bằng-test. Người bạn đồng hành của nó, NFR-MNT-02, đặt sàn độ phủ: logic nghiệp vụ tối thiểu 70%, nhưng thứ tự tin nhắn, đẳng xâm và cách ly tenant phải đạt 100% độ phủ nhánh — ba phân hệ mà một nhánh bị bỏ sót đồng nghĩa một tin nhắn thất lạc hoặc một tenant bị lộ. Tính kiểm chứng không phải món trang trí hành chính; nó là cách một đội hai người đưa ra lời hứa mà một chuyên viên kiểm định bảo mật của tập đoàn Fortune 500 chấp nhận được.
Một bản đặc tả hấp thụ thay đổi mà không nói dối
Đây là phần mà hầu hết các bài hướng dẫn về yêu cầu đều bỏ qua: chuyện gì xảy ra khi sản phẩm đổi ý? Relay vừa làm đúng điều đó — và bạn đã tận mắt chứng kiến. Chương 0.1 từng ghi "không lưu trữ file" như một non-goal, rồi đảo ngược nó một cách công khai khi một bản thiết kế trả lời được mọi lý do đã nêu. Hãy nhìn cú đảo ngược ấy tác động lên SRS thế nào: nó không viết lại lịch sử. Nó xuất hiện như một mục hoàn toàn mới — §4.14, từ FR-MED-01 đến FR-MED-14, mười bốn ID mới với độ ưu tiên và phương pháp kiểm chứng của riêng chúng — trong khi mọi ID cũ giữ nguyên ý nghĩa. Cuốn sổ cái dày lên; nó không bao giờ nói dối.
Và mục mới lập tức nhập lại vào những cuộc trò chuyện cũ. Hãy đọc FR-MED-09:
FR-MED-09 · A rejected attachment shall render as an explicit rejection
marker in history — never as a broken link — preserving the record that
something was sent (Priya's reconstruction must distinguish "rejected
upload" from "deleted message").
Priority: P3 · Verification: T
(Dịch nghĩa: một tệp đính kèm bị từ chối phải hiển thị trong lịch sử như một dấu từ chối tường minh — không bao giờ là một liên kết hỏng — để bảo toàn bằng chứng rằng đã có thứ gì đó được gửi; cú tái dựng của Priya phải phân biệt được "upload bị từ chối" với "tin nhắn đã xóa".)
Một yêu cầu được viết nhiều tháng sau khi hành trình của Priya được vẽ, gọi đích danh khoảnh khắc ★ của cô. Đống giấy tờ không phải một giai đoạn đã hoàn thành; nó là một khí cụ đang sống, mà mọi công việc mới đều phải trả lời trước nó.
Đến lượt bạn
Đã đến lúc viết ra những yêu cầu mà các bản đồ hành trình của bạn vẫn đang ngầm gợi ý — từ 8 đến 15 dòng, không hơn. (Vẫn theo đuổi công cụ đặt lịch phòng khám thú y? Tốt lắm.)
Bài tập 1 — lát cắt SRS. Đi qua hai bản đồ hành trình của bạn, các chặng ★ trước
tiên. Phát minh một bộ ID theo họ, một lần duy nhất — VET-REM-01 cho nhắc hẹn,
VET-PRT-01 cho cổng thông tin, miễn sao vừa vặn — rồi giữ nó mãi mãi. Với mỗi yêu
cầu, viết trọn một dòng: ID; một câu shall với đối tượng cụ thể và kết quả đo
được; một độ ưu tiên kèm lý do phase trong một câu ("P1 — sản phẩm vô nghĩa nếu lời
nhắc không đến nơi"); và đúng một phương pháp kiểm chứng, T, D, I hoặc A. Các khoảnh
khắc ★ của bạn phải nổi lên thành những độ ưu tiên cao nhất — nếu không, hoặc các
ngôi sao sai, hoặc các độ ưu tiên sai.
Bài tập 2 — cuộc săn ý kiến. Giờ hãy tấn công chính lát cắt của mình. Với từng dòng, viết ra đúng một bài kiểm thử, một màn trình diễn, một cuộc thanh tra hay một phép phân tích có thể khiến nó rớt. Không phải xác nhận nó — mà đánh rớt nó. Đây là bài tập mẫu trên kẻ phạm lỗi kinh điển:
Trước: Hệ thống shall nhanh.
Không gì đánh rớt nổi câu này. "Nhanh" không có đối tượng, không có con số, không có người quan sát. Nó là một ý kiến khoác chiếc áo shall.
Sau:
VET-REM-03· Một lời nhắc hẹn shall được giao trong vòng 5 phút so với giờ hẹn định sẵn, cho 99% số lời nhắc trong một tháng dương lịch. Priority: P1 · Verification: A (đo trên lưu lượng production; một bài test đơn lẻ không thể xác lập một bách phân vị theo tháng).Giờ có ba thứ đánh rớt được nó: phép đo, bách phân vị, và hạn chót.
Bất kỳ dòng nào của bạn mà không gì đánh rớt nổi đều là một ý kiến — hãy viết lại với một con số và một người quan sát, hoặc gạch bỏ.
Các câu tự kiểm. Mỗi câu trả lời được bằng có hoặc không:
- Mỗi khoảnh khắc ★ có sinh ra một yêu cầu, và những yêu cầu ấy có mang độ ưu tiên cao nhất của bạn?
- Mỗi dòng có đúng một phương pháp kiểm chứng — và bạn có thể bắt tay viết bài test/trình diễn/thanh tra/phân tích ấy ngay ngày mai?
- Cuộc săn ý kiến có giết chết hoặc chữa lành ít nhất một dòng? (Nếu không, hãy săn gắt hơn — một bản nháp đầu tiên không chứa ý kiến nào là loài chưa ai từng quan sát được ngoài tự nhiên.)
- Bộ ID của bạn có sống sót nổi ba năm sản phẩm biến chuyển xung quanh nó?
Hãy lưu lát cắt này cạnh các tài liệu Phần 0 còn lại, trong repository. Chương 0.5 quyết định kiến trúc — và nó sẽ bị phán xét theo đúng một chuẩn mực duy nhất: liệu nó có thỏa mãn nổi những dòng này hay không.
Những điều đọng lại
Nếu bạn không đọc gì khác trong chương này, hãy giữ lấy những điều sau:
- Một yêu cầu không kèm kế hoạch kiểm thử chỉ là một ý kiến. Mỗi dòng trả lời câu "làm sao chúng ta biết?" bằng một trong bốn phương pháp: kiểm thử tự động, trình diễn, thanh tra, phân tích.
- ID là những lời hứa. Bền vững, không bao giờ tái sử dụng, có tiền tố theo họ — một địa chỉ vĩnh viễn mà mã nguồn, test và tài liệu có thể trích dẫn trong nhiều năm.
- Độ ưu tiên là phase, không phải cảm tính. 224 yêu cầu, 57 dòng ở Phase 1 — xếp thứ tự, chứ không làm đồng thời. Các khoảnh khắc ★ của bạn trở thành các P1 của bạn.
- Yêu cầu quan trọng nhất là yêu cầu được kiểm thử ở mọi lần build. Bộ tấn công cross-tenant của FR-TEN-05 và bộ ba 100%-độ-phủ-nhánh cho thấy "không thể thương lượng" trông ra sao trong thực tế.
- Một bản đặc tả sống hấp thụ thay đổi bằng ID mới, không bao giờ bằng sửa đè. Mục FR-MED là một non-goal bị đảo ngược, đến nơi dưới dạng mười bốn câu kiểm chứng được — chuỗi giấy tờ tự khép vòng trong thời gian thực.