Sáu tháng xây dựng Bookverse, một mình
Có một phiên bản lãng mạn của việc viết phần mềm một mình, nơi bạn có một chiếc bàn gọn gàng, một ly espresso, và bạn ra mắt thứ gì đó mà mọi người yêu thích trước giờ ăn trưa. Phiên bản tôi thực sự đã sống suốt sáu tháng qua thì giống “viết đi viết lại cùng một file cấu hình Nginx bốn lần vì trường hợp ngoại lệ thứ bảy vừa cắn bạn.”
Đây là một sự suy ngẫm — không phải danh sách những gì đã ra mắt, không phải hướng dẫn. Chỉ là vài ghi chú sau sáu tháng.
Vì sao tôi bắt đầu
Tôi đã dùng các ứng dụng học ngôn ngữ lúc này lúc kia suốt nhiều năm và nhận ra một điều cụ thể: tôi có thể hoàn thành chuỗi 30 ngày trên ứng dụng game hóa nổi tiếng mà vẫn không đọc nổi một đoạn văn bản bản ngữ. Vòng phản hồi rất chặt, sự game hóa rất mượt, nhưng đơn vị tiến bộ lại là một câu, đôi khi là một từ. Còn đọc ngôn ngữ — thực sự đọc chúng — diễn ra ở cấp độ những trang sách.
Tôi muốn một ứng dụng đối xử với sách giáo khoa như một cuốn sách giáo khoa. Mở chương một. Đọc nó. Nghe nó. Nói lại nó. Học những gì còn đọng lại. Ngày mai, chương hai.
Hình hài của sản phẩm đã rõ ràng từ ngày đầu tiên. Cái bẫy là “hình hài rõ ràng từ ngày đầu tiên” chỉ chịu trách nhiệm cho khoảng 5% việc xây dựng phần mềm. 95% còn lại là đoạn giữa chẳng hào nhoáng chút nào.
Đoạn giữa chẳng hào nhoáng
Một danh sách chưa đầy đủ những việc tôi đã làm trong quý này mà không có trong bất kỳ ghi chú phát hành nào:
- Đổi tên cả một cây thư mục monorepo từ
app_v54_01thànhbookverse(và đổi lại lần nữa khi tôi muốn có dấu gạch dưới trong tên đơn vị systemd). - Viết bốn phiên bản cấu hình Terraform cho các vhost Nginx trước khi
phát hiện ra rằng một trigger
null_resourcecần phải bao gồm hash của template đã render, chứ không chỉ các biến đầu vào. - Mất một tuần truy tìm lý do vì sao một giá trị biến môi trường
EXPO_PUBLIC_*lại resolve thành chuỗi rỗng trong bundle web nhưng chạy ngon trên iOS. (preset-expocủa Babel bỏ qua việc inline chonode_modules. Dùng hàm factory, chứ không phải biến môi trường, trong các package đã publish.) - Refactor 17 nơi gọi một helper URL của API vì tôi đã tập trung hóa nó sai ngay từ lần đầu.
Không điều nào trong số này sẽ xuất hiện trong một bài đăng quảng cáo về ứng dụng. Tất cả chúng đều là công việc thực sự.
Điều mà không ai cảnh báo bạn về việc phát triển một mình là chẳng có ai gánh phần nửa nhàm chán. Bạn không thể nói “đội nền tảng lo việc deploy” bởi vì bạn chính là đội nền tảng. Bạn đội mọi chiếc mũ một cách vụng về cho đến khi đã đội đủ lâu để đội cho ra trò.
Cái hố sâu của nhận diện giọng nói
Giai đoạn dạy cho tôi nhiều bài học nhất trong sáu tháng qua là làm cho phần luyện nói chạy được trên điện thoại ở Trung Quốc.
Kế hoạch: chạm vào một dòng, nghe một người bản ngữ đọc nó, chạm lại, tự
ghi âm mình, xem bạn nói sát đến đâu. Nhận diện giọng nói di động tiêu
chuẩn — expo-speech-recognition trên iOS, dịch vụ hệ thống trên
Android, xong.
Thực tế: một bộ phận lớn đối tượng mục tiêu dùng điện thoại Lenovo
Motorola với biến thể hệ điều hành phiên bản Trung Quốc (lớp phủ
gmsconfig.china), vốn lược bỏ hoàn toàn Google Mobile Services. Không
có speech-to-text hệ thống. Ứng dụng chạy hoàn hảo trong emulator. Trên
một chiếc Moto XT2507 ở Bắc Kinh, nó crash âm thầm.
Việc khắc phục mất khoảng ba tuần:
- Xây một mẫu adapter để ứng dụng có thể tráo đổi các backend giọng nói theo nền tảng — nhận diện hệ thống ở nơi có sẵn, phiên âm trên đám mây làm phương án dự phòng.
- Thêm một backend đám mây kiểu Whisper (
qwen3-asr-flashcủa Alibaba qua DashScope, vì các thiết bị phiên bản Trung Quốc có thể truy cập nó mà không cần VPN). - Tinh chỉnh phát hiện hoạt động giọng nói để bản ghi tự dừng khi bạn nói xong. (Ngưỡng -25 dBFS, cửa sổ im lặng 600ms, được làm mượt qua năm mẫu — mọi tổ hợp khác đều hoặc cắt ngang giữa từ hoặc chẳng bao giờ dừng.)
- Chuyển từ upload
FormDatacủa React Native sanguploadAsynccủaexpo-file-system, vìFormDatacủa RN hay trục trặc với các blob âm thanh trên chính những thiết bị đó.
Một nửa trong bốn gạch đầu dòng đó là nhiều code hơn lượng tôi viết trong một tuần điển hình. Không cái nào là “một tính năng.” Tất cả đều cần thiết để tính năng tồn tại cho những người cần đến nó.
Bài học — lặp lại xấp xỉ mỗi hai tuần — là phần khó hiếm khi là phần bạn nghĩ sẽ khó. Tôi dự trù một ngày cho nhận diện giọng nói. Nó mất hai mươi.
Kỷ luật của việc hoàn thành
Cám dỗ khi xây dựng một mình là đuổi theo cái mới lấp lánh. Một tính năng mới thì thú vị. Lần tinh chỉnh thứ 47 cho một luồng đã có thì không. Thế là bạn tích lũy các tính năng, chẳng cái nào thực sự xong, và sản phẩm có cảm giác như một nghĩa địa của những công trình dang dở.
Kỷ luật mà tôi cứ phải học lại: hoàn thành một thứ cho tử tế trước khi bắt đầu thứ tiếp theo. Tiếng Quan Thoại trước. Làm cho tiếng Quan Thoại thật tốt. Rồi tiếng Hàn. Rồi tiếng Anh. Nền tảng được xây để cung cấp các khóa học có cấu trúc — nhưng khóa học đầu tiên phải là khóa học chủ lực, khóa học mà người học thực sự có thể hoàn thành.
Một khóa tiếng Hàn được lên kế hoạch nhưng mới xây 5% chẳng giúp ích cho ai. Một khóa tiếng Quan Thoại hoàn chỉnh mà ai đó có thể đọc từ đầu đến cuối mới là một sản phẩm thực sự.
Với các tính năng cũng vậy. Luyện nói nằm trong lộ trình suốt ba tháng trước khi ra mắt. Nó ra mắt muộn, nhưng nó ra mắt đúng cách — xử lý trường hợp phiên bản Trung Quốc là yếu tố chịu lực để nó dùng được, chứ không phải một chi tiết đánh bóng để hoãn lại.
Điều tôi sẽ nói với chính mình hồi tháng Mười Một
Ba điều, nếu tôi có thể gửi một tấm bưu thiếp về cho phiên bản của tôi đã bắt đầu chuyện này.
Đừng đổi tên nữa. Một cái tên là thứ chẳng sao khi đặt sai vào ngày đầu. Đổi tên lại tốn kém hơn giá trị của nó trong phần lớn trường hợp. (Tôi đã làm điều này đúng bốn lần rồi.)
Mua sách có cấu trúc. Tôi mất hàng tuần nhảy qua nhảy lại giữa các danh sách từ vựng trên các diễn đàn. Các tiêu chuẩn HSK 3.0 là một tài liệu đã được công bố thực sự. Mua sách có cấu trúc và làm theo chúng thì nhanh hơn việc đảo ngược kỹ thuật để đoán xem chúng bao gồm những gì.
Khán giả rất kiên nhẫn. Tôi cứ nghĩ mình phải ra mắt thật nhanh nếu không mọi người sẽ mất hứng thú. Sự thật thì ngược lại: người học ngôn ngữ theo định nghĩa vốn đã kiên nhẫn — họ vốn đã cam kết với cả một năm luyện tập. Họ không cần một bản demo vào ngày thứ ba. Họ cần một thứ chạy được vào ngày thứ ba trăm.
Tiếp theo là gì
Tiếng Quan Thoại cứ lớn dần — Band 1 và Band 2 đã hoạt động, Band 3 đang được kiểm duyệt ngay lúc này. Việc biên soạn nội dung khóa tiếng Hàn sẽ khởi động sau khi Band 3 tiếng Quan Thoại ra mắt. Mảng nền tảng giờ êm ả hơn so với sáu tháng trước, nghĩa là nhiều thời gian hơn được dồn vào nội dung học tập thực sự — đó mới là nơi nó nên đến.
Nếu bạn đang dùng Bookverse: cảm ơn bạn. Nếu chưa: hãy mở một chương lúc nào đó. Chương đầu tiên là miễn phí.