Nguyen Le PhongNguyen Le Phong

System Design Interview bắt đầu từ việc làm rõ yêu cầu

Một hướng dẫn thực tế cho những phút đầu của System Design Interview: làm rõ người dùng, quy mô, luồng chính, ràng buộc và trade-off trước khi chọn công cụ.

Chiếc nắp bút marker vừa bật khẽ thì interviewer đọc xong đề bài: “Hãy thiết kế một hệ thống lưu trữ ảnh.” Chưa đầy một phút sau, trên bảng trắng có thể đã xuất hiện ba ô quen thuộc: object storage để giữ file, database để lưu metadata và CDN để phân phối ảnh.

Một software engineer dừng lại bên bảng trắng để hỏi làm rõ bài toán trong System Design Interview.
Quyết định thiết kế hữu ích đầu tiên đôi khi là để bảng trắng trống thêm một phút.

Không thành phần nào trong số đó vô lý. Vấn đề nằm ở thời điểm chúng xuất hiện. Ứng viên đã bắt đầu trả lời trước khi câu hỏi có đủ hình dạng để nâng đỡ một câu trả lời.

Một “hệ thống lưu trữ ảnh” có thể dùng để giữ avatar cho ứng dụng nội bộ, sao lưu ảnh riêng tư của gia đình, phục vụ bảng tin công khai, hoặc xử lý hàng triệu ảnh sản phẩm. Tất cả đều lưu ảnh, nhưng mỗi hệ thống bảo vệ một lời hứa khác nhau. Dịch vụ backup có thể đặt durability và khả năng khôi phục lên trước tốc độ hiển thị. Mạng xã hội lại phải quan tâm nhiều hơn đến lưu lượng đọc, thumbnail, moderation, nội dung bất ngờ trở nên phổ biến và việc phân phối qua nhiều khu vực. Ý nghĩa sản phẩm thay đổi thì kiến trúc cũng thay đổi.

Vì vậy, câu hỏi đầu tiên trong System Design Interview hiếm khi nên là “Mình sẽ dùng công nghệ gì?” Câu hỏi hữu ích hơn là “Hệ thống này cần làm tốt điều gì?” Ai tải ảnh lên, ai xem ảnh, ảnh công khai hay riêng tư, cần giữ bao lâu và điều gì phải xảy ra sau khi upload không phải những chi tiết để bổ sung sau. Chúng quyết định thiết kế.

Quy mô làm sự khác biệt ấy hiện rõ. Số người đã đăng ký chưa nói được nhiều. Số người hoạt động, lượng ảnh tải lên mỗi ngày, kích thước trung bình, tỷ lệ đọc so với ghi, nơi người dùng sinh sống và thời gian lưu giữ mới giúp ta thấy tải thật. Nếu nói rõ giả định hệ thống nhận hai triệu ảnh mỗi ngày, mỗi ảnh trung bình 4 MB, riêng dữ liệu gốc đã tăng khoảng 8 TB một ngày, gần 3 PB một năm. Đây không phải dự báo chính xác. Nó là phép tính nhanh để mở ra các câu hỏi tiếp theo về nén, các phiên bản ảnh, replication, lifecycle policy, chi phí egress và xóa dữ liệu.

Các luồng chính cũng cần được thu hẹp như vậy. Phiên bản đầu chỉ upload và xem ảnh, hay còn phải sửa, chia sẻ, tìm kiếm và xóa? Hệ thống có resize, nén, scan hoặc loại bỏ metadata nhạy cảm không? Thumbnail phải xuất hiện ngay trong response upload, hay có thể được xử lý bất đồng bộ? Tìm theo tên file, theo metadata có cấu trúc và theo nội dung hình ảnh là ba yêu cầu rất khác nhau cùng ẩn sau chữ “search”.

Non-functional requirements biến những luồng đó thành ràng buộc kỹ thuật. Latency bao nhiêu là chấp nhận được? Availability và durability cần ở mức nào? Nếu một region gặp sự cố, hệ thống được phép mất bao nhiêu dữ liệu? Khi quyền xem ảnh riêng tư bị thu hồi, ảnh có phải biến mất ngay ở mọi cache không? Consistency không phải một chiếc công tắc chung cho cả hệ thống: bộ đếm lượt xem có thể chấp nhận eventual consistency, nhưng access control và một ảnh đã được đánh dấu ready có thể cần đảm bảo mạnh hơn.

Interviewer có thể không cung cấp đủ mọi con số, nhưng cuộc trao đổi không vì thế mà bế tắc. Ứng viên có thể nói rõ assumption rồi tiếp tục: “Em sẽ giả định đây là dịch vụ chia sẻ ảnh công khai, read-heavy, có một triệu người dùng hoạt động mỗi ngày, cần tạo thumbnail và người dùng chủ yếu ở Đông Nam Á. Nếu scope đó phù hợp, em sẽ thiết kế luồng upload và read trước.” Một assumption được nói ra có thể được sửa. Một assumption nằm im trong đầu có thể dẫn cả buổi phỏng vấn về sai hệ thống.

Làm rõ yêu cầu cũng không có nghĩa dành nửa buổi để đọc hết một checklist. Câu hỏi tốt là câu hỏi có khả năng thay đổi kiến trúc. Trong vài phút đầu, hãy xác định primary use case, khung quy mô, những ràng buộc quan trọng nhất và tiêu chí thành công. Sau đó tóm tắt scope, nói rõ phần nào chưa xử lý và bắt đầu thiết kế.

Lúc ấy, những thành phần quen thuộc mới có lý do để xuất hiện. Object storage có thể phù hợp với file lớn cần durability cao. Metadata database có thể giữ owner, object key, quyền truy cập và trạng thái xử lý. Pre-signed URL có thể cho client upload trực tiếp để file lớn không phải đi xuyên qua application server. Queue có thể tách việc nhận upload khỏi resize hoặc scan. CDN có thể giảm latency cho một workload công khai và thiên về đọc. Đây không còn là những ô được học thuộc; chúng là câu trả lời cho các yêu cầu đã được gọi tên.

Cách suy nghĩ đó cũng làm lộ khoảng trống giữa các ô. Điều gì xảy ra nếu object đã upload xong nhưng ghi metadata thất bại? Worker có thể tạo cùng một thumbnail hai lần sau retry mà vẫn an toàn không? Metadata có thể chuyển sang ready trước khi mọi phiên bản ảnh cần thiết tồn tại không? Khi người dùng xóa ảnh riêng tư, bản đang nằm trong CDN cache được thu hồi thế nào? Những object không còn metadata sẽ được phát hiện và dọn dẹp ra sao? Các failure path này thường cho thấy engineering judgment rõ hơn một service mới được thêm vào sơ đồ.

Phản xạ vẽ ngay cũng dễ hiểu. Công nghệ đem lại cảm giác cụ thể, còn một bảng trắng kín ô tạo cảm giác mình đang tiến lên dưới áp lực thời gian. Nhưng System Design Interview không chỉ kiểm tra ứng viên nhớ được bao nhiêu tên công nghệ. Nó còn quan sát cách một người biến sự mơ hồ thành phạm vi có thể giải, làm cho assumption trở nên kiểm chứng được và nối từng trade-off với một nhu cầu thật.

Một sơ đồ phức tạp có thể cho thấy vốn từ kỹ thuật. Vài câu hỏi cẩn thận ở đầu buổi lại cho thấy người kỹ sư hiểu vốn từ ấy dùng để làm gì. Lần tới khi nhận một đề bài chỉ có một câu, có lẽ ta nên để chiếc bút đứng yên thêm một chút và bắt đầu bằng lời này: “Trước khi đề xuất architecture, em muốn làm rõ primary use case và những constraint có thể làm thay đổi thiết kế.”

Khoảng dừng ấy không phải là thiếu câu trả lời. Nó là phần đầu tiên của một câu trả lời có trách nhiệm. Nếu từng tham gia System Design Interview, câu hỏi làm rõ nào đã khiến thiết kế phía sau của bạn thay đổi?

Bạn thấy bài viết thế nào?