Hoa Ban Không TànCh.39 / 47
Chapter 39

Người không ngủ

Mùi khét của hạt cà phê rang già bám riết lấy từng kẽ móng tay tôi, quyện chặt vào mùi xà phòng giặt sàn loại rẻ tiền có tính kiềm nồng nặc. Đó là thứ mùi hăng hắc, nhờn nhợt, bám dai dẳng vào da thịt suốt dọc đường tôi chạy bộ từ con ngõ sâu hút ở phố Trần Đại Nghĩa ngược về khu ký túc xá Bách khoa.

Gió cuối thu thổi thốc qua các ngã tư, mang theo cái lạnh khô khốc xát vào da mặt, nhưng hai bên thái dương và dọc sống lưng tôi vẫn ướt đẫm mồ hôi. Đôi giày vải Thượng Đình mòn vẹt đế trượt trên lớp sỏi răm trước sân nhà B7. Tôi vừa kịp lách cả thân hình gầy guộc qua khe hẹp của cánh cổng sắt hoen gỉ thì tiếng xích gang nặng trịch đã va vào chấn song loảng xoảng phía sau. Bác bảo vệ già lầm bầm chửi với theo một câu quen thuộc về cái giờ giới nghiêm mười một giờ đêm của trường, rồi chiếc ổ khóa Việt Tiệp to bản sập lại bằng một tiếng *cạch* dứt khoát, đanh gọn.

Tôi đứng tựa vào cột bê tông ở chân cầu thang, lồng ngực phập phồng đập thình thịch, nuốt từng ngụm khí lạnh buốt để xoa dịu cuống họng đang rát bỏng. Bốn tiếng đồng hồ đứng chôn chân bên bồn rửa bát bằng tôn của quán cà phê Mùa Gió, cọ rửa hàng trăm chiếc tách sứ cáu bẩn và khay gạt tàn ngập đầu lọc thuốc lá, đã vắt kiệt chút sinh lực cuối cùng trong cơ thể tôi. Nhưng tôi không thể quay về phòng 314 để ngủ. Trên tầng hai, ở góc hành lang tối tăm dẫn ra phía sau dãy nhà vệ sinh, có một cánh cửa gỗ dán mở hé, hắt ra một vệt sáng vàng vọt.

Đó là phòng tự học đêm—nơi duy nhất được ban quản lý ký túc xá châm chước duy trì một bóng đèn tuýp hai mươi mốt oát cho những sinh viên chuẩn bị thi cử hoặc làm đồ án.

Tôi bước vào phòng, kéo lê chiếc ghế gỗ thông lỏng khớp xuống góc bàn trống sát cửa sổ. Gió lùa qua những chấn song sắt không có kính chắn, thổi phần phật mép tập tài liệu A4 mà Phong đã nhét vào ba lô tôi lúc chập tối, trước khi tôi tất tả xỏ chân vào đôi ủng cao su để bắt đầu ca làm việc.

Tôi quệt mồ hôi trên trán, mở tập tài liệu ra. Mùi mực in la-de còn mới sực lên, lấn át tạm thời mùi cà phê khét lẹt trên những đầu ngón tay đang run rẩy vì mỏi. Trang bìa in đậm dòng chữ: *Bài tập lớn môn Kỹ thuật lập trình: Xây dựng mô đun quản lý, truy vấn và tối ưu đường đi trên đồ thị mạng lưới phân phối dữ liệu đa mục tiêu.*

Nhóm của chúng tôi gồm bốn người, do Phong làm trưởng nhóm. Hai thành viên còn lại là Tuấn và Hoàng—hai cậu bạn thành thị có máy tính xách tay xịn xò, đảm nhận phần thiết kế giao diện dòng lệnh và viết các hàm đọc ghi tệp dữ liệu vào ra. Phong phụ trách dựng khung cấu trúc dữ liệu tổng quát và điều phối chung. Còn tôi, kẻ không có lấy một đồng dính túi và vừa bước chân ra khỏi bản làng vùng cao chưa đầy ba tháng, được giao phần “lõi”: thuật toán tìm kiếm đường đi ngắn nhất có ràng buộc về dung lượng truyền tải giữa các nút mạng.

Đó là trái tim của cả chương trình. Và lúc này, trái tim ấy đang ngừng đập trong một tập tin mã nguồn dài hơn bốn trăm dòng lệnh viết dở.

Một mẩu giấy nhớ màu vàng được Phong dán chặt ở góc trang đầu tiên. Nét chữ của cậu ấy vốn nắn nót, nhưng ở đây từng nét bút ghì rách cả mặt giấy: *“Hàm tìm kiếm bị rò rỉ bộ nhớ nghiêm trọng. Cứ chạy đến bộ dữ liệu trên một nghìn nút là chương trình tự ngắt, báo lỗi vi phạm phân vùng (Segmentation fault). Sáng mai tám giờ ba mươi phải nộp mã nguồn hoàn chỉnh và biên bản thử nghiệm cho thầy Tuấn. Cậu xem có cứu được không, không là cả nhóm ăn điểm không tròn trĩnh phần thực hành.”*

Tôi ngả lưng vào thành ghế gỗ cứng, nhìn đăm đăm vào những trang mã nguồn in bằng phông chữ Courier thô kệch. Các dòng lệnh đan xen chằng chịt, thụt đầu dòng lộn xộn, biến được đặt tên theo kiểu chắp vá: `temp1`, `temp2`, `node_ptr`, `flag_x`. Người viết trước—dường như là Tuấn phối hợp với Phong—đã cố nhồi nhét toàn bộ thuật toán duyệt đồ thị vào một hàm duy nhất dài ngoằng hơn hai trăm dòng. Bên trong đó là ba tầng vòng lặp `for` lồng nhau, cùng một rừng con trỏ cấp phát động bằng lệnh `malloc`, nhưng tìm mỏi mắt không thấy một dòng lệnh `free` nào để giải phóng những ô nhớ đã dùng xong.

Khi Phong dúi tập tài liệu này vào tay tôi ở cổng ký túc xá lúc năm giờ chiều, gương mặt cậu ấy tái mét, vẻ ngao ngán lộ rõ trong từng cử chỉ: “Hai đứa kia buông xuôi rồi. Chúng nó bảo thuật toán này trong giáo trình thầy chỉ dạy dạng đơn giản, giờ thầy bắt cài thêm ràng buộc phụ tải luồng dữ liệu, chúng nó không làm nổi. Tớ thì kẹt cứng ở phần phân giải gói tin. Nam, cậu gánh được không? Nếu căng quá thì để mai tớ lên gặp thầy xin lùi hạn, dù chắc chắn bị trừ một nửa số điểm quá trình.”

Lúc đó, tôi đã không ngần ngại nhận lấy, thậm chí còn gật đầu bằng một sự chắc nịch đến lạnh lùng.

Tôi tin vào một chân lý giản đơn, mộc mạc và ngây thơ đến cùng cực: trên cõi đời này, khó khăn duy nhất là tìm ra bản chất logic của một bài toán. Một khi quy luật toán học đã sáng rõ, thuật toán đã chạy ra đáp số đúng trên từng trường hợp biên, thì mọi thứ râu ria xung quanh—từ cách trình bày biến, chuẩn hóa giao tiếp hàm, hay việc phân chia công việc trong nhóm—chỉ là những thứ tiểu tiết tầm thường, giải quyết trong chớp mắt lúc nào chẳng được. Tôi mang theo cái quán tính tư duy ấy từ những năm tháng ngồi ở trường huyện vùng cao, nơi người ta chỉ chấm điểm một bài toán bằng con số duy nhất nằm ở góc dưới cùng bên phải của trang giấy thi. Ở đó, không một ai bận tâm xem cây bút chì của bạn gãy mấy lần, bạn đã nháp lộn xộn ra sao, hay bạn đã phải ngồi còng lưng giải nó bên ngọn đèn dầu liu riu trong đêm lạnh giá như thế nào.

“Cứ để đấy cho tớ,” tôi đã nói với Phong như thế, bằng tất cả sự tự tin lì lợm của một đứa từng đỗ thủ khoa đầu vào của tỉnh miền núi. “Chỉ cần thuật toán chạy đúng, sáng mai nhóm mình sẽ có bài nộp.”

Bây giờ là mười hai giờ bốn mươi phút đêm. Chiếc đồng hồ Poljot cũ mòn mặt kính mà người cha quá cố để lại đang nhích từng nhịp tích tắc khô khốc trên cổ tay tôi. Tôi chỉ còn đúng bảy tiếng đồng hồ.

Tôi không có máy tính xách tay để mở ra ngay tại chỗ như các bạn. Góc bàn tự học này là nơi tôi đặt nhờ cỗ máy tính để bàn cũ kỹ—chiếc thùng máy vỏ tôn gỉ sét chạy chip Pentium III 600MHz mà thầy Dũng ở trường huyện đã cặm cụi gom góp từng thanh RAM phế liệu, từng sợi cáp IDE gãy lẫy để ráp thành một cỗ máy hoàn chỉnh cho tôi mang xuống thủ đô. Chiếc màn hình CRT 15 inch hiệu Samtron màu trắng ngà đã ngả sang màu cháo lòng, bám một lớp bụi mờ ở các khe tản nhiệt phía sau.

Tôi cúi xuống, với tay nhấn nút nguồn bằng một lực ngón cái vừa đủ để cái lẫy nhựa không bị tụt vào trong.

Một tiếng *xoạch* trầm đục vang lên từ rơ-le nguồn, kèm theo tiếng *boong* đặc trưng khi cuộn dây khử từ quanh ống phóng điện tử phát hỏa. Chiếc màn hình rung lên bần bật, mặt kính tóe ra những hạt tĩnh điện li ti kêu tanh tách dưới mu bàn tay tôi. Quạt tản nhiệt của bộ nguồn rít lên một tràng dài the thé, phát ra thứ âm thanh nhọc nhằn của một cỗ máy đã cày ải quá niên hạn sử dụng cả chục năm trời, phả thẳng vào ống chân tôi một luồng hơi nóng lẫn mùi bụi khét lẹt.

Các ngón tay tôi vẫn còn tê dại vì nước lạnh và xà phòng ở quán cà phê. Cơn buồn ngủ bắt đầu ập đến như những con sóng ngầm, nặng trĩu nơi khóe mắt, kéo theo cảm giác choáng váng quen thuộc của một cơ thể đang bị vắt kiệt giữa mười tiếng lao động chân tay và áp lực đèn sách. Nhưng ngay khi mười đầu ngón tay tôi đặt lên bàn phím Mitsumi cơ cũ kỹ—thứ bàn phím gõ đanh và sâu lòng—tiếng lạch cạch khô giòn vang lên trong căn phòng vắng bỗng làm các dây thần kinh trong đầu tôi căng giật trở lại.

Tôi nhắm mắt lại trong năm giây, hít sâu một hơi để trấn tĩnh. Trong bóng tối của tâm trí, tôi nhớ lại những buổi chiều muộn mùa đông trong gian chái phụ bằng gỗ tạp ở Nà Ban. Gió mùa đông bắc rít qua từng khe nứa hở, thổi tắt ngọn đèn dầu, và thầy Dũng ngồi bên cạnh tôi trên chiếc ghế mây gãy nan, gõ nhẹ ngón tay trỏ cằn cỗi xuống mặt bàn: *“Nam này, khi máy tính không chạy ra kết quả như em muốn, đừng bao giờ ngồi chửi cái máy hay hoảng loạn đập phá bàn phím. Chiếc máy là thứ vô tri vô giác nhất trên trần đời này, nó chỉ làm đúng những gì em ra lệnh cho nó làm mà thôi. Em sai thì nó sai, em cẩu thả thì nó đình công. Muốn trị nó, phải chia nhỏ vấn đề ra. Tách từng khối chức năng độc lập. Kiểm tra từng giả định logic. Em phải lập bảng truy vết các biến trên mặt giấy trắng trước khi ngón tay em được phép chạm vào bàn phím.”*

Lời dạy trầm đục của thầy như một chiếc mỏ neo sắt, cắm phập vào tâm trí tôi giữa mớ bòng bong của những dòng mã nguồn hỏng hóc.

Tôi rút từ đáy ba lô ra cuốn sổ tay kỹ thuật bìa các-tông xám—cuốn sổ duy nhất tôi mang từ Sơn La xuống Hà Nội, nơi từng trang giấy đã ố vàng vì ẩm mốc nhưng ghi chép cẩn thận từng nguyên tắc giải thuật từ thời tôi còn mò mẫm viết từng dòng Turbo Pascal trên nền DOS màn hình xanh. Tôi gạt đống vỏ bút bi sang một bên, đặt tập mã nguồn của nhóm ở bên tay trái, tờ giấy nháp trắng tinh ở bên tay phải. Tôi rút chiếc bút bi Thiên Long ra, bắt đầu vạch từng khối chức năng.

Vấn đề thứ nhất: lỗi rò rỉ bộ nhớ dẫn đến *Segmentation fault*.

Tôi dùng mắt quét từng dòng lệnh, ngón trỏ dò theo luồng thực thi trong hàm tìm kiếm chính. Không quá mười lăm phút, vết nứt tử huyệt đã lộ diện. Nhóm sử dụng một vòng lặp `while` để duyệt qua tất cả các đỉnh lân cận của nút hiện tại. Trong mỗi bước lặp, họ dùng lệnh `malloc` để cấp phát một vùng nhớ tạm thời chứa thông tin luồng dữ liệu của nhánh rẽ. Nhưng bi kịch nằm ở chỗ: mỗi khi nhánh rẽ đó không thỏa mãn điều kiện ràng buộc về dung lượng truyền tải, người viết lại cẩu thả ném vào một lệnh `continue` để lập tức nhảy cóc sang nhánh tiếp theo.

Vùng nhớ vừa xin cấp phát từ hệ điều hành lập tức bị bỏ rơi. Con trỏ tạm thời bị ghi đè, và ô nhớ cũ trôi dạt vô định trong không gian địa chỉ mà không hề có lệnh `free` nào thu hồi nó lại.

Với một đồ thị thử nghiệm vài chục nút trong giáo trình, sai số này hoàn toàn vô hình, bởi dung lượng RAM của hệ điều hành đủ rộng để dung túng cho vài chục kilobyte rác bị bỏ quên. Nhưng khi nhét vào một tệp dữ liệu thực tế với một nghìn đỉnh và hàng vạn cạnh, hàng triệu khối nhớ rác tích tụ lại như một con đập bị nghẽn bùn. Hệ thống cạn kiệt tài nguyên cấp phát, tiến trình cố tình ghi đè lên các vùng nhớ được bảo vệ khác, và nhân Linux lập tức giáng xuống một nhát búa lạnh lùng, tàn nhẫn: *Segmentation fault (core dumped)*.

Tôi dùng bút bi mực đỏ gạch một đường dứt khoát ngang qua đoạn mã đó. Lỗi này là hệ quả của một thói quen viết mã chộp giật, thiếu nền tảng về quản lý tài nguyên cấp thấp. Sửa nó chỉ mất năm phút.

Nhưng vấn đề thứ hai mới thực sự là một ngọn núi đá sừng sững: thời gian thực thi của giải thuật.

Thuật toán mà Phong và hai bạn đang cài đặt là một biến thể vụng về của thuật toán Dijkstra cổ điển. Trong mỗi bước tìm kiếm đỉnh có khoảng cách ngắn nhất chưa được thăm, thay vì sử dụng cấu trúc hàng đợi ưu tiên (Priority Queue) để trích xuất phần tử cực tiểu trong thời gian logarit, các bạn lại dùng một mảng tĩnh một chiều và cho một vòng lặp chạy tuần tự từ phần tử đầu tiên đến phần tử cuối cùng để so sánh.

Với một đồ thị có $N$ đỉnh, độ phức tạp tính toán bị đẩy thẳng lên mức $O(N^2)$. Nếu đồ thị thưa có hàng chục nghìn đỉnh, số phép toán so sánh sẽ chạm ngưỡng hàng trăm triệu phép tính.

Trên chiếc máy tính hiện đại của Phong chạy chip Core 2 Duo với hai gigabyte RAM, bộ xử lý có thể dùng sức mạnh phần cứng thô bạo để nghiền nát một thuật toán tồi trong vòng vài giây mà mắt thường khó nhận ra sự chậm trễ. Nhưng trên cỗ máy Pentium III 600MHz cổ lỗ sĩ này của tôi, với thanh RAM 256MB còi cọc đang phải gánh cả hệ điều hành lẫn các tiến trình nền, bi kịch lộ rõ ngay lập tức. Khi tôi thử nạp bộ dữ liệu năm nghìn đỉnh, con trỏ chuột trên màn hình CRT lập tức đông cứng lại. Đèn báo ổ cứng màu đỏ lừ ở mặt trước thùng máy sáng rực không chớp, phát ra những tiếng kêu *lọc cọc... tạch tạch...* nhọc nhằn, rên rỉ khi bộ nhớ ảo phải liên tục tráo đổi dữ liệu (paging/swapping) giữa RAM và các phiến đĩa từ đã xước.

Cỗ máy quá chậm. Nó không thể dung thứ cho sự cẩu thả của thuật toán. Sự nghèo nàn về phần cứng tước đi của tôi mọi sự khoan nhượng, nhưng chính nó lại đẩy tôi vào con đường duy nhất của một lập trình viên chân chính: phải giải quyết vấn đề từ gốc rễ toán học thuần khiết nhất.

Tôi thở hắt ra một hơi dài, ngửa cổ nhìn lên trần nhà loang lổ những vệt ẩm mốc hình thù kỳ dị. Đám muỗi bắt đầu vo ve quanh mắt cá chân. Tôi cúi xuống, kéo cao hai ống quần bảo hộ lao động dày cộm lên quá bắp chân để tránh muỗi đốt, với tay lấy cốc nước lọc đã nguội ngắt để trên bậu cửa sổ, ực một ngụm lớn nhằm đè nén cơn cồn cào trong dạ dày. Bát cơm nguội với miếng đậu phụ rán chan nước mắm mặn chát mà chị bếp cho tôi lúc chín giờ tối ở quán cà phê đã tan biến từ lâu sau những chặng chạy bàn liên tục.

Đồng hồ điểm một giờ ba mươi phút sáng.

Tôi quyết định không sửa trên cái đống rác cũ của nhóm nữa. Việc chắp vá một cấu trúc đã hỏng từ gốc rễ chỉ tổ sinh ra thêm những lỗi tiềm ẩn quái gở. Tôi mở một tệp tin mới tinh trong trình soạn thảo `nano` trên giao diện dòng lệnh: `core_solver.c`.

Tôi sẽ đập đi xây lại toàn bộ từ con số không.

Thay vì dùng mảng tĩnh và tìm kiếm tuần tự, tôi tự tay định nghĩa một cấu trúc Cây đống nhị phân tối thiểu (Min-Heap). Vì không muốn lạm dụng các lệnh cấp phát động `malloc` vốn rất tốn chu kỳ xử lý của CPU Pentium III và dễ gây phân mảnh bộ nhớ, tôi tự tạo một mảng quản lý trạng thái tĩnh cố định ngay từ khi chương trình khởi tạo.

Tôi bắt đầu viết các hàm cốt lõi của cây đống: hàm vun đống ngược lên (`heapify_up`), hàm vun đống xuôi xuống (`heapify_down`), hàm trích xuất nút có chi phí đường đi nhỏ nhất (`extract_min`), và hàm cập nhật giảm khóa (`decrease_key`). Với cấu trúc này, mọi thao tác lấy ra nút tối ưu chỉ tiêu tốn thời gian $O(\log N)$, và việc cập nhật chi phí đường đi cũng chỉ mất $O(\log N)$. Toàn bộ độ phức tạp của bài toán sẽ giảm ngoạn mục từ $O(N^2)$ xuống $O((E + N) \log N)$, trong đó $E$ là số lượng cạnh kết nối.

Những ngón tay tôi bắt đầu gõ xuống bàn phím. Ban đầu còn ngập ngừng, chậm chạp vì các khớp tay còn buốt, nhưng càng về sau, nhịp gõ càng trở nên dồn dập, đều đặn như tiếng máy khâu đạp chân của mẹ Mai trong những đêm giáp Tết ở quê nhà.

Trong gian phòng tự học rộng thênh thang và lạnh lẽo, tiếng lách cách của bàn phím cơ vang lên khô khốc, gõ vào màn đêm tĩnh mịch một nhịp điệu kiên trì, cô độc. Tôi quên mất cái đói đang cào ruột, quên mất mùi cà phê khét nồng bám trên da thịt, quên cả tiếng muỗi vo ve quanh tai. Tôi chìm vào thế giới của những con trỏ, những mảng phẳng chỉ số, những phép toán dịch bit (`<<`, `>>`) để tìm nút cha, nút con trên cây nhị phân mà tôi đã thuộc nằm lòng từ những ngày còn ngồi chép trộm sách thuật toán ở thư viện tỉnh.

Lập trình đối với tôi chưa bao giờ là một thứ nghệ thuật thời thượng để khoe mẽ, cũng không phải là chiếc chìa khóa thần kỳ để đổi đời theo kiểu hào nhoáng của những người thành phố. Nó là sự cứu rỗi duy nhất mà tôi nắm bắt được. Trong cái thế giới khắc nghiệt bên ngoài kia, tôi là một đứa nhà quê nghèo rớt mồng tơi, mặc chiếc áo sơ mi sờn cổ, phải lủi thủi bưng từng khay nước ngọt và cúi đầu trước những cái nhìn xoi mói của những vị khách ăn mặc sang trọng. Nhưng trước màn hình CRT đen sì này, trước những dòng lệnh C trần trụi và lạnh lùng, mọi thứ đều công bằng tuyệt đối. Máy tính không phân biệt xuất thân của bạn; nó không quan tâm bạn ăn cơm căng-tin hay ăn sơn hào hải vị. Nếu logic của bạn đúng, nó sẽ cho ra kết quả đúng. Nếu bạn đặt sai một con trỏ, nó sẽ trừng phạt bạn không thương tiếc. Đó là sự chính xác thuần khiết, một thứ trật tự hoàn hảo mà cuộc đời đầy rẫy bất công của tôi chưa từng có được.

Ba giờ bốn mươi phút sáng.

Tôi vươn vai, các khớp xương sống kêu răng rắc. Tôi gõ xong hàm cuối cùng: hàm truy vết và hoàn nguyên đường đi tối ưu từ đỉnh đích ngược về đỉnh nguồn, dựa trên mảng chỉ số nút cha.

Tôi lưu tệp tin, thoát ra màn hình dòng lệnh của hệ điều hành Linux. Tôi gõ lệnh biên dịch với các cờ tối ưu hóa khắt khe nhất: `gcc -Wall -Wextra -O2 core_solver.c -o core_solver`

Tôi nhấn phím Enter.

Chiếc quạt tản nhiệt của cỗ máy rít lên một tràng dài. Ống phóng điện tử kêu *u... u...* bên tai. Tôi nín thở, hai bàn tay nắm chặt mép bàn gỗ, các đốt ngón tay trắng bệch ra vì căng thẳng. Mười giây trôi qua dài tựa mười thế kỷ. Màn hình dòng lệnh nhấp nháy con trỏ màu trắng.

Không có bất kỳ dòng cảnh báo nào. Không có một thông báo lỗi nào xuất hiện. Chương trình đã được dịch sang mã máy một cách hoàn hảo.

Tôi lập tức viết một đoạn mã kịch bản nhỏ bằng ngôn ngữ Bash để tự động sinh ra một tệp dữ liệu ngẫu nhiên mô phỏng mạng lưới phân phối dữ liệu khổng lồ: mười nghìn nút mạng và năm mươi nghìn cạnh kết nối, kèm theo các trọng số về độ trễ truyền dẫn và ngưỡng dung lượng ngẫu nhiên. Quy mô này lớn gấp mười lần yêu cầu thử nghiệm tối đa mà thầy Tuấn đưa ra trong đề bài.

Tôi gõ lệnh thực thi, kèm theo lệnh đo thời gian và công cụ kiểm tra rò rỉ bộ nhớ Valgrind: `valgrind --leak-check=full ./core_solver test_10k.txt`

Một vệt sáng lướt qua mắt tôi.

Chiếc quạt tản nhiệt khẽ rùng mình một nhịp rất nhẹ. Và rồi, trên nền màn hình đen sì, toàn bộ bảng kết quả hiện ra. Từng dòng văn bản cuộn mượt mà như một dải lụa: danh sách các trạm trung chuyển tối ưu, tổng độ trễ, lưu lượng phụ tải khả dụng trên từng cung mạng, và thời gian thực thi: *0.038 giây*.

Dưới cùng, Valgrind in ra những dòng thông báo xanh rờn của sự hoàn mỹ: `HEAP SUMMARY:` ` in use at exit: 0 bytes in 0 blocks` ` total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated` `All heap blocks were freed -- no leaks are possible.` `ERROR SUMMARY: 0 errors from 0 contexts.`

Không rò rỉ một byte bộ nhớ nào. Thuật toán mới nuốt trọn bộ dữ liệu mười nghìn nút trong một cái chớp mắt, nhanh gấp ít nhất bốn mươi lần so với bản thiết kế cũ kỹ của cả nhóm. Cảm giác đê mê của một người thợ vừa dùng chính bàn tay trần và cây búa thô sơ đập nát một cỗ máy cồng kềnh để rèn lại thành một lưỡi dao sắc lẹm chạy dọc khắp các mạch máu trong người tôi. Cơn mệt mỏi thể xác dường như bốc hơi hoàn toàn trong giây phút ấy.

Tôi mỉm cười một mình giữa góc phòng tự học vắng ngắt. Tôi cắm chiếc USB vỏ nhựa cũ mòn của mình vào máy, sao chép tệp tin `core_solver.c` vào thư mục gốc.

Tôi không viết thêm bất kỳ dòng chú thích nào vào đoạn mã. Trong mắt tôi lúc đó, mọi thứ đã quá rõ ràng và trong sáng: các hàm con trỏ, các mảng trạng thái phẳng, các phép toán nhị phân xử lý bit trên cây đống đều là những chuẩn mực tối ưu không thể bàn cãi. Tôi nghĩ bụng, bất kỳ ai đã học đến năm thứ hai đại học ngành công nghệ thông tin khi nhìn vào đoạn mã này cũng sẽ lập tức hiểu được sự tinh tế của cấu trúc dữ liệu mà tôi đã dày công xây dựng.

Tôi cũng không buồn nhắn tin hay gọi điện cho Phong. Chiếc điện thoại cục gạch cũ kỹ của tôi đã hết sạch tiền từ ba ngày trước, và quan trọng hơn cả, trong đầu tôi lúc ấy đinh ninh một điều: phần khó khăn nhất, phần sống còn của cả môn học đã được giải quyết triệt để. Chuyện ghép nối giao diện, đọc vài ba tệp tin văn bản thì có gì to tát đâu? Đến lớp, chỉ cần ba mươi phút cắm máy vào là mọi thứ sẽ chạy trơn tru như một cỗ xe tăng bọc thép.

Tôi tắt máy tính, lắng nghe tiếng quạt nguồn lịm dần thành một tiếng thở dài khô khốc. Tôi thu dọn sách vở, lảo đảo bước ra khỏi phòng tự học khi ánh bình minh đầu tiên của ngày mới bắt đầu rải một lớp sáng mờ đục lên những ngọn xà cừ cổ thụ ngoài sân trường.

Về đến phòng 314, đồng hồ điểm gần năm giờ sáng. Cả phòng vẫn đang chìm trong tiếng ngáy đều đặn. Tôi nhẹ nhàng trèo lên chiếc giường tầng hai của mình, cởi chiếc áo khoác bạc màu đắp ngang ngực, nhắm nghiền đôi mắt cay xè và chìm ngay vào một giấc ngủ mê man, nặng nề như một tảng đá rơi xuống đáy vực.

***

“Nam! Dậy ngay! Cậu làm cái trò quái quỷ gì thế này hả?”

Một bàn tay thô bạo túm lấy vai tôi, lay mạnh như muốn giật tung khớp xương. Tấm chăn mỏng bị giật phắt ra khỏi người tôi một cách thô bạo.

Tôi giật nảy mình, mở choàng mắt. Đầu óc tôi quay cuồng dữ dội, một cơn choáng váng buốt nhức ập đến phía sau gáy vì bị đánh thức quá đột ngột sau giấc ngủ chập chờn chưa đầy hai tiếng đồng hồ. Ánh sáng ban mai chói chang hắt qua khung cửa sổ phòng 314 chiếu thẳng vào mắt làm tôi lóa đi, phải giơ cánh tay gầy guộc lên che trán, ho khan vài tiếng khô khốc.

Trước mặt tôi là Phong. Cậu ấy đã mặc sẵn chiếc áo khoác gió đồng phục của trường, nhưng khuôn mặt thì đỏ bừng lên vì giận dữ, hai cánh mũi phập phồng, ánh mắt tóe lửa. Trên tay Phong là chiếc laptop Asus đang mở toang, màn hình sáng rực, được cậu ta đặt mạnh xuống chiếc bàn tròn giữa phòng.

Chiếc đồng hồ treo tường chỉ bảy giờ mười lăm phút.

“Sao thế?” Tôi khàn giọng hỏi, cố gắng gượng ngồi dậy, hai bắp chân đau nhức như vừa phải gánh hàng chục cân ngô leo dốc. “Thuật toán chạy tốt mà... Tớ đã giải quyết xong hết từ lúc gần bốn giờ sáng rồi. Tớ lưu trong USB của cậu rồi đấy thôi.”

“Chạy tốt? Đúng, nó chạy nhanh đến mức tớ không dám tin vào mắt mình!” Phong gằn giọng, âm lượng lớn đến mức hai người bạn cùng phòng ở giường đối diện cũng phải giật mình cựa quậy. Phong xoay phắt màn hình laptop về phía tôi: “Tớ vừa nạp thử bộ dữ liệu mười nghìn nút, nó chạy cái vèo trong chưa đầy nửa giây! Tớ thực sự không hiểu bằng cách nào mà với cái máy cà tàng của cậu, cậu lại tối ưu được cấu trúc cây đống này kinh khủng đến thế.”

Tôi thoáng nở một nụ cười tự hào, với tay lấy chiếc áo sơ mi vắt ở đầu giường xỏ vào người: “Thầy Dũng ở quê từng dạy tớ cách lập cây nhị phân trên bộ nhớ tĩnh... Chỉ cần chia nhỏ vấn đề ra, kiểm soát chặt chẽ con trỏ thì triệt tiêu được rò rỉ ngay. Đã bảo với cậu rồi mà, chỉ cần giải được phần lõi toán học thì coi như bài tập lớn đã xong xuôi.”

“Xong cái đầu cậu ấy!” Phong cắt ngang lời tôi bằng một tiếng quát nén lại trong lồng ngực, đầy ức chế. Cậu ta dí ngón tay trỏ sát vào màn hình, nơi hàng trăm dòng mã nguồn mới toanh của tôi đang hiển thị trong trình soạn thảo: “Cậu nhìn xem cậu viết cái gì ở đây? Cậu có nhận ra mình đã làm gì không? Cậu tự ý xóa sạch toàn bộ cấu trúc dữ liệu `struct Node` và `struct Edge` mà tớ đã thức trắng cả tuần trước để thống nhất với hai đứa kia! Cậu tự ý đổi kiểu dữ liệu từ danh sách liên kết sang mảng con trỏ tĩnh! Cậu bỏ luôn cả ba cái hàm giao tiếp `get_next_neighbor` và `read_graph_file` mà Tuấn với Hoàng đã cặm cụi viết để đọc dữ liệu đầu vào!”

Tôi ngơ ngác trèo xuống thang giường, bước chân trần chạm vào nền gạch men lạnh ngắt làm tôi rùng mình một cái: “Thì cấu trúc cũ của các cậu quá cồng kềnh, dùng danh sách liên kết cấp phát động ở quy mô lớn là nguyên nhân trực tiếp gây phân mảnh bộ nhớ và tràn RAM. Tớ đổi sang mảng phẳng thì tốc độ truy xuất ngẫu nhiên mới đạt $O(1)$ được chứ! Cách ấy tối ưu hơn hẳn, về mặt khoa học máy tính thì cấu trúc của tớ vượt trội hoàn toàn mà?”

“Vượt trội? Đúng, về mặt lý thuyết toán học thì cậu tối ưu tuyệt đối, không ai cãi được cậu!” Ngực Phong phập phồng dữ dội, cậu ta trừng mắt nhìn thẳng vào mặt tôi, hai hàm răng nghiến chặt: “Nhưng đây là bài tập nhóm, Nguyễn Văn Nam ạ! Cậu có hiểu hai chữ ‘làm việc nhóm’ nghĩa là cái quái gì không? Suốt cả đêm qua cậu đập đi xây lại toàn bộ mà không thèm hé răng lấy một lời trong nhóm chat! Cậu không gửi lấy một tin nhắn báo rằng cậu đã vứt bỏ toàn bộ giao diện hàm cũ! Cậu biến cái phần lõi của cậu thành một ốc đảo riêng biệt, chỉ có một mình cậu hiểu cậu đang làm cái gì. Cậu viết theo kiểu của một mình cậu: không một dòng chú thích, các biến đặt tên toàn là `u`, `v`, `k`, `flag_mask`... Cậu tự chế ra các cờ hiệu nhị phân mà không ai biết để làm gì! Bây giờ còn đúng một tiếng mười lăm phút nữa là đến giờ lên lớp của thầy Tuấn, cậu bảo tớ và hai đứa kia phải làm thế nào để ghép cái giao diện dòng lệnh với phần xuất báo cáo vào cái mớ mã nguồn siêu đẳng này của cậu?”

Từng lời nói của Phong như những gáo nước đá tạt thẳng vào mặt tôi giữa buổi sáng mùa thu se lạnh. Tôi đứng chôn chân giữa phòng 314, hai bàn tay buông thõng bên hông, ngực nghẹn lại.

Một làn sóng tự ái và phản kháng dữ dội bùng lên trong lồng ngực tôi. Tôi đã thức trắng một đêm ròng sau ca làm việc kiệt sức ở quán cà phê. Tôi đã còng lưng bên cỗ máy cũ kỹ, chịu đựng tiếng muỗi đốt, cái đói cào ruột để bẻ gãy một bài toán hóc búa mà cả ba người bọn họ đã giơ tay đầu hàng suốt mấy ngày trời. Tôi đã cứu cả nhóm thoát khỏi một bàn thua trông thấy, tạo ra một chương trình chạy với tốc độ không tưởng mà có lẽ cả khóa K58 này hiếm đứa nào làm nổi trên một cỗ máy thời tiền sử. Vậy mà cái tôi nhận được không phải là một lời cảm ơn, không phải là sự khâm phục, mà lại là sự trách móc, hạch sách giận dữ chỉ vì mấy cái tên biến và vài ba cái hàm giao diện tầm thường?

“Chương trình đã chạy ra kết quả đúng tuyệt đối,” tôi cất tiếng, giọng tôi đanh lại, lạnh lùng và cố chấp như cái cách tôi từng cãi lại bác Lương bên đống ngô vụ trước ở Nà Ban. “Quan trọng nhất là nộp một sản phẩm chạy đúng thuật toán và giải quyết được bài toán tối ưu. Mấy cái hàm nhập xuất kia chỉ là vỏ bọc bên ngoài, sửa lại vài tham số truyền vào là xong, có gì mà cậu phải làm ầm ĩ lên như thế?”

Phong cười nhạt một tiếng, một nụ cười đầy vẻ thất vọng và cay đắng: “Cậu tưởng sửa tham số là xong à? Cậu tưởng đời này cái gì cũng đơn giản như việc cậu ngồi một xó giải toán à? Cậu tự nhìn đi!”

Phong giật lấy con chuột quang, mở tập tin mã nguồn tích hợp mà Tuấn và Hoàng vừa gửi qua hòm thư điện tử lúc sáu giờ sáng. Cậu ta bấm lệnh biên dịch toàn bộ dự án: `gcc main.c io_handler.c core_solver.c -o network_opt`

Màn hình laptop lập tức đỏ rực lên bởi một dải dài dằng dặc những dòng thông báo lỗi chết chóc: `io_handler.c:45: error: unknown type name ‘CustomNode’` `main.c:112: error: too few arguments to function ‘solve_network_routing’` `core_solver.c:18: fatal error: conflicting types for ‘initialize_graph’`

Hơn năm mươi lỗi biên dịch đổ ập xuống như một trận sạt lở đất đá mùa mưa lũ. Toàn bộ dự án vỡ vụn. Các mô đun không thể nói chuyện được với nhau, các kiểu dữ liệu xung đột chan chát, các con trỏ trỏ vào những khoảng không vô định.

Đúng lúc đó, cánh cửa phòng 314 bị đẩy bật ra. Tuấn và Hoàng hớt hải lao vào phòng, mặt mày tái mét không còn một hột máu, trên tay vẫn còn cầm hai ổ bánh mì kẹp chả gặm dở: “Sao rồi Phong? Ghép mã nguồn xong chưa? Nguy to rồi mày ơi! Thầy Tuấn vừa đăng thông báo khẩn trên diễn đàn môn học, hôm nay thầy sẽ gọi ngẫu nhiên ba nhóm lên cắm máy chiếu chạy thử trực tiếp trước cả giảng đường đấy!”

Phong không quay đầu lại nhìn hai người bạn mới vào, chỉ hất cằm về phía tôi, buông ra một câu cay đắng: “Hỏi thiên tài thuật toán của chúng ta ấy. Cậu ấy vừa cứu sống phần thuật toán, nhưng tiện tay bức tử luôn toàn bộ hệ sinh thái của cả nhóm rồi.”

Căn phòng 314 bỗng chốc rơi vào một sự im lặng ngột ngạt đến nghẹt thở. Tuấn và Hoàng nhìn trừng trừng vào màn hình laptop đang đỏ lòm những dòng thông báo lỗi, rồi quay sang nhìn tôi bằng ánh mắt vừa bàng hoàng, vừa bất lực, vừa pha lẫn một chút tức giận.

Tuấn vò đầu bứt tai, chiếc bánh mì trên tay suýt rơi xuống đất: “Trời đất ơi Nam... Sao cậu lại đổi hết định dạng dữ liệu đầu vào thế này? Tệp kiểm thử của thầy phát hôm trước được cấu trúc theo thẻ bản ghi, tụi tớ đã thức trắng hai đêm để viết hơn một trăm dòng mã xử lý chuỗi ký tự theo đúng cái `struct` cũ. Giờ nhìn vào hàm của cậu, toàn mảng phẳng với chỉ số dịch bit thế này, khác gì nhìn vào chữ Phạn đâu? Làm sao mà viết lại toàn bộ trình phân tích cú pháp trong vòng bốn mươi phút nữa?”

Tôi đứng chôn chân tại chỗ, nhìn trôi dạt vào những dòng thông báo lỗi màu đỏ trên màn hình. Lần đầu tiên trong suốt hai mươi năm cuộc đời, sự tự tin sắt đá về năng lực kỹ thuật của tôi xuất hiện một vết rạn nứt sâu hoắm, lạnh buốt.

Tôi từng nghĩ máy tính là một thế giới độc lập, tách biệt hoàn toàn với những phức tạp, phiền toái của con người—chỉ cần công thức đúng, logic chuẩn xác thì cái máy sẽ ngoan ngoãn phục tùng. Tôi đã quen với việc một mình đối mặt với cỗ máy Pentium III trong gian chái phụ tối tăm ở Nà Ban, tự mình đặt ra đề bài, tự mình giải, tự mình kiểm tra và tự mỉm cười gật đầu với chính bản thân. Nhưng ở giảng đường đại học này, một phần mềm không phải là một bài toán thi học sinh giỏi đóng khung trong một tệp mã nguồn đơn độc. Nó là một cỗ máy gồm nhiều bánh răng khớp nối vào nhau. Và một bánh răng—dù cho có được đúc bằng vàng ròng, mài giũa tinh xảo đến từng micromet đi chăng nữa—nhưng nếu làm sai kích thước chốt nối, sai bước răng với phần còn lại của hệ thống, thì nó cũng chỉ là một khối kim loại phế thải, làm kẹt cứng và phá hủy toàn bộ cỗ máy.

Tôi nhìn đồng hồ. Bảy giờ hai mươi lăm phút.

“Đưa máy cho tớ,” tôi cất tiếng. Giọng tôi trầm xuống, không còn một chút kiêu hãnh hay bướng bỉnh nào của ban nãy.

Phong nhìn tôi trừng trừng: “Cậu định làm gì? Viết lại từ đầu à?”

“Không,” tôi lắc đầu, ngồi thụp xuống chiếc ghế trước bàn, kéo chiếc laptop Asus về phía mình. “Tớ sẽ viết một lớp chuyển đổi trung gian—một cái adapter wrapper. Các cậu không cần sửa một dòng nào trong hàm nhập xuất hay giao diện nữa. Giữ nguyên toàn bộ cấu trúc `struct Node` cũ của các cậu. Tớ sẽ viết một hàm đệm để hứng dữ liệu từ cấu trúc cũ, tự động chuyển đổi và nén nó vào mảng phẳng của tớ trước khi đẩy vào hàm giải, rồi sau đó lại giải nén kết quả trả ngược về định dạng cũ của các cậu.”

Phong nhìn chằm chằm vào mắt tôi, giọng nói sắc lạnh như dao: “Cậu còn đúng bốn mươi phút. Đúng tám giờ mười lăm chúng ta phải rời khỏi phòng này để chạy sang giảng đường. Nếu trước tám giờ mười lăm mà không biên dịch xong, tớ sẽ nộp biên bản trắng và ghi rõ nhóm không thể tích hợp được mã nguồn vì lỗi cá nhân.”

Không một ai nói thêm bất kỳ lời nào nữa. Bầu không khí trong phòng 314 đặc quánh lại như keo. Tiếng quạt tản nhiệt của chiếc máy Asus thổi vù vù giữa những tiếng thở dài thườn thượt, đầy lo âu của Tuấn và Hoàng.

Tôi bắt đầu gõ phím. Những ngón tay tôi lướt trên bàn phím laptop với một tốc độ điên cuồng, tuyệt vọng. Lưng áo sơ mi của tôi lại bắt đầu ướt đẫm mồ hôi lạnh, nhưng lần này không phải vì hơi nóng của quán cà phê, cũng không phải vì sức nặng của những khay nước bưng bê, mà là vì một nỗi sợ hãi hoàn toàn mới: nỗi sợ của một kẻ vừa nhận ra rằng lời giải hoàn hảo của mình đang biến thành một gánh nặng, một thảm họa không thể dung nạp đối với những người xung quanh.

Tôi viết hàm `convert_legacy_to_flat()`. Tôi phải cẩn thận ép từng kiểu con trỏ, tính toán lại từng bước nhảy địa chỉ trên mảng tĩnh, bắt từng trường hợp biên khi các đỉnh trong danh sách liên kết cũ bị thiếu thông tin liên kết. Từng phút trôi qua như có lửa đốt dưới chân ghế.

Bảy giờ bốn mươi lăm. Viết xong phần chuyển đổi đầu vào. Tám giờ tròn. Viết xong phần ánh xạ ngược kết quả đầu ra. Tám giờ mười phút. Tôi gõ lệnh biên dịch lại toàn bộ dự án.

Trình biên dịch chạy trong ba giây. Con trỏ nhấp nháy. Dòng chữ thông báo lỗi màu đỏ biến mất. Thay vào đó là một tập tin thực thi duy nhất được tạo ra: `network_opt`.

Tôi nạp thử tệp dữ liệu mẫu của thầy Tuấn. Giao diện dòng lệnh do Tuấn và Hoàng thiết kế hiện lên, các bảng biểu hiển thị ngay ngắn, và chỉ mất đúng 0.05 giây để thuật toán của tôi nhả ra đường đi tối ưu với đầy đủ các tham số theo đúng định dạng ban đầu của nhóm.

Phong không kịp nói một lời cảm ơn, cũng chẳng kịp thở phào. Cậu ấy giật phắt chiếc USB ra khỏi cổng cắm, gập mạnh màn hình laptop lại, nhét vội vào ba lô rồi vẫy tay gọi Tuấn và Hoàng: “Chạy mau! Muộn giờ nộp là thầy khóa hệ thống đấy!”

Ba người họ lao như bay ra khỏi cửa phòng, tiếng đế giày nện thình thịch xuống bậc cầu thang nhà B7 rồi mất hút trong tiếng ồn ào của dòng sinh viên đang đổ về các khu giảng đường.

Căn phòng 314 đột ngột trở lại vẻ tĩnh lặng hoang hoải.

Tôi ngồi gục xuống mép chiếc giường sắt thô ráp, hai bàn tay buông thõng giữa hai đầu gối, run lên bần bật vì căng thẳng thần kinh kéo dài. Cả thân xác tôi rã rời, trống rỗng như một thân cây mục ruỗng vừa bị rút cạn nhựa sống.

Chiều hôm đó, tôi có một buổi giảng lý thuyết môn Tin học đại cương lúc một giờ ba mươi tại giảng đường D3—một môn học cơ sở với những khái niệm lập trình sơ khai mà tôi từng lướt qua giáo trình và đinh ninh rằng mình đã nắm chắc trong lòng bàn tay từ hồi còn ngồi ở phòng máy cũ của thầy Dũng. Tôi lảo đảo bước tới bàn, với tay vặn chiếc đồng hồ báo thức cơ học bằng sắt cũ kỹ, kéo cái chốt hẹn giờ đến đúng mười hai giờ bốn mươi lăm phút.

Tôi leo lên giường tầng hai, kéo tấm chăn mỏng ngang ngực, nhắm nghiền đôi mắt cay xè. Tôi chỉ cần ngủ một giấc ngắn, chỉ một giấc ngắn thôi để hồi phục lại chút sức lực tàn tạ này.

Nhưng chiếc đồng hồ cơ ấy reo chuông vào lúc nào, tôi hoàn toàn không hay biết.

Cơn kiệt sức tích tụ sau ca làm đêm ngâm mình trong xà phòng, cộng với một đêm trắng căng não viết mã và bốn mươi phút chạy đua với tử thần buổi sáng, đã dìm cả thể xác lẫn tâm trí tôi xuống một tầng sâu thăm thẳm của sự mê man. Không mộng mị, không một ảo giác, chỉ là một khoảng tối đen đặc quánh, nặng trềnh trịch như chì đè nghiến lên lồng ngực.

Tôi bừng tỉnh vì một cơn co thắt nhói buốt ở vùng thượng vị—cơn đau dạ dày quen thuộc của một đứa thường xuyên bỏ bữa.

Tôi giật mình mở mắt trừng trừng nhìn lên trần nhà. Ánh nắng gay gắt ban trưa ngoài cửa sổ đã hoàn toàn tắt lịm. Thay vào đó là một ráng chiều đỏ quạch, ảm đạm hắt những vệt bóng dài của chấn song sắt lên bức tường vôi lở loét.

Tôi hốt hoảng nhìn sang chiếc đồng hồ Poljot trên cổ tay. Bốn giờ mười lăm phút chiều.

Buổi học Tin học đại cương đã kết thúc từ hơn bốn mươi phút trước.

Tôi ngồi chết trân trên giường sắt, toàn thân lạnh ngắt từ đỉnh đầu xuống tận gót chân. Tiếng ve sầu cuối thu ngoài sân trường rỉ rả những âm thanh thê lương, nhức nhối.

Mãi đến sáu giờ tối, khi trời sập tối hẳn, Phong mới đẩy cửa bước vào phòng. Cậu ấy không nói một lời nào về chuyện sáng nay, trên tay cầm theo cuốn vở ghi chép của một bạn cùng lớp và một hộp cơm căng-tin nguội ngắt mua về cho tôi.

Cậu ấy đặt cuốn vở lên bàn, bật chiếc điện thoại di động lên, mở một bức ảnh chụp bảng danh sách điểm danh được giảng viên dán ở cửa giảng đường sau giờ học.

“Hôm nay thầy Tuấn bất ngờ cho cả lớp làm một bài kiểm tra ngắn mười lăm phút ngay đầu giờ,” Phong nói, giọng trầm xuống, không có vẻ gì là giễu cợt hay hả hê. “Thầy dùng bài kiểm tra đó để vừa điểm danh, vừa lấy điểm hệ số một vào điểm quá trình.”

Tôi run rẩy nhìn vào màn hình điện thoại của Phong. Ở dòng thứ bốn mươi hai, bên cạnh cái tên *Nguyễn Văn Nam - Lớp CNTT K58*, là một con số không đỏ chót được ghi bằng bút dạ dầu, kèm theo dòng chữ ký tắt lạnh lùng: *Vắng mặt không lý do*.

Con số không đầu tiên trong suốt mười hai năm đi học giáng xuống đầu tôi buốt nhói như một cú đấm thép.

Nỗi xấu hổ trào lên nghẹn ứ nơi cuống họng, đắng ngắt và nhục nhã hơn cả cái khoảnh khắc tôi bị gã khách chơi cờ quát tháo là “thằng nhà quê ngơ ngác” giữa quán cà phê Mùa Gió tối hôm trước. Ở bản Nà Ban hay ở trường huyện, tôi luôn là đứa làm được những việc khó khăn nhất, giải quyết những bài toán hóc búa nhất mà cả trường phải bó tay. Nhưng cỗ máy đại học khắc nghiệt này không vận hành theo quy luật của một cuộc thi học sinh giỏi cấp tỉnh. Nó không được sinh ra chỉ để chấm điểm những khoảnh khắc lóe sáng cá nhân mà tôi tự chọn để phô diễn. Hệ thống ấy đòi hỏi sự hiện diện, tính kỷ luật, sự tuân thủ đều đặn và chuẩn xác của từng mắt xích thường nhật—những thứ mà một kẻ phải bán từng giờ ban đêm lấy sáu mươi sáu nghìn đồng tiền công rửa bát như tôi không cách nào kiểm soát nổi.

Tôi có thể thức trắng đêm để bẻ gãy một thuật toán tối ưu đồ thị phức tạp nghìn nút, nhưng tôi lại ngã gục nhục nhã trước một bài kiểm tra định nghĩa nhị phân cơ bản mười lăm phút chỉ vì một giấc ngủ quên cay đắng.

Phong kéo ghế ngồi đối diện tôi. Cậu ấy nhìn gương mặt hốc hác, đôi mắt trũng sâu thâm quầng và đôi bàn tay thô ráp còn vương mùi xà phòng bếp của tôi, rồi hỏi bằng một giọng trầm thấp, nặng trĩu:

“Cậu định sống bằng bao nhiêu đêm như thế này nữa, Nam?”

Tôi cúi gầm mặt, nhìn chằm chằm vào đôi dép tổ ong rách mép dưới chân, trốn tránh ánh mắt sắc sảo của người bạn cùng phòng: “Tớ mệt quá nên ngủ quên thôi... Tớ sẽ sắp xếp lại. Mấy hôm nữa quen việc ở quán Mùa Gió rồi, tớ sẽ xin anh quản lý đổi ca, chèn giờ học vào giữa.”

“Sắp xếp thế nào được khi lịch học kín ban ngày còn lịch ca kín ban đêm?” Phong thở dài, đẩy hộp cơm về phía tôi. “Bách khoa không phải là chỗ để cậu cậy thông minh rồi muốn học lúc nào thì học, muốn bỏ lúc nào thì bỏ. Cậu cứ tự bào mòn cơ thể theo cái kiểu liều mạng này, chưa kịp lấy được tấm bằng kỹ sư thì người cậu đã tàn phế rồi.”

Tôi không thể cất lời đáp lại. Tôi biết Phong nói đúng từng câu từng chữ. Nhưng phía sau lưng tôi là một khoảng trống rỗng không có đáy: không một đồng trợ cấp từ gia đình, không một khoản tiền dự phòng trong túi áo, và mỗi bát cơm tôi nuốt vào cổ họng hằng ngày đều phải đánh đổi bằng từng phút ngâm tay trong chậu nước xà phòng kiềm nồng nặc.

***

Chiều ngày hôm sau, nhóm chúng tôi có mặt tại phòng thực hành máy tính ở tầng ba nhà D9 để chuẩn bị cho buổi báo cáo thử nghiệm trước toàn lớp.

Bài tập lớn của nhóm đã qua được vòng kiểm duyệt sơ bộ của trợ giảng sau khi lớp chuyển đổi trung gian của tôi hoạt động ổn định. Giờ đây, Phong đang cắm chiếc USB vào cỗ máy tính thực hành của phòng máy, nạp bộ dữ liệu thử nghiệm chuẩn do khoa cung cấp để kiểm tra lần cuối trước khi thầy Tuấn bước vào đánh giá.

Chương trình vận hành trơn tru một cách đáng kinh ngạc.

Cấu trúc Cây đống nhị phân tối thiểu mà tôi thức trắng đêm viết trong căn phòng tự học lạnh lẽo đã phát huy uy lực tuyệt đối trên nền phần cứng chuẩn của phòng máy. Trên màn hình CRT đen sì của giao diện dòng lệnh, các dòng kết quả, đường đi tối ưu qua các nút trung chuyển và thời gian phản hồi chưa đầy hai phần trăm giây cuộn vút qua màn hình như một dải lụa.

Tuấn và Hoàng đứng phía sau khẽ reo lên một tiếng nhẹ nhõm, đập tay nhau ăn mừng. Phong gật đầu, khuôn mặt giãn ra đôi chút, thầm thừa nhận rằng phần việc khó nhằn nhất rốt cuộc đã chạy không một tì vết kỹ thuật nào.

Giữa lúc cả nhóm đang thở phào nhẹ nhõm, một bóng người từ hàng ghế phía sau bước lại gần khu vực máy của chúng tôi.

Đó là một nữ sinh viên có vóc dáng mảnh khảnh, mái tóc cắt ngắn ngang vai gọn gàng, mặc chiếc áo sơ mi kẻ ca-rô phẳng phiu, sạch sẽ. Cô đứng tựa nhẹ lưng vào mép bàn máy bên cạnh, hai tay khoanh trước ngực, đôi mắt đen láy chăm chú nhìn từng khối văn bản đen trắng đang nhảy múa trên màn hình máy tính.

Tôi nhận ra cô ấy ngay lập tức—Bùi Thanh Hà, người luôn ngồi ở chính giữa bàn đầu trong tất cả các tiết lý thuyết trên giảng đường lớn. Hà là người luôn có những câu hỏi phản biện sắc sảo, khúc chiết đến mức đôi khi các giảng viên cũng phải dừng lại vài giây để cân nhắc câu chữ trước khi trả lời.

Hà nhìn chăm chú vào các thông số tài nguyên hiển thị ở góc dưới màn hình, rồi lướt mắt nhìn xuống bàn phím—nơi tôi vừa trực tiếp gõ một chuỗi tham số thực thi dài ngoằng toàn những cờ hiệu nhị phân kỳ quái mà tôi tự quy ước: `-m 0x0F -k 4 --mem-static`.

Đoạn, Hà ngước mắt lên, nhìn thẳng vào mặt tôi. Ánh mắt cô sáng, sắc lạnh, điềm tĩnh và hoàn toàn không có chút kiêng nể nào của một người bạn cùng khóa:

“Phần thuật toán của cậu chạy rất mượt,” Hà mở lời, giọng nói rành rọt, âm lượng vừa đủ để mấy nhóm xung quanh cũng có thể nghe thấy. “Tối ưu hóa cấu trúc cây đống trên mảng phẳng để tận dụng bộ nhớ đệm L1/L2 của CPU, xử lý dữ liệu lớn mà không tốn một chút RAM thừa nào. Rất ấn tượng.”

Tôi thoáng ngẩng đầu lên, trong lòng nhen nhóm một cảm giác tự hào kín đáo. Tôi ngỡ rằng đó là một lời tán dương kỹ thuật từ một người quan sát có chuyên môn thực thụ, một sự thừa nhận mà suốt hai ngày qua tôi chưa nhận được từ những người đồng đội của mình.

Nhưng ngay giây tiếp theo, nụ cười vừa chớm nở trên môi tôi lập tức đông cứng lại.

Giọng nói điềm tĩnh, lạnh lùng của Hà lại buông xuống giữa không gian nồng mùi ozone của phòng máy, sắc ngọt như một lưỡi dao mổ rạch toang tấm màn tự mãn vừa mới dựng lên trong tôi:

“Nhưng sản phẩm này của cậu làm ra, ngoài cậu với cái máy tính ra, thì gần như không một ai muốn dùng.”

How was this chapter?Ratings help Readeep recommend better stories