Steven
Steven8 phút đọc

Trang login CHÍNH LÀ bản demo

GeekBye v1.7.5 thêm một tấm screenshot sản phẩm vào trang login rồi xóa nó ngay trong ngày — thay vào đó dựng lại bằng component thật. Kèm theo: người dùng nhanh hơn cả OCR, và 25 commit style trong một ngày thực sự trông như thế nào.

Kỹ thuật
Thiết kế
UX
Bản phát hành GeekBye
Trang login CHÍNH LÀ bản demo

GeekBye v1.7.5 là một bản phát hành một tuần mang hai nhân cách: 37 commit, trong đó 28 là thiết kế lại trang login — và 25 trong số đó là những chỉnh sửa li ti kiểu style(login), tất cả đáp xuống trong đúng một ngày. Đây cũng là bản phát hành sửa một trong những race đáng học nhất của codebase. Cả hai câu chuyện đều đáng kể, và chúng gặp nhau ở cùng một ý tưởng: trang login là thứ đầu tiên một người dùng chưa đăng nhập nhìn thấy, nên tốt nhất nó phải sản phẩm, chứ không phải một bức ảnh của sản phẩm.

Một tấm screenshot, sống được chừng năm tiếng

Cuộc thiết kế lại khởi đầu theo lối thông thường. Sắp lại thành hai cột, đặt phần đăng nhập bên trái, và cho xem sản phẩm bên phải — dưới dạng ảnh. Các commit cuối buổi sáng làm đúng như thế: lúc 11:57, một tấm screenshot preview thật đáp vào repo, một file PNG 114 KB, và được cập nhật một lần sáu phút sau đó.

Đến 17:04 nó đã biến mất. Commit xoay trục thay tấm ảnh tĩnh bằng 344 dòng component thật — một panel LoginDemo lắp ráp từ tám mảnh nhỏ tái hiện đúng UI overlay thật: cái pill điều hướng ghi âm với các thanh EQ nhấp nháy và nút dừng, panel chat với hai tab Chat/Transcript, một câu trả lời của trợ lý được render sẵn (giải thích useEffect của React — hợp cảnh làm sao), các quick action "Tell me more / Simplify / Show example", hàng live-prompt, và ô nhập Assist ⌘⏎.

Hãy nói cho chính xác về chữ "demo", vì rất dễ nói quá: các nút có hover state thật — glow, shimmer, transition — nhưng không có gì được nối dây vào sự kiện click, và ô nhập là read-only. Nó không phải sandbox. Thứ nó là, là vốn từ vựng UI thật của sản phẩm được render sống: cùng một asset logo, cùng một kiểu viền gradient và backdrop-blur, cùng một lệnh import productName mà hệ thống white-label dùng — nên bản demo tự đổi thương hiệu cho từng sản phẩm được build từ codebase này. Một tấm screenshot chẳng làm nổi điều nào trong số đó. Screenshot cũ ngay từ ngày bạn chụp, nhòe trên màn hình không hợp, và vĩnh viễn mang thương hiệu của đúng cái sản phẩm bạn tình cờ chụp. Component sắc nét ở mọi DPI, luôn luôn mới, và đúng với mọi thương hiệu — vì chúng không phải bức ảnh của design system, chúng design system.

Nhân tiện, tấm PNG bị xóa vẫn còn nằm trong repo tại release tag — mồ côi, không gì tham chiếu đến nữa. Codebase nào cũng mang theo vài dấu tích của phương án đã thua cuộc.

25 commit style trong một ngày trông như thế nào

Nhật ký commit của riêng ngày hôm đó là cuốn sổ phác thảo của một designer, được lưu giữ trung thực đến hiếm thấy. Tỷ lệ cột đi từ 40/60, rồi 45/55. Một nhãn "Works with" (Hoạt động cùng) phía trên các logo nền tảng được thêm vào giữa trưa, dời chỗ, rồi gỡ bỏ — nó sống được chừng nửa ngày. Bản thân hàng logo nền tảng (Google Meet, Teams, Zoom, Slack, Webex), thêm vào lúc 10:59 sáng, bị xóa sạch lúc 22:08 đêm đó. Còn phần footer thì trải qua một trường thiên bốn cách tiếp cận mới căn thẳng được: một container bọc duy nhất, rồi bỏ các class căn giữa, rồi căn giữa bằng flexbox, rồi cuối cùng chỉ đơn giản nhích nó sát xuống đáy hơn.

Đọc chuyện đó thành quần quanh vô ích thì dễ. Chúng tôi đọc nó như hình dạng thực của công việc thiết kế: bạn hội tụ bằng cách render, nhìn, và chỉnh — và làm điều đó trong 25 commit nhỏ thay vì một cục squash "redesign login page" nghĩa là chính cuộc tìm kiếm được ghi lại. Khi ai đó hỏi "chẳng phải mình từng thử một hàng logo à?", câu trả lời nằm trong lịch sử, kèm timestamp.

Người dùng nhanh hơn cả OCR

Câu chuyện kỹ thuật của bản này xảy ra năm ngày trước đó, trong một chuỗi sửa ba commit. Từ v1.5.12, bấm Cmd+H sẽ đưa screenshot vào hàng đợi với phản hồi tức thời: thumbnail xuất hiện trong hàng đợi ngay lập tức, còn phần trích xuất văn bản — Apple Vision OCR chạy cục bộ, cỡ một đến hai giây — chạy nền. Sự kiện vào hàng đợi được gửi đi đúng nghĩa đen với ocrText: '' và một dòng comment hứa hẹn sẽ điền vào sau.

Đó là một tối ưu tốt, và nó đẻ ra một race. Một người dùng nhanh tay bấm Cmd+H và gửi câu hỏi ngay lập tức. Trường text của screenshot vẫn còn rỗng. Request bay đi mà không mang chút nội dung màn hình nào, và model trả lời — đúng sự thật, một cách phát bực — "I cannot see images" (Tôi không nhìn thấy hình ảnh). Con đường ngây thơ này không thất bại bằng một lỗi; nó thất bại bằng một câu trả lời đúng cho một câu hỏi sai — cách thất bại gây bối rối nhất mà phần mềm có thể có.

Bản sửa chặn đường submit bằng chính phần việc async mà tối ưu kia đã hoãn lại: nếu bất kỳ screenshot nào trong hàng đợi vẫn còn text OCR rỗng, request tấp vào lề và UI hiện chỉ báo "Reading screen..." (Đang đọc màn hình); một useEffect kích hoạt đúng khoảnh khắc văn bản đáp xuống và gửi request kèm toàn bộ nội dung đã trích xuất. Có hai chi tiết đặc thù React trong cái diff đáng để học lỏm: hàng đợi screenshot được phản chiếu vào một ref được sync ngay trong lúc render, vì chuỗi closure của event handler đang bắt phải state cũ; và cái request đang tấp lề được gửi trực tiếp thay vì đi qua hook hàng đợi request chung, cũng vì đúng lý do stale closure đó.

Và có một khúc quanh trung thực được ghi lại ngay trong commit message: những dòng log truy vết thêm vào để săn cái race này đã hé lộ một bug thứ hai ở backend — khâu ghép prompt đang làm rơi toàn bộ text của screenshot ở một nhánh code. Một triệu chứng, hai bug, tìm ra nhờ gắn đo đạc lên cả chuỗi và quan sát xem văn bản biến mất ở đâu. Chuỗi này khép lại bằng một quyết định sản phẩm, chín phút sau bản sửa race: Cmd+H đưa screenshot vào hàng đợi để phân tích theo lô, còn Cmd+Enter luôn chụp mới màn hình hiện tại — hai workflow rành mạch thay vì một workflow mập mờ. (Assist của Cmd+Enter thực sự làm gì thì là một bài riêng: trợ giúp AI tức thời cho bất cứ thứ gì bạn đang nhìn.)

Một đoạn vĩ thanh nhỏ từ cùng tuần đó, dành cho độc giả của chương white-label: chuỗi User-Agent Product/version (platform) nhận một bản sửa cho chế độ dev, vì app.getVersion() trong Electron chưa đóng gói trả về phiên bản của Electron, chứ không phải của sản phẩm. Các chuỗi định danh, như mọi khi, luôn rò rỉ trong đường ống.

Ba điều bản phát hành này dạy chúng tôi

  1. Hãy render sản phẩm, đừng chụp ảnh nó. Một bản demo trang login dựng từ component thật tự đổi thương hiệu, sống sót qua mọi mật độ màn hình, và không thể lỗi thời. Phương án screenshot được thử và bị xóa trong vòng một ngày làm việc — thí nghiệm rẻ, phán quyết rõ.
  2. Mỗi tối ưu async cần một cái chốt chặn tại điểm sử dụng. "Phản hồi tức thời với text OCR rỗng" là quyết định UX đúng, nhưng đường submit phải học cách chờ thứ mà tối ưu kia đã hoãn. Nếu bạn hoãn một phần việc, hãy tìm mọi nơi tiêu thụ kết quả của nó và dạy chúng phân biệt giữa "rỗng" và "chưa sẵn sàng".
  3. Gắn đo đạc lên cả chuỗi, đừng chỉ lên nghi phạm. Các dòng log truy vết bám theo text của screenshot từ đầu đến cuối — từ shortcut handler qua IPC đến API client — và đó là lý do một cuộc điều tra khép lại hai bug, một trong số đó nằm ở phía bên kia của mạng.

Về chương trước trong câu chuyện v1, xem những cuộc họp bạn thực sự tìm lại được (v1.7.3); và cho toàn bộ vòng cung, xem giải phẫu việc xuất xưởng phần mềm đến độ hoàn hảo.

Bài Viết Liên Quan

Thiết kế lại Dashboard xoay quanh một biểu đồ sóng duy nhất
Steven
Steven10 phút đọc

Thiết kế lại Dashboard xoay quanh một biểu đồ sóng duy nhất

GeekBye v1.8.2 biến dashboard từ một chiếc điều khiển từ xa cho việc ghi âm thành một khung phân tích chỉ-đọc — một dải thống kê và một biểu đồ sóng 7 ngày. Cả hai thành phần đặc trưng đều là bản nháp thứ hai, được ship trong vòng 20 phút sau bản nháp đầu, trong cùng một buổi chiều.

Kỹ thuật
Thiết kế
Dashboard
Những cuộc họp bạn thực sự tìm lại được: Bản phát hành Timeline
Steven
Steven8 phút đọc

Những cuộc họp bạn thực sự tìm lại được: Bản phát hành Timeline

GeekBye v1.7.3 thay dropdown cuộc họp bằng một timeline thực thụ — ngày giờ kiểu con người, tìm kiếm, một breadcrumb cho biết bạn đang ở cuộc họp nào. Bên dưới: một race condition do auto-select, một screenshot ra đời trước cả cuộc họp của chính nó, và năm bản sửa cho Windows trong vỏn vẹn 28 phút.

Kỹ thuật
UX
Desktop
Ship Ba Mươi Ngôn Ngữ Mà Không Có Lưới An Toàn
Steven
Steven10 phút đọc

Ship Ba Mươi Ngôn Ngữ Mà Không Có Lưới An Toàn

GeekBye v1.8.3 đấu nối react-i18next và dịch toàn bộ ứng dụng sang 30 ngôn ngữ. Phần thư viện chỉ là việc thường ngày. Phần thú vị nằm ở những gì còn thiếu: không có kiểm tra tính đồng nhất của key và không có công cụ trích xuất chuỗi — nên tiếng Anh hardcode lọt lưới, một lỗi chính tả tiếng Đan Mạch bị ship, và cái changelog thì không thống nhất nổi rằng ứng dụng nói 28, 29, hay 30 ngôn ngữ.

Kỹ thuật
i18n
Desktop