Node và edge là quyết định thiết kế,
tại sao hai đội cùng nhìn một thực tế lại vẽ ra hai đồ thị không tương đương
Một công ty du lịch nhận về cùng một nguồn dữ liệu chuyến bay, sạch sẽ và đầy đủ: số hiệu chuyến, sân bay đi, sân bay đến, giờ cất cánh, giờ hạ cánh. Hai đội kỹ sư được giao xây tính năng tìm hành trình. Cả hai đội đều đã làm xong phần việc của chương trước, họ chạy bài test và bài test trả lời rõ ràng, quan hệ là dữ liệu chính, câu hỏi nói về đường đi, độ sâu không biết trước. Đây là graph problem, không có gì phải bàn cãi.
Đội A vẽ mô hình mà gần như bất kỳ ai từng học qua một khoá thuật toán cũng sẽ vẽ. Sân bay là node. Chuyến bay là edge nối hai sân bay, mang theo thuộc tính giờ cất cánh và giờ hạ cánh. Bản vẽ lên whiteboard trong mười phút, ai nhìn vào cũng gật đầu, vì nó chính xác là bản vẽ trong mọi giáo trình, mọi slide bài giảng, mọi ví dụ minh hoạ về graph từng tồn tại. Hà Nội nối Bangkok, Bangkok nối Doha, Doha nối Lisbon. Một tấm bản đồ đường bay thu nhỏ.
Đội B vẽ thứ trông kỳ cục hơn nhiều. Trong mô hình của họ, mỗi chuyến bay là một node. Chuyến VN615 Hà Nội đi Bangkok sáng thứ ba là một node. Chuyến QR837 Bangkok đi Doha chiều thứ ba là một node khác. Edge không nối sân bay với sân bay, edge nối chuyến bay với chuyến bay, và chỉ tồn tại khi hai chuyến nối chuyến được với nhau, nghĩa là chuyến trước hạ cánh ở đúng sân bay chuyến sau cất cánh, và khoảng cách thời gian giữa hai chuyến nằm trong ngưỡng cho phép. Sân bay, nhân vật chính của mọi bản đồ đường bay, gần như biến mất khỏi bản vẽ, chỉ còn là một thuộc tính ghi chú trên node. Người ngoài nhìn vào sẽ nói đội B vẽ sai, hoặc ít nhất là vẽ ngược.
Rồi câu hỏi business đến, như nó luôn đến, bằng một câu tiếng người: tìm hành trình từ Hà Nội đến Lisbon, tối đa hai lần nối chuyến, mỗi lần chờ không quá bốn tiếng và không ít hơn chín mươi phút.
Đội B trả lời bằng một phép traversal thẳng. Mọi ràng buộc của câu hỏi đã được nướng sẵn vào cấu trúc, edge chỉ tồn tại giữa hai chuyến nối được nhau, nên đi trên đồ thị của đội B chính là đi trên các hành trình hợp lệ, máy chỉ việc bước.
Đội A mắc kẹt. Không phải kẹt kiểu chậm, kẹt kiểu không diễn đạt nổi. Thông tin giờ giấc trong mô hình của họ sống trên edge, nhưng ràng buộc nối chuyến lại là ràng buộc giữa hai edge liên tiếp, giờ hạ cánh của edge này so với giờ cất cánh của edge kia. Phép traversal tiêu chuẩn bước từ node sang node và nhìn từng edge một, nó không có khái niệm nhìn hai edge cạnh nhau cùng lúc. Đội A bắt đầu viết code vá, lưu trạng thái chuyến vừa đi vào bộ nhớ của thuật toán, lọc thủ công ở mỗi bước, và mỗi dòng code vá là một lời thú nhận rằng mô hình không nói được điều câu hỏi cần nói.
Hãy dừng ở đây một chút, vì nghịch lý này đáng được nhìn thẳng. Cùng một dữ liệu, đến từng dòng. Hai đội cùng giỏi. Cả hai cùng nhận diện đúng rằng đây là graph problem. Và nếu mô hình hoá là việc vẽ lại thực tế một cách trung thực, thì hai bản vẽ trung thực với cùng một thực tế phải tương đương nhau, phải trả lời được cùng những câu hỏi. Chúng không tương đương. Một bản nói, một bản câm.
Đội A không vẽ sai thực tế. Sân bay có thật, chuyến bay nối hai sân bay có thật, mọi thứ trên bản vẽ của họ đều kiểm chứng được ngoài đời. Họ chỉ vẽ đúng một thực tế không chứa câu trả lời.
Nếu bạn hỏi một kỹ sư vừa chuyển sang graph rằng làm sao quyết định cái gì là node, cái gì là edge, nhiều khả năng bạn sẽ nghe một heuristic được truyền miệng qua nhiều thế hệ tài liệu: đọc requirement, gạch chân danh từ, đó là node, gạch chân động từ, đó là edge.
Heuristic này không phải lời khuyên vớ vẩn. Hãy thử nó lên ba requirement bất kỳ. Khách hàng mua sản phẩm, vậy là hai node và một edge, vẽ xong. Nhân viên báo cáo cho manager, hai node một edge, org chart hiện ra. Tài khoản chuyển tiền đến tài khoản, một đồ thị giao dịch thành hình. Ba lần thử, ba lần heuristic cho ra mô hình dùng được ngay, không cần họp, không cần tranh luận.
Và giá trị của nó còn nằm ở chỗ khác, ít được nói ra hơn. Một đội đứng trước whiteboard trắng cần một cách để bắt đầu, và danh từ với động từ cho họ một ngôn ngữ chung, một quy trình đủ máy móc để mọi người vẽ ra gần như cùng một thứ thay vì sa vào tranh cãi triết học về bản chất của dữ liệu. Một heuristic giúp người ta bắt đầu là một heuristic có giá trị, bất kể nó đúng đến đâu.
Bây giờ soi nó vào câu chuyện mở đầu. Đội A chính là đội theo heuristic một cách trung thành nhất. Sân bay là danh từ, hiển nhiên đến mức không cần nghĩ. Bay từ đâu đến đâu là động từ. Heuristic không sai cú pháp ở chỗ nào cả, nó được áp dụng đúng từng bước, và nó cho ra một mô hình câm. Vấn đề không nằm ở chỗ heuristic bị dùng sai. Vấn đề nằm ở chỗ trong toàn bộ quy trình của nó, không có bước nào bắt người vẽ dừng lại và hỏi: câu hỏi mình cần trả lời là gì?
Có một giới hạn thứ hai, sâu hơn. Ngôn ngữ tự nhiên không phân loại thế giới theo nhu cầu truy vấn của bạn. Cùng một thứ có thể là danh từ trong câu này và là cả một mệnh đề quan hệ trong câu kia. Chuyến bay VN615 là danh từ khi bạn nói "chuyến bay VN615 bị delay", và là động từ khi bạn nói "Vietnam Airlines bay Hà Nội Bangkok mỗi sáng". Ngữ pháp uốn theo góc nhìn của người nói, từng câu một. Một heuristic dựa trên ngữ pháp thừa kế trọn vẹn sự tuỳ tiện đó.
Nghĩa là: ranh giới giữa node và edge không nằm trong ngữ pháp, và cũng không nằm sẵn trong bản thân sự vật. Nếu nó nằm sẵn trong sự vật, chuyến bay đã không thể vừa là edge của đội A vừa là node của đội B, hai bản vẽ cùng trung thực với một bầu trời.
Vậy có thứ gì đó đứng được ở cả hai bên ranh giới. Có thứ gì đó cho phép một quan hệ, một đường kẻ giữa hai chấm, bước qua và trở thành một chấm. Câu hỏi của chương không còn là tại sao đội A thất bại nữa. Câu hỏi là: lực nào đẩy một quan hệ trở thành một thực thể?
Hiện tượng đó có tên, và cái tên đáng được biết vì bạn sẽ gặp lại nó suốt phần còn lại của cuốn sách này: reification°, biến quan hệ thành thực thể.
Trước khi dùng thuật ngữ, hãy nói nó bằng tiếng người. Một quan hệ bắt đầu cuộc đời như một đường kẻ giữa hai chấm. Nó cứ là đường kẻ như vậy, cho đến khi ba chuyện xảy ra. Khi nó cần mang thuộc tính riêng và thuộc tính đó tham gia vào điều kiện của câu hỏi. Khi nó cần được tham chiếu, được chỉ đích danh, được trỏ vào. Hoặc khi nó cần tự mình tham gia vào một quan hệ khác. Bất kỳ chuyện nào trong ba chuyện đó xảy ra, đường kẻ không gánh nổi nữa. Nó phải trở thành một chấm.
Chạy khái niệm này ngược vào ca bệnh mở đầu và mọi thứ vào khớp. Chuyến bay là quan hệ giữa hai sân bay, và nó sống ổn như một quan hệ, cho đến khi câu hỏi business cần ràng buộc giữa hai chuyến bay liên tiếp. Ràng buộc nối chuyến là một quan hệ mà hai đầu của nó là hai quan hệ khác. Edge không trỏ được vào edge, không một hệ hình thức lành mạnh nào cho phép điều đó. Khoảnh khắc câu hỏi đòi hỏi điều đó, chuyến bay buộc phải thành node, và đội B không vẽ kỳ cục. Đội B vẽ theo câu hỏi.
“Quan hệ là một đường kẻ giữa hai chấm, cho đến khi câu hỏi của bạn buộc nó trở thành một chấm.
”
Ba tín hiệu ở trên đáng được giữ lại như một bài kiểm tra nhỏ, cùng tinh thần với bài test năm dấu hiệu mà bạn đã có. Quan hệ cần thuộc tính riêng, và thuộc tính đó không phải trang trí mà nằm trong điều kiện truy vấn, giờ cất cánh của chuyến bay không nằm đó cho đẹp, nó nằm trong mệnh đề lọc của mọi câu hỏi nối chuyến. Quan hệ cần được tham chiếu, "đổi khách sang chuyến muộn hơn" chỉ nói được khi từng chuyến có danh tính riêng để chỉ vào. Quan hệ tham gia quan hệ khác, nối chuyến, codeshare, một chuyến thay thế cho một chuyến. Requirement của bạn khớp một trong ba tín hiệu là quan hệ đó đã ứng cử vào ghế node.
Và một khi bạn nhìn thấy chuyển động này, bạn thấy nó khắp nơi, không riêng gì hàng không. Nhân viên làm việc cho công ty, một quan hệ hiền lành, hai chấm một đường kẻ, cho đến ngày phòng nhân sự cần hỏi về giai đoạn làm việc, chức danh lúc đó, mức lương lúc đó, lý do kết thúc, thế là hợp đồng tách ra thành một thực thể đứng giữa người và công ty. Tài khoản chuyển tiền cho tài khoản, hiền lành, cho đến ngày điều tra viên cần gom mười hai giao dịch cụ thể vào một nghi án và chú thích từng giao dịch một, thế là giao dịch thành node, có danh tính, có hồ sơ. Bác sĩ kê thuốc cho bệnh nhân, hiền lành, cho đến khi cần liều lượng, ngày kê, và câu hỏi về tương tác giữa hai đơn thuốc, một quan hệ giữa hai quan hệ, đúng cái hình chúng ta vừa gặp ở chuyện nối chuyến.
Đến đây có vẻ mọi thứ đã sáng. Heuristic danh từ động từ là điểm khởi đầu, reification là nước đi nâng cấp khi câu hỏi đòi hỏi, ca của đội A đội B đóng sổ. Nhưng để ý kỹ thì lời giải này vừa mở ra một vực mới, rộng hơn nhiều cái hố nó vừa lấp.
Nếu mọi quan hệ đều có thể trở thành node khi cần, và nhìn theo chiều ngược lại, mọi thuộc tính cũng có thể tách thành một quan hệ trỏ đến một node giá trị, thì về nguyên tắc bạn có thể reify mãi mãi. Mô hình nào cũng nâng cấp được thành một mô hình chi tiết hơn, giàu có hơn, "đúng" hơn. Không có điểm dừng tự nhiên nào nằm sẵn trong lý thuyết. Vậy những người làm việc này nghiêm túc, ở quy mô mà mỗi quyết định mô hình hoá trị giá hàng triệu giờ máy, họ dừng ở đâu, và họ dựa vào đâu để dừng?
Câu hỏi đó không trả lời được trên whiteboard. Phải đi xem.
Cuối những năm 2000, social graph của Facebook đã phình quá mọi thước đo quen thuộc. Người, trang, bài đăng, bình luận, ảnh, lượt thích, check-in, tất cả nối vào nhau, và mọi lần một người mở trang chủ là hàng trăm câu hỏi nhỏ bắn vào cái graph đó, bạn của người này là ai, bài nào mới, ai thích bài này, bình luận nào gần nhất. Nhân con số đó với hàng tỷ người dùng và bài toán hiện nguyên hình: đây không phải bài toán biểu diễn sao cho đẹp, đây là bài toán biểu diễn sao cho hàng tỷ câu hỏi nhỏ mỗi giây trả lời nổi.
Đội Facebook chốt một mô hình mà nếu đặt cạnh các hệ knowledge graph hàn lâm cùng thời sẽ trông nghèo đến mức gây ngạc nhiên. Trong hệ thống tên là TAO, thế giới chỉ có hai loại thứ: objects, các node có type và một túi field, và associations, các edge có type, có hướng, nối hai object. Không có hierarchy của type, không có edge trỏ vào edge, không có cấu trúc lồng nhau. Hai khái niệm, hết.
Nghèo, nhưng không ngây thơ. Và có một chi tiết nên biết trước khi đi tiếp, vì nó gỡ một hiểu nhầm phổ biến: toàn bộ cái graph này, ở tầng lưu trữ, sống trên MySQL, một hệ quan hệ thuần tuý, cộng một tầng cache khổng lồ phía trên. Không có graph database nào ở đây cả. Mô hình objects và associations là một quyết định về cách nhìn dữ liệu, không phải quyết định về công nghệ chứa nó, và hai chuyện này tách nhau được triệt để đến mức một trong những graph lớn nhất hành tinh nằm gọn trong những bảng quan hệ. Mô hình hoá xảy ra ở tầng tư duy. Công nghệ đến sau, và là một câu chuyện khác.
Quay lại mô hình. Có hai quyết định trong đó đáng dừng lại nhìn thật kỹ, vì cả hai đều là quyết định mô hình hoá thuần tuý.
Quyết định thứ nhất: mọi association đều có chiều ngược được duy trì song song. A thích B thì trong hệ thống tồn tại đồng thời B được-thích-bởi A, hai bản ghi, cập nhật cùng nhau. Nhìn từ góc tiết kiệm, đây là sự hoang phí, mọi edge tốn gấp đôi chi phí ghi. Nhưng đội TAO biết hình dạng câu hỏi của họ: sản phẩm hỏi cả hai chiều, ai thích bài này và người này thích những bài nào, với tần suất khổng lồ như nhau, và lượng đọc áp đảo lượng ghi nhiều bậc. Họ trả gấp đôi ở phía ghi để mua câu hỏi hai chiều với giá một chiều ở phía đọc. Một cái giá chỉ hợp lý với đúng tỷ lệ đọc ghi đó, nghĩa là với đúng bộ câu hỏi đó.
Quyết định thứ hai: thời gian là thuộc tính hạng nhất của edge, và các association được giữ theo thứ tự thời gian. Vì sao thời gian, mà không phải một thuộc tính nào khác trong hàng trăm thuộc tính khả dĩ? Vì câu hỏi thật của sản phẩm gần như luôn có chữ "gần đây" giấu bên trong, bình luận mới nhất, lượt thích gần nhất, hoạt động vừa xảy ra. Mô hình được uốn quanh hình dạng của câu hỏi, đến từng quyết định một, và những thuộc tính không phục vụ câu hỏi nào thì không được mời vào cấu trúc.
Bây giờ soi TAO bằng bộ ba tín hiệu reification của phần trước. Trong domain° của Facebook, rất nhiều quan hệ là ứng viên sáng giá. Bình luận, xét cho cùng, là quan hệ giữa một người và một bài đăng. Nhưng bình luận cần thuộc tính riêng nằm trong truy vấn, cần được tham chiếu, và cần tham gia quan hệ khác, người ta thích một bình luận, trả lời một bình luận. Ba tín hiệu khớp cả ba. Và đúng như khung dự đoán, bình luận trong TAO là object, không phải association. Reification đã xảy ra, có chọn lọc, lặng lẽ, đúng những chỗ câu hỏi cần và không một chỗ nào khác.
Còn cái giá thì sao, vì mô hình nào cũng có giá. Mô hình nghèo nghĩa là những câu hỏi giàu cấu trúc không phải khách hàng ở đây. Traversal sâu nhiều bước, pattern phức tạp, các phân tích toàn cục, TAO không phục vụ và không xin lỗi vì điều đó, những nhu cầu ấy đi đường khác, qua các hệ thống khác được xây cho việc khác. Một mô hình tốt, hoá ra, không phải mô hình trả lời được mọi câu hỏi. Nó là mô hình biết rõ mình phục vụ câu hỏi nào, và từ chối phần còn lại một cách có chủ đích.
TAO là câu trả lời cho câu hỏi "dừng reify ở đâu" của một đội biết rất rõ câu hỏi của mình, vài chục kiểu truy vấn, lặp lại hàng tỷ lần mỗi giây, ổn định qua nhiều năm. Họ dừng rất sớm, và sự dừng sớm đó là sức mạnh. Nhưng đó là một thái cực. Chuyện gì xảy ra ở thái cực còn lại, nơi chính việc xác định câu hỏi mới là phần khó nhất của bài toán?
Airbnb đứng ở thái cực đó. Khoảng giữa thập kỷ 2010, họ bắt đầu xây một knowledge graph nội bộ nối listing với địa điểm, trải nghiệm, sự kiện, tiện ích, với tham vọng để search và recommendation hiểu được "kỳ nghỉ trượt tuyết gần Tokyo" như một ý định, thay vì match từng từ khoá rời rạc. Khác với Facebook, đội này không có sẵn vài chục câu hỏi cố định lặp tỷ lần. Họ có một không gian câu hỏi đang tự nở ra theo sản phẩm, hôm nay là tìm kiếm theo địa danh, quý sau là gợi ý theo phong cách du lịch, năm sau là thứ chưa ai trong phòng nghĩ ra.
Và cuộc tranh luận khó nhất của một đội như vậy, kể lại từ chính người trong cuộc, không phải là tranh luận kỹ thuật. Nó là tranh luận ontology, nghĩa là tranh luận về việc thế giới trong hệ thống của họ gồm những loại thứ gì. Câu hỏi nghe nhỏ mà chia đôi căn phòng: thành phố là một node, hay là một property của listing?
Trước khi đọc phần phân tích, thử tự chọn một phe và viết ra lý do: thành phố nên là node, hay nên là property?
Hãy nghĩ về nó một chút.
Đáng để đi đến tận đáy ví dụ này, vì nó chính là câu hỏi "dừng reify ở đâu" của phần trước, mặc quần áo đời thật.
Nếu thành phố là property, một chuỗi ký tự nằm trên mỗi listing, thì câu hỏi "listing nào ở Tokyo" trả lời được bằng một phép lọc, rẻ, nhanh, không cần hạ tầng gì mới. Nhưng mọi câu hỏi mà trong đó thành phố đóng vai trò một thứ có quan hệ riêng đều câm. Tokyo gần những vùng trượt tuyết nào. Thành phố này thuộc vùng văn hoá nào, mùa cao điểm của nó là mùa nào. Người thích Kyoto thường thích thêm thành phố nào. Một chuỗi ký tự không có hàng xóm, không có vùng lân cận, không thuộc về cái gì, nó chỉ bằng hoặc khác một chuỗi ký tự khác.
Nếu thành phố là node, tất cả các câu hỏi trên mở ra. Tokyo giờ nối được với vùng, với mùa, với sự kiện, với các thành phố tương đồng, cấu trúc kết nối quanh nó bắt đầu mang thông tin. Nhưng cái giá đến ngay lập tức, và đến trước cả lợi ích: mỗi listing giờ phải link đến đúng node thành phố. "Tokyo", "Tōkyō", "東京", và mười cách viết khác trong dữ liệu do hàng triệu host tự nhập, tất cả phải về một mối. Bài toán entity resolution° chen vào giữa dữ liệu và mọi truy vấn, chi phí curate tăng, và một tầng phức tạp mới đứng chắn trước cả những câu hỏi đơn giản nhất từng trả lời được bằng một phép lọc.
Điểm chốt của câu chuyện nằm ở chỗ này: không có đáp án đúng nằm sẵn trong địa lý. Tokyo, tự nó, không phải node và cũng không phải property. Tokyo chỉ là Tokyo. Quyết định nằm trọn ở phía Airbnb, ở chỗ họ muốn search và recommendation trả lời loại câu hỏi nào trong hai năm tới, và họ sẵn sàng trả bao nhiêu chi phí curate cho điều đó. Cùng một thành phố, hai số phận mô hình, tuỳ chiến lược sản phẩm của người vẽ.
Bây giờ đặt hai công ty cạnh nhau và để phép so sánh tự nói. Facebook chọn một mô hình nghèo có chủ đích, hai khái niệm, từ chối mọi sự giàu có về cấu trúc. Airbnb chọn một ontology giàu có chủ đích, chấp nhận trả chi phí curate để mua không gian câu hỏi rộng. Hai lựa chọn gần như đối nghịch nhau về mọi mặt, và cả hai đều đúng, mỗi bên đúng với bài toán của mình.
Sự khác nhau giữa họ, nhìn kỹ, không nằm ở domain. Nó nằm ở độ chín của câu hỏi. Facebook biết câu hỏi của mình đến từng chữ, vài chục kiểu truy vấn đã ổn định qua nhiều năm sản phẩm, nên họ dám đúc mô hình cứng quanh đúng bộ câu hỏi đó và vứt mọi thứ thừa. Airbnb chưa biết hết câu hỏi của mình, không gian câu hỏi của họ còn đang nở theo sản phẩm, nên họ mua sự rộng rãi và trả giá bằng curate. Mức độ chắc chắn về câu hỏi quyết định mức độ cứng của mô hình. Còn thứ duy nhất nhất quán giữa hai bên thì không nằm trong mô hình nào cả. Nó nằm ở điểm xuất phát: cả hai đội đều bắt đầu từ câu hỏi, không phải từ domain.
Và đó là lúc nhận ra câu hỏi của chương này đã bị đặt sai ngay từ đầu, sai theo đúng cái cách mà hầu hết chúng ta được dạy. Câu hỏi chưa bao giờ là "domain này trông như thế nào", vì domain trông thế nào thì nó vẫn trả lời được vô số mô hình trung thực khác nhau. Câu hỏi luôn luôn là "mình cần hỏi nó điều gì".
“Mô hình không mô tả thực tế, nó mô tả những câu hỏi bạn định hỏi thực tế.
”
Hệ quả đầu tiên của cách nhìn này đến ngay, và hơi lạnh. Câu hỏi của một sản phẩm sống sẽ thay đổi theo thời gian, còn mô hình thì đông cứng tại thời điểm thiết kế. Nghĩa là mô hình tốt nhất cho câu hỏi hôm nay hoàn toàn có thể câm với câu hỏi năm sau, không phải vì ai đó vẽ ẩu, mà vì bản chất của việc vẽ là chốt một bộ câu hỏi lại. Đội A của phần mở đầu không thất bại vì kém. Họ thất bại vì vẽ trước khi biết câu hỏi, và phần lớn chúng ta được dạy vẽ đúng theo thứ tự đó, dữ liệu trước, câu hỏi sau, bản đồ trước, chuyến đi sau.
Phát biểu lại điều vừa lộ ra, ở dạng đầy đủ của nó: mô hình hoá không phải là vẽ lại thực tế. Mô hình hoá là chọn cách cắt thực tế theo câu hỏi cần trả lời. Và phép cắt đó có năm con dao, chọn cái gì là node là chọn cái gì được tham chiếu, chọn cái gì là edge là chọn cái gì traverse được, chọn hướng của edge là chọn câu hỏi nào rẻ và câu hỏi nào đắt, chọn weight là chọn cái gì so sánh được với cái gì, chọn cái gì là property là chọn cái gì bị giấu khỏi cấu trúc, nằm đó nhưng không tham gia vào hình. Mỗi nhát cắt mở vài cánh cửa và đóng vài cánh cửa khác, không nhát nào miễn phí.
Thử cầm một con dao trong số đó lên cho cụ thể, con dao về hướng. Một đồ thị "service A gọi service B" với edge trỏ theo chiều gọi trả lời rất rẻ câu hỏi "A gọi những ai", và trả lời rất đắt câu hỏi "những ai gọi A", dù hai câu hỏi mô tả cùng một thực tế, chỉ nhìn từ hai phía. Người vẽ chiều edge đã quyết định thay tổ chức của mình rằng câu hỏi nào sẽ được trả lời trong mili giây và câu hỏi nào sẽ được trả lời trong một cuộc họp, và phần lớn các quyết định như thế được đưa ra mà không ai nhận ra mình đang quyết định.
Cách nhìn này còn lật lại một thói quen ngôn ngữ trong nghề mà chúng ta ít khi để ý. Khi một hệ thống bế tắc, các đội hay nói "mô hình hoá sai rồi", với hàm ý của một lỗi lầm, một sự bất cẩn đáng lẽ tránh được. Nhưng nhìn từ phía câu hỏi, phần lớn các "mô hình sai" đó không sai theo nghĩa lỗi. Chúng là những mô hình trung thành với một bộ câu hỏi đã hết hạn. Chúng từng nói rất rõ, với những câu hỏi của ba năm trước. Nhìn như vậy thì migrate mô hình thôi không còn là lời thú tội nữa, nó là dấu hiệu của một sản phẩm còn sống, còn sinh ra câu hỏi mới nhanh hơn tốc độ đông cứng của bản vẽ.
Còn một tầng nữa, tầng này nằm ở chỗ giáo dục của chúng ta bắt đầu. Mọi giáo trình thuật toán mở đầu bằng cùng một câu thần chú, cho đồ thị G gồm tập đỉnh V và tập cạnh E. Chương trước đã chỉ ra ba chữ "cho đồ thị" giấu mất việc ngoài đời không ai cho bạn đồ thị cả. Nhưng nó còn giấu một điều thứ hai, kín hơn: V và E không phải sự kiện tự nhiên, chúng là kết quả của một chuỗi quyết định mà ai đó đã làm thay bạn, theo những câu hỏi của họ, vào thời của họ. Mỗi lần bạn dùng lại một graph có sẵn, một dependency graph do công cụ sinh ra, một social graph do hệ thống khác định nghĩa, một knowledge graph mua về, là một lần bạn thừa kế bộ câu hỏi của người khác mà không đọc di chúc. Đồ thị trả lời trơn tru những gì người vẽ nó từng cần hỏi, và im lặng một cách khó hiểu trước những gì bạn cần hỏi, và sự im lặng đó trông y hệt như lỗi của bạn.
Người đọc đi đến đây đang đứng ở một chỗ cụ thể. Bài toán đã nhận diện đúng, nhờ bài test của chương trước. Mô hình đã cắt theo câu hỏi, nhờ chương này. Và chính vì cắt theo câu hỏi, các câu hỏi giờ bắt đầu lộ hình dạng riêng của chúng. Có câu hỏi mang hình "từ chỗ này, cái gì chạm tới được". Có câu hỏi mang hình "giữa hai chỗ, đường nào tốt nhất, và tốt nghĩa là gì". Có câu hỏi mang hình "trong cả mạng lưới này, ai đứng ở vị trí quan trọng". Có câu hỏi mang hình "những thứ này, nhóm nào thuộc về nhau". Mỗi hình dạng là một họ bài toán, với cách giải riêng, cái giá riêng, và cạm bẫy riêng mà người ta thường chỉ phát hiện khi đã ở trong đó.
Còn đội A, để khép lại câu chuyện của họ. Họ rồi sẽ vẽ lại, các đội như vậy luôn vẽ lại. Lần này họ sẽ hỏi câu hỏi trước khi đặt bút, và bản vẽ thứ hai của họ sẽ trông kỳ cục trong mắt người ngoài, y như bản vẽ của đội B từng kỳ cục trong mắt chính họ. Có lẽ đó là dấu hiệu đáng tin nhất của một mô hình được cắt theo câu hỏi thật. Nó hiếm khi trông giống hình minh hoạ trong giáo trình.
Mô hình không mô tả thực tế, nó mô tả những câu hỏi bạn định hỏi thực tế.
Did anything here change how you think about the problem?
In this neighborhood
hand-picked by the author“Chương trước dạy nhận diện graph problem từ cách câu hỏi được phát biểu, và kết thúc bằng một khoảng trống: hai đội cùng nhận diện đúng vẫn có thể dựng hai mô hình khác nhau. Chương này nhận lấy đúng khoảng trống đó, nhận diện xong thì cắt thực tế thành node và edge thế nào.”
“Chương mở series chỉ ra rằng không ai dạy bước vẽ, trường chỉ dạy giải đồ thị đã vẽ sẵn. Chương này chính là bước vẽ đó, và cho thấy vẽ không phải là chép lại thực tế mà là một chuỗi quyết định, mỗi quyết định mở một số câu hỏi và đóng những câu hỏi khác.”