Tìm kiếm đa công cụ: Mã nguồn không phải nơi cần tìm
Hầu hết quyết định của lập trình viên nằm ngoài mã nguồn. Cách xây dựng tìm kiếm đa công cụ qua Slack, Linear, GitHub và Notion.
By Ellis Keane · 2026-03-17
Mã nguồn của bạn là nơi ít hữu ích nhất để tìm kiếm lý do tại sao một quyết định được đưa ra.
Tôi biết điều đó nghe có vẻ ngược đời. Chúng ta dành nhiều năm học các flag của ripgrep, cấu hình tìm kiếm trong IDE, ghi nhớ các mẫu regex – và không có điều gì trong số đó giúp ích khi câu hỏi không phải "hàm này ở đâu?" mà là "tại sao chúng ta chọn cách tiếp cận này thay vì ba lựa chọn thay thế mà chúng ta đã thảo luận?" Câu trả lời cho câu hỏi thứ hai hầu như không bao giờ nằm trong mã nguồn. Nó nằm trong một thread Slack từ bốn tháng trước, một bình luận Linear bị chôn vùi dưới các cập nhật trạng thái, một tài liệu Notion mà ai đó bắt đầu và chưa bao giờ hoàn thành, và một đánh giá PR nơi cuộc tranh luận thực sự xảy ra trong một phản hồi của phản hồi của phản hồi.
Đó là vấn đề tìm kiếm đa công cụ cho lập trình viên – ngữ cảnh quyết định bị phân tán trên nhiều công cụ mà không có đường truy vấn thống nhất. Chúng ta có tìm kiếm hoạt động tốt trong từng công cụ – tìm kiếm của Slack khá tốt, tìm kiếm code của GitHub xuất sắc, Linear có bộ lọc cho mọi thứ – nhưng không có gì tìm kiếm xuyên suốt chúng. Các quyết định định hình kiến trúc của bạn nằm ở năm nơi khác nhau, và bạn được kỳ vọng nhớ nơi nào cần tìm.
Được rồi – đây là cách xây dựng tìm kiếm đa công cụ với những gì bạn đã có. Không cần công cụ mới (gần như vậy – tôi sẽ đề cập đến một cái ở cuối, nhưng cách này hoạt động mà không cần nó).
Giải phẫu của một quyết định rải rác
Hãy để tôi đi qua một ví dụ cụ thể. Năm ngoái, chúng tôi đang quyết định sử dụng BullMQ hay Temporal cho hàng đợi công việc. Đây là nơi quyết định đó thực sự tồn tại:
- Slack (#engineering): Ba thread riêng biệt trong hai ngày. Thread đầu tiên là một liên kết mà ai đó chia sẻ đến bài đăng blog của Temporal. Thread thứ hai là cuộc tranh luận về việc chúng tôi có cần durable execution không. Thread thứ ba (một tuần sau, kênh khác) là ai đó hỏi "khoan đã, chúng ta đã quyết định về vấn đề hàng đợi chưa?"
- Linear: Một issue có tiêu đề "Đánh giá các tùy chọn hàng đợi công việc" với sáu bình luận, bao gồm bảng so sánh mà một trong những kỹ sư của chúng tôi đã mất nửa ngày để viết.
- GitHub: Mô tả PR cho việc triển khai BullMQ ghi "như đã thảo luận" mà không có liên kết nào đến nơi đã thảo luận.
- Notion: Một bản ghi quyết định kiến trúc hoàn thành một nửa bao gồm ưu điểm của Temporal nhưng chưa bao giờ được cập nhật với lựa chọn cuối cùng.
- Google Docs: Ghi chú cuộc họp từ cuộc gọi nơi chúng tôi thực sự đưa ra quyết định, được chôn vùi trong các gạch đầu dòng giữa hai mục chương trình nghị sự không liên quan.
Năm công cụ. Một quyết định. Và nếu bạn tìm kiếm trong bất kỳ công cụ đơn lẻ nào, bạn sẽ chỉ tìm thấy một mảnh – không bao giờ có bức tranh đầy đủ. PR cho bạn biết chúng tôi đã chọn gì. Các thread Slack cho bạn biết chúng tôi đã cân nhắc điều gì. Issue Linear cho bạn biết sự đánh đổi. Tài liệu Notion cho bạn biết một nửa lý do. Ghi chú cuộc họp cho bạn biết thời điểm quyết định được hoàn tất.
Đây không phải là điều bất thường. Đây, theo một cách nào đó, là hiện trạng của cách các nhóm kỹ thuật theo dõi quyết định vào năm 2026. Chúng ta có AI tạo code và công cụ tìm kiếm lập chỉ mục toàn bộ internet, nhưng việc tìm ra tại sao nhóm của bạn chọn BullMQ thay vì Temporal đòi hỏi phải kiểm tra năm ứng dụng và hy vọng trí nhớ của ai đó không thất bại.
Điều gì làm cho tìm kiếm đa công cụ khó khăn với lập trình viên
Đây không phải là vấn đề API – mỗi công cụ chúng ta sử dụng đều có API tìm kiếm hoàn toàn tốt. Vấn đề kỳ lạ hơn thế:
Hình dạng dữ liệu khác nhau. Slack trả về tin nhắn với timestamps và ID kênh. Linear trả về issues với trạng thái và nhãn. GitHub trả về commits, PR và kết quả trùng khớp code ở các định dạng phản hồi hoàn toàn khác nhau. Việc kết hợp chúng thành một dòng thời gian gắn kết đòi hỏi chuẩn hóa mà không ai bận tâm xây dựng (vì, thành thật mà nói, đó là loại công việc không xuất hiện trong các buổi demo sprint).
Phân mảnh ngữ cảnh. Một tin nhắn Slack nói "hãy đi với lựa chọn B" không có nghĩa gì nếu không có thread định nghĩa các lựa chọn A, B và C. Nhưng tìm kiếm của Slack trả về các tin nhắn riêng lẻ, không phải cung của cuộc trò chuyện. Bạn tìm thấy kết luận mà không có lý do.
Trôi dạt theo thời gian. Quá trình ra quyết định thường kéo dài nhiều ngày hoặc nhiều tuần, với những khoảng trống khi không có gì xảy ra vì mọi người đang tập trung vào công việc khác. Tìm kiếm theo từ khóa có thể đưa ra điểm đầu và điểm cuối của cuộc trò chuyện trong khi bỏ lỡ phần giữa quan trọng, chỉ đơn giản vì các từ khác nhau đã được sử dụng ở các giai đoạn khác nhau.
Tìm kiếm đa công cụ cho lập trình viên không phải là vấn đề API – mỗi công cụ đều có endpoint tìm kiếm hoàn toàn tốt. Đó là vấn đề ngữ cảnh: các quyết định rải rác trên nhiều công cụ ở các hình dạng không tương thích, bị phân mảnh bởi các cung trò chuyện và tách biệt bởi sự trôi dạt theo thời gian. Tìm kiếm theo từ khóa chỉ tìm thấy các mảnh vỡ; chỉ có ngữ cảnh được kết nối mới tìm thấy bức tranh đầy đủ.
Xây dựng tìm kiếm đa công cụ với những gì bạn có
Đây là phần thực tế. Với ba hoặc bốn công cụ có tìm kiếm chỉ đọc, hãy dự kiến nửa ngày để MVP hoạt động – hầu hết thời gian đó dành cho thiết lập xác thực và chuẩn hóa phản hồi hơn là logic tìm kiếm thực sự.
Thiết lập quyền truy cập API
Bạn cần token cho từng công cụ:
- Slack: Token người dùng với scope
search:read (các phương thức tìm kiếm của Slack yêu cầu token người dùng, không phải bot token – tạo qua trang Slack API apps)
- Linear: Khóa API cá nhân từ Cài đặt, sau đó API
- GitHub: PAT chi tiết với quyền đọc vào các repo của bạn
- Notion: Token tích hợp nội bộ từ Cài đặt, sau đó Connections
Script truy vấn fan-out
Mẫu cơ bản đơn giản đến mức ngượng ngùng – gửi cùng một truy vấn tìm kiếm tới mọi API và thu thập kết quả:
```typescript interface SearchResult { source: 'slack' | 'linear' | 'github' | 'notion'; title: string; snippet: string; url: string; timestamp: Date; }
async function crossToolSearch(query: string): Promise<SearchResult[]> { const results = await Promise.all([ searchSlack(query), searchLinear(query), searchGitHub(query), searchNotion(query), ]);
return results .flat() .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()); } ```
Mỗi hàm search* bọc API tương ứng. Với Slack, đó là search.messages. Với Linear, đó là truy vấn GraphQL đối với các trường tìm kiếm của họ. Với GitHub, đó là REST search endpoint. Với Notion, đó là search endpoint với tham số query.
Chuẩn hóa và loại bỏ trùng lặp
Phần khó không phải là tìm kiếm – mà là làm cho kết quả hữu ích. Bạn sẽ muốn:
- Chuẩn hóa timestamps trên các công cụ (Slack sử dụng Unix epoch, Linear sử dụng chuỗi ISO, GitHub sử dụng ISO với độ lệch múi giờ)
- Nhóm các kết quả liên quan – nếu cùng một thread Slack xuất hiện ba lần vì ba tin nhắn khớp, hãy gộp chúng thành một kết quả với URL thread
- Xếp hạng theo mức độ liên quan – hầu hết API trả về điểm liên quan riêng của mình, nhưng chúng không thể so sánh trên các công cụ. Heuristic đơn giản: các từ khóa khớp chính xác trong tiêu đề xếp hạng cao hơn các khớp trong nội dung, và các kết quả gần đây hơn xếp hạng cao hơn các kết quả cũ hơn với mức độ liên quan bằng nhau
Bọc trong CLI
Tôi dùng Commander.js cho điều này (chủ yếu do thói quen, nhưng bất cứ thứ gì cũng được):
```bash $ cross-search "bullmq vs temporal"
Found 14 results across 4 tools:
[Slack] #engineering – 2025-11-14 "I've been comparing BullMQ and Temporal for the job queue..." https://myteam.slack.com/archives/C0X.../p17318...
[Linear] ENG-342 – 2025-11-15 "Evaluate job queue options – BullMQ vs Temporal" https://linear.app/myteam/issue/ENG-342
[GitHub] PR #289 – 2025-11-22 "feat: implement BullMQ job queue (as discussed)" https://github.com/myorg/myrepo/pull/289
[Notion] Architecture Decisions – 2025-11-13 "Job Queue Evaluation: Temporal vs BullMQ" https://notion.so/myteam/abc123... ```
Mười bốn kết quả, được sắp xếp theo thời gian, trên bốn công cụ. Bạn có thể thấy toàn bộ cung quyết định ở một nơi: tài liệu Notion được bắt đầu trước, sau đó cuộc thảo luận Slack diễn ra, rồi issue Linear được tạo để theo dõi, và cuối cùng PR xuất hiện một tuần sau đó.
Làm cho nó thực sự tốt
Phiên bản cơ bản ở trên hoạt động, nhưng có một số cạnh khó chịu. Đây là cách cải thiện:
Mở rộng thread cho Slack. Khi bạn tìm thấy một tin nhắn khớp, hãy lấy toàn bộ thread bằng conversations.replies. Tin nhắn khớp có thể là "ừ, hãy đi với BullMQ" – không có ích gì nếu không có 40 tin nhắn tranh luận trước đó. Hiển thị đoạn trích của thread, không chỉ tin nhắn khớp.
Bình luận đánh giá PR. API tìm kiếm của GitHub không đưa ra các bình luận đánh giá khi bạn tìm kiếm PR – bạn sẽ cần một lệnh gọi riêng tới endpoint đánh giá pull request để lấy chúng. Đó là nơi cuộc thảo luận kỹ thuật thực sự diễn ra.
Backlinks. Khi bạn tìm thấy một issue Linear, hãy kiểm tra xem có tin nhắn Slack nào chứa URL của issue đó không. Tìm kiếm của Slack hỗ trợ bộ lọc has:link kết hợp với từ khóa. Điều này đưa ra cuộc thảo luận không chính thức đã xảy ra xung quanh việc theo dõi chính thức.
Bộ nhớ đệm. Nếu nhóm của bạn tạo nhiều nội dung (và nhóm nào không?), bạn sẽ nhanh chóng vượt quá giới hạn tốc độ. Cache kết quả cục bộ với TTL 30 phút – hầu hết các quyết định lịch sử không thay đổi nhanh đến vậy.
Khi tìm kiếm văn bản thất bại
Đây là nơi tôi sẽ thành thật về những hạn chế. Tìm kiếm từ khóa trên các công cụ đưa bạn đi khá xa một cách đáng ngạc nhiên, và sau đó nó va vào một bức tường.
Bức tường là thế này: các quyết định phát triển. Thread Slack về "hàng đợi công việc" có thể không bao giờ đề cập đến "BullMQ" theo tên – thay vào đó, ai đó chia sẻ một liên kết, người khác nói "tôi thích tùy chọn được hỗ trợ bởi Redis," và người thứ ba nói "đồng ý, hãy đi với cái đó." Tìm kiếm "BullMQ" của bạn bỏ lỡ toàn bộ thread vì từ đó chưa bao giờ được sử dụng. Những người trong thread biết "tùy chọn được hỗ trợ bởi Redis" có nghĩa là gì. Tìm kiếm của bạn thì không.
Đây về cơ bản là vấn đề đồ thị, không phải vấn đề văn bản. Những gì bạn thực sự muốn là: "hiển thị cho tôi mọi thứ được kết nối với quyết định dẫn đến PR #289." Điều đó có nghĩa là hiểu rằng PR tham chiếu đến một issue Linear, issue này được tạo ra sau một cuộc thảo luận Slack, cuộc thảo luận đó bắt đầu vì ai đó đọc một tài liệu Notion. Các kết nối là ngầm định – con người tạo ra chúng bằng cách sao chép URL và nói "như đã thảo luận" – và tìm kiếm từ khóa không thể tái tạo lại chúng.
Bạn có thể giải quyết một phần vấn đề này bằng cách theo dõi các liên kết. Phân tích các URL từ tin nhắn Slack, mô tả PR và bình luận Linear. Xây dựng một danh sách kề đơn giản: thread Slack này liên kết đến issue Linear này, được tham chiếu trong PR này. Sau đó khi ai đó tìm kiếm, bạn có thể mở rộng kết quả để bao gồm các mục được liên kết ngay cả khi chúng không khớp với từ khóa.
Cách tiếp cận danh sách kề này về cơ bản là một đồ thị tri thức sơ khai – và đây là nơi giá trị thực sự của tìm kiếm đa công cụ cho lập trình viên nằm ở đó. Không phải trong việc tìm kiếm các tin nhắn riêng lẻ, mà là theo dõi sợi chỉ của một quyết định qua mọi công cụ mà nó đã chạm đến. Đây ít là "tìm kiếm" hơn và nhiều là quản lý tri thức lập trình viên hơn – hiểu cách thông tin chi tiết chảy giữa các công cụ của bạn để bạn có thể tái tạo lại ngữ cảnh khi cần.
Vấn đề bảo trì (và lối tắt)
Cách tiếp cận script hoạt động xuất sắc trong khoảng ba tháng, sau đó ai đó thay đổi workspace Slack, hoặc Linear cập nhật schema GraphQL, hoặc bạn thêm một công cụ mới và không ai nhớ cập nhật script tìm kiếm. Tôi đã xây dựng chính xác điều này hai lần và từ bỏ hai lần (điều này có lẽ nói nhiều hơn về cam kết bảo trì của tôi hơn là về chính cách tiếp cận).
Nếu bạn muốn tìm kiếm đa công cụ cho lập trình viên luôn cập nhật mà không cần giám sát, đó là điều mà các công cụ như Sugarbug được xây dựng để làm – nó duy trì đồ thị tri thức tự động và giữ các kết nối sống động khi các công cụ của bạn thay đổi. Nhưng phiên bản DIY ở trên thực sự hữu ích nếu bạn sẵn sàng bảo trì nó.
Ngừng tìm kiếm trong năm công cụ riêng biệt. Sugarbug xây dựng đồ thị tri thức để bạn có thể tìm thấy bất kỳ quyết định, cuộc thảo luận hoặc commit nào ở một nơi.
Q: Làm thế nào để tìm kiếm trên nhiều công cụ lập trình cùng lúc? A: Bạn có thể xây dựng tìm kiếm đa công cụ nhẹ bằng cách kết hợp API của từng công cụ – search.messages của Slack, issueSearch của Linear và endpoint tìm kiếm code của GitHub – thành một script duy nhất phân phối truy vấn và gộp kết quả theo thời gian. Các mẫu code ở trên sẽ giúp bạn bắt đầu trong nửa buổi chiều. Thách thức chính không phải là bản thân việc tìm kiếm mà là chuẩn hóa các định dạng phản hồi khác nhau thành một dòng thời gian gắn kết.
Q: Sugarbug có cung cấp tìm kiếm đa công cụ cho lập trình viên không? A: Có. Sugarbug thu thập tín hiệu từ Linear, GitHub, Slack, Figma, Notion và các công cụ khác vào đồ thị tri thức, giúp bạn tìm kiếm một quyết định hoặc cuộc thảo luận và tìm thấy mọi thread, issue và commit liên quan ở một nơi. Nó xử lý việc chuẩn hóa, loại bỏ trùng lặp và theo dõi liên kết tự động – những phần làm cho cách tiếp cận DIY trở nên dễ vỡ theo thời gian.
Q: Tại sao tôi không thể tìm thấy quyết định kiến trúc trong mã nguồn? A: Vì hầu hết quyết định xảy ra trong các thread Slack, bình luận Linear, tài liệu Notion và đánh giá PR – không phải trong chính mã nguồn. Mã nguồn ghi lại kết quả của quyết định (hàm tồn tại, thư viện được chọn), nhưng lý do, sự đánh đổi và các lựa chọn thay thế được thảo luận thì rải rác trên các công cụ giao tiếp của bạn. git blame cho bạn biết ai đã thay đổi một dòng và khi nào, nhưng không phải tại sao họ chọn cách tiếp cận đó thay vì các lựa chọn thay thế.
Q: Sugarbug có thể thay thế tài liệu ADR để theo dõi quyết định không? A: Sugarbug không thay thế ADR, nhưng nó nắm bắt các quyết định không bao giờ được ghi vào ADR. Hầu hết các nhóm viết ADR cho khoảng 10% lựa chọn kiến trúc của họ – phần còn lại tan biến trong các thread Slack và bình luận PR. Sugarbug đưa những quyết định đó lên bề mặt bằng cách kết nối các cuộc trò chuyện với những thay đổi code mà chúng tạo ra, vì vậy bạn có được việc theo dõi quyết định cho 90% còn lại mà không cần thay đổi quy trình của bất kỳ ai.