Mã Nguồn Ngược Dòng Chương 85 / 209

Chương 85 — Stack

Đường đi dây mạng trên tường văn phòng Tô Hiến Thành bị dán đè bởi sơ đồ kiến trúc của Minh. Mấy sợi cáp nhô ra ở góc bảng trắng, ngoằn ngoèo như mạch máu cũ chưa cắt, trong khi hệ thống mới lại được vẽ bằng bút đỏ ô vuông rành mạch. Hoàng đứng trước sơ đồ đó, cà phê đá trong tay còn một ngụm đã loãng. Mùi cà phê sữa trộn với mùi nhựa nóng từ máy in trên kệ thấp chạy thử label cho cuộn tem. Tiếng máy lạnh Toshiba rè rè xen vào nhịp gõ ThinkPad của Minh, lần nào quạt thổi mạnh cũng làm mép sơ đồ trên tường phấp phới.

Minh dán laptop lên cái bàn gỗ veneer, quay màn hình về phía cả nhóm.

“Em muốn dừng ý tưởng rewrite trên PHP,” anh nói. “Mình nên chuyển core sang Node.js, viết bằng TypeScript.”

Câu đó không to, nhưng đủ để Phương Anh ngẩng lên khỏi bảng chi phí tháng. Khoa đang gõ điện thoại cũng dừng tay. Trâm ngồi ở mép bàn ngoài, chưa hiểu hết, chỉ kịp kéo ghế lại gần hơn. Hoàng không nói ngay. Anh nhìn vào diagram mới của Minh: hình bên trái là một khối lớn chiếm gần hết bảng, bên trên ghi chữ PHP Monolith quen thuộc đến mức anh đọc nó bằng cơ thể, không phải bằng mắt; hình bên phải là nhiều ô vuông nhỏ hơn, tách ra theo khối: User, Debt, Notification, Report, mỗi ô khoanh tên riêng, phía trên là dòng Node.js + TypeScript, mũi tên chạy sang message queue, sang cache, sang database tách nhỏ.

Minh chỉ vào ô lớn bên trái.

“Đây là phần anh viết từ ngày đầu,” anh nói. “Chạy được. Nhưng mọi thứ nằm trong một khối. Auth, báo cáo, ghi nợ, thông báo, export file — đụng một chỗ là rủi ro một chỗ. Em không muốn sửa thêm trên cái này.”

Hoàng đặt cà phê lên mặt bàn, cố không để nó kêu mạnh.

“Tao viết cái đó,” anh nói, “và nó đang chạy.”

Minh gật.

“Chạy,” anh thừa nhận. “Nhưng nó chạy được vì mình còn nhỏ.”

“Nhỏ?” Khoa hỏi lại, mắt liếc Hoàng. “Mình vừa mới có văn phòng. Tao gọi đó là lớn.”

“Lớn ở đây khác,” Minh nói, không nhìn Khoa mà nhìn Hoàng. “Lớn ở đây là khi có thêm hai, ba developer vào code chung, khi khách nhảy từ ngàn sang ba ngàn, năm ngàn, khi feature mới đụng report, đụng giao dịch, đụng lịch sử nợ và anh không còn ngồi code từ 12 giờ khuya đến 3 giờ sáng để giữ mọi thứ.”

Hoàng nghe câu cuối đọng lại trong tai. Anh biết nó có lý. Anh cũng biết lý do nó chạm mình không phải vì câu nói đúng. Nó chạm vì suốt 18 tháng qua, nếu có thứ anh hiểu đến tận xương thì chính là cái khối PHP đó. Anh biết từng function nào ghi nợ, biết đoạn nào đã nợ kỹ thuật từ đợt hội chợ, biết file nào Khoa từng gọi điện báo lỗi lúc anh đang trong lớp. Anh thuộc nó bằng ký ức mùi và bằng thói quen, không chỉ bằng code.

Anh mở máy tính, mở terminal, rồi ghìm tay lại. Không phải lúc show code.

“Bảo hiểm,” anh nói. “Tao không muốn di chuyển khách hàng đang dùng để viết lại phần core cho đẹp. Nếu migrate sai, mất dữ liệu, chị Bảy tạp hóa gọi lần này khác lần trước.”

Khoa nhăn mặt.

“Chị Bảy mà gọi là mệt,” anh nói.

“Đó là lý do,” Hoàng nói.

Minh không lùi. Anh kéo chuột, mở slide mới. Trên màn hình hiện ra bảng so sánh đơn giản: PHP monolithNode.js microservices. Phía dưới là ba cột chỉ số. Anh chỉ từng dòng, giọng đều, không biện hộ.

“Type safety,” anh nói. “TypeScript cho anh bắt lỗi ở thời gian viết, không phải chờ khách báo. Developer experience — codebase tách service, module rõ ràng, người mới vào onboard nhanh hơn. Scalability — khi tăng trưởng, mình không bê nguyên cái nhà lên, mà mở thêm phòng.”

Hoàng nhìn ba chữ đó. Anh ghét câu nào cũng đúng. Nhưng anh cũng thấy cái anh ghét hơn: tất cả đều là chuyện sau này. Hiện tại, chị Bảy vẫn gọi điện hỏi vì sao hôm nay báo cáo không in được. Hiện tại, Trâm vừa nhận được insight từ khách muốn tìm nợ theo biệt danh, không phải theo tên chính. Hiện tại, codebase của Hoàng vẫn là thứ duy nhất đủ quen để anh vá kịp khi mọi thứ vỡ lúc 2 giờ sáng.

“Tao nghe mày,” anh nói, “nhưng tao không nghe bài toán trên slide. Tao nghe bài toán sản phẩm. Nếu rewrite, bao lâu? Bao nhiêu feature dừng lại? Khách nào bị ảnh hưởng? Ai bảo đảm migration không đứt?”

Minh nhấn vào phần sau của slide. Lần này anh chiếu timeline sơ bộ: module hoá theo từng service nhỏ, song song hoá rồi mới tắt lõi cũ. Anh giải thích nhịp độ, lượng task, thời gian ước tính cho từng phần. Hoàng nhìn vào con số — rồi nhìn vào cách Minh nói, như người đã xây kế hoạch trong đầu từ rất lâu, không phải người vừa mới có sáng kiến sáng nay.

“Đây là đề xuất,” Minh nói. “Nhưng nếu mình không bắt đầu, code cũ sẽ ngày càng đắt.”

Hoàng buông mắt khỏi slide, nhìn về phía tường trắng. Sơ đồ lớn trên kia không còn là bức tranh tổ chức. Nó thành bằng chứng. Mũi tên của Minh chia cái anh từng viết nguyên vẹn ra thành những phần nhỏ. Có chỗ anh công nhận cần tách. Có chỗ anh không muốn tách. Có chỗ anh nghĩ nếu tách ra thì người viết đoạn đó không còn là mình nữa.

“PHP,” anh nói, “chạy ổn định 18 tháng.”

“Ổn,” Minh đáp. “Ổn ở quy mô ổn định.”

“Và dữ liệu,” anh nói tiếp. “Tao không muốn đụng database kiểu migrate ồ ạt để rồi khách ghi nợ sáng thức dậy thấy mình nợ không.”

“Nợ không?” Trâm hỏi nhỏ.

“Mất,” Khoa dịch nhanh. “Là mất.”

Minh thở ra, nhưng không nặng.

“Em không muốn xóa,” anh nói. “Em muốn bọc. Service mới nhận yêu cầu, service cũ giữ dữ liệu. Song song. Chuyển dần. Nhưng phải có người viết service mới.”

“Tức là mày,” Khoa nói.

“Tức là em,” Minh đáp.

Hoàng nhìn sang Khoa. Khoa nhìn lại, rồi nhìn sơ đồ trên tường như thể đang đọc bản đồ đường đi mà chỉ hiểu được một nửa.

“Tao nghe,” Khoa nói. “Nhưng tao không giỏi khoản này. Tao chỉ biết khách đang kêu gì.”

“Nói đi,” Phương Anh cắt vào từ phía góc bàn.

Mọi người quay lại.

“Không phải về stack,” cô nói. “Là về tiêu chí. Nếu các anh cãi nhau về PHP hay Node, tôi nghe cũng không biết ai đúng. Tôi cần một câu hỏi đơn giản hơn.”

Hoàng nhìn cô. Mấy tháng trước, Phương Anh cũng từng cắt câu hỏi kiểu này. Cô không giỏi diễn giải code, nhưng cô giỏi ép người ta nói ra thứ có thể đo.

“Cái nào,” cô nói, “giúp khách hàng ít bị gián đoạn nhất?”

Câu hỏi đó treo trong phòng.

Minh nhìn cô. Hoàng nhìn cô. Khoa thở ra, rõ hơn. Trâm ghi nhanh vào sổ tay, nét bút chạy loằng ngoằng. Tiếng máy lạnh lúc này sao mà to.

“Không phải về anh quen,” Phương Anh nói, nhìn Hoàng. “Không phải về anh giỏi,” rồi nhìn sang Minh. “Là về khách.”

Hoàng thấy câu đó chạm xuống mặt đất. Không phải đòn cao. Không phải lập luận kỹ thuật. Chỉ là tiêu chí mà ai cũng phải nghe.

Minh gật đầu trước.

“Em nói,” anh nói. “Node.js mới giúp em viết service nhỏ, test dễ hơn, deploy riêng lẻ được. Nếu một service lỗi, mình không rollback toàn bộ. Khách bị ảnh hưởng ít hơn.”

Hoàng liếc lên sơ đồ, nhìn mũi tên tách từ ô lớn sang các ô nhỏ.

“Nhưng trước khi có service mới,” anh nói, “phải đi qua cái cũ. Đi qua nghĩa là đụng.”

“Đụng,” Minh nói, “nhưng đụng có lộ trình.”

“Còn khách,” Trâm nói, giọng hơi rụt rè. “Em… em vừa mới biết tìm nợ theo biệt danh. Anh Khoa nói chị Ba Muối hay ghi sai tên. Nếu mình đổi giữa chừng mà người ta không hiểu…”

Khoa quay lại.

“Mày nói đúng,” anh nói. “Khách mình không cần kiến trúc đẹp. Họ cần phần mềm sáng mở lên vẫn chạy.”

“Vậy thì phải có thời gian chuyển tiếp,” Minh nói, quay lại nhìn Hoàng. “Không bỏ PHP ngay. Nhưng không viết thêm code mới trên cái cũ.”

Hoàng nhìn anh. Anh ghét câu đó, vì nó cũng đúng. Anh ghét hơn khi nhận ra mình đang cố tìm lý do để giữ, thay vì tìm lý do để đổi.

Phương Anh gập bảng chi phí lại, đặt sang bên cạnh.

“Tôi nghe,” cô nói. “Anh giữ PHP vì anh biết nó. Anh muốn đổi vì anh thấy tương lai. Cả hai đều có lý. Nhưng tôi chưa thấy ranh giới. Nếu deploy, ai approve? Nếu rollback, ai gọi? Khách gọi ai?”

“Gọi em,” Trâm nói, nhanh hơn cô nghĩ.

Khoa cười khẽ.

“Gọi tụi em,” anh nói.

Hoàng không cười. Anh nhìn sang Minh.

“Nếu mày muốn đổi,” anh nói, “mày viết service mới. Nhưng production hiện tại không đụng khi chưa qua tao.”

Minh nhìn lại anh, không giận, nhưng sắc.

“Được,” anh nói. “Em viết trong branch mới. Microservice tách riêng. Nhưng anh phải cho em ranh giới rõ: phần nào được phép migrate, phần nào không.”

“Phần nào ảnh hưởng khách,” Hoàng nói, “thì tao.”

“Phần nào ảnh hưởng tương lai,” Minh nói, “thì em.”

Im lặng ngắn. Không phải im lặng giận. Là im lặng của hai người đang chia một thứ mà cả hai đều nghĩ là của mình.

“Song song,” Phương Anh nói. “Tôi hiểu. Microservice mới. Monolith cũ chạy. Nhưng phải có mốc. Bao lâu?”

“Hai tháng,” Minh nói. “Em sẽ chạy module notification trước. Ít rủi ro. Ít đụng dữ liệu thanh toán.”

“Báo cáo?” Hoàng hỏi.

“Sau,” Minh đáp. “Báo cáo đụng nhiều nhất. Không vội.”

Hoàng nhìn lên sơ đồ, nhìn chữ Report nằm sát bên trong ô lớn. Anh nhớ cái đêm anh viết phần xuất báo cáo cho Khoa, ba tiếng chạy deadline, mắt rát, bàn tay đau. Anh nhớ cảm giác ấy không như viết code. Nó như cột nhà.

“Tao giữ PHP,” anh nói, “trong giai đoạn chuyển tiếp.”

“Và em viết Node,” Minh nói, “cho cái sau.”

“Không phải thay,” Phương Anh nói thêm. “Là tách.”

Minh gật. Hoàng cũng gật, nhưng gật chậm hơn.

Cuộc họp xong không có tiếng vỗ tay. Không có ai chốt bằng câu slogan. Khoa đứng dậy, lưng kêu lục cục, nói đi gọi cho chị Bảy hỏi đợt in báo cáo mới. Trâm xé tờ sổ tay, xếp lại cho ngay ngắn, nói em sẽ ghi quy trình khách gọi ai vào mẫu mới. Minh không tắt laptop ngay. Anh kéo diagram ra giữa màn hình, lưu lại, rồi nhìn Hoàng.

“Em biết,” anh nói, “PHP là máu.”

Hoàng khựng. Anh định nói không phải, rồi dừng. Đúng. Nó là máu. Nó là 18 tháng thức khuya, là bản commit đầu tiên, là đợt fix trước hội chợ, là tiếng Khoa gọi điện báo lỗi, là chị Bảy bảo con ơi phần mềm của con kỳ quá. Nó là vết sẹo đầu tiên.

“Nhưng,” Minh nói, “máu không phải lúc nào cũng đủ.”

Hoàng nhìn anh.

“Tao nghe,” anh nói.

Minh gật, rồi đeo headphone lại, không nói thêm. Tiếng nhạc nhỏ phát ra từ headphone mà Hoàng nghe được. Tiếng bass mỏng, đều. Không phải giọng nói ai. Nhưng câu nói sau của Minh vẫn treo trong phòng, nặng hơn cả tiếng bass.

“Anh giữ PHP,” Minh nói, “vì anh quen. Không phải vì nó đúng. Đó là lý do em cần quyền quyết định kỹ thuật.”

Hoàng nghe câu đó, rồi nhìn về phía tường trắng. Sơ đồ kiến trúc trên kia, với những ô vuông đỏ chia tách từ khối lớn, sao mà giống một cuộc phẫu thuật. Anh là người phẫu thuật lẫn bệnh nhân. Anh muốn mở, nhưng cũng không muốn cắt.

Phương Anh đi ngang, đặt tờ giấy chi phí lên chồng tài liệu.

“Chốt,” cô nói. “Node cho phần mới. PHP cho phần cũ. Có tiêu chí.”

Hoàng nhìn cô, gật.

“Có,” anh nói.

Nhưng trong đầu anh, câu nói của Minh vẫn lặp lại, không phải vì ghét, mà vì đúng. Anh giữ PHP vì quen. Anh giữ vì 18 tháng. Anh giữ vì biết từng dòng code, biết mùi bug, biết nhịp vá lỗi lúc khuya. Anh giữ vì nếu buông, thì cái gì thay?

Ngoài cửa sổ, đường Tô Hiến Thành bắt đầu chiều, xe máy tấp nập hơn, tiếng còi nhấn dài rồi ngắn. Tiếng đời thường lọt vào phòng, lẫn tiếng máy lạnh, lẫn tiếng ThinkPad gõ tiếp của Minh. Hoàng ngồi lại, mở terminal, nhìn vào codebase cũ. Con trỏ nhấp nháy trên dòng quen thuộc. Anh chưa gõ gì. Anh chỉ nhìn, như nhìn một người bạn cũ mà biết mình sắp phải lùi lại.

Trâm ghi xong, quay lại hỏi nhỏ Khoa: “Em hỏi thật, mình đổi thiệt hả?”

Khoa gật.

“Đổi,” anh nói. “Có gì mà không đổi.”

“Vậy… khách có biết không?”

“Không,” Khoa đáp. “Khách không cần biết stack. Khách chỉ cần biết nợ mình vẫn còn.”

Hoàng nghe câu đó, thấy nhẹ hơn một chút, nhưng chỉ một chút. Bên kia, Minh đang mở branch mới, tên nhấp nháy trên thanh git. Hoàng nhìn, rồi nhìn lại code cũ. Trong lòng anh, hai thứ đó đang kéo nhau. Một bên là cái đã sống sót. Một bên là cái sẽ lớn lên.

Cuối ngày, khi Khoa dẫn Trâm xuống Bình Thạnh gặp khách, khi Phương Anh dọn dẹp bảng chi phí, khi Minh vẫn cặm cụi với branch mới, Hoàng ở lại văn phòng một mình. Anh tắt terminal, mở sơ đồ trên tường, lấy bút đen khoanh một ô nhỏ phía dưới chữ Node.js. Rồi anh viết thêm dòng bên cạnh:

Song song.

Đơn giản vậy thôi. Nhưng khi buông bút ra, anh biết câu đó không chỉ là kỹ thuật. Nó là thỏa hiệp. Nó là cách anh giữ lại cái quen mà vẫn mở đường cho người giỏi hơn đi nhanh hơn.

Và khi đèn văn phòng bắt đầu sáng trắng trên nền tường chưa treo gì ngoài sơ đồ kiến trúc, câu nói cuối của Minh vẫn còn đọng trong đầu Hoàng, không như một nhát dao, mà như một viên đá bỏ xuống nước. Viên đá đã chìm. Nhưng sóng vẫn lan.