混沌をコードで制圧せよ:Linear Triage機能の極限活用と、バックログ崩壊を防ぐ非同期受入パイプラインの設計
開発組織のスケールに伴い、バックログが「ゴミ捨て場」と化す現象は、あらゆるプロダクトチームが直面するエントロピーの増大である。野放図に作成されるIssue、文脈の欠落したバグ報告、情緒的な機能要望。これらがバックログを汚染し、チームのベロシティを確実に蝕んでいく。
Jiraの複雑怪奇なワークフローに絶望し、私たちはLinearにたどり着いた。Linearはその圧倒的なUI/UXの速度で開発体験を革命的によくしたが、ツールがどれほど洗練されていようとも、「入り口の統制(Triage)」をアーキテクチャとして組み込まなければ、結局のところカオスは再現される。
本稿では、LinearのTriage(トリアージ)機能を単なる「未整理チケットの置き場」としてではなく、チームの認知負荷を最小化し、プロダクトバックログの純度を極限まで保つための「非同期受入パイプライン」として完全に掌握するための設計論と実装を解説する。
—
1. 思想:なぜバックログはカオス化するのか?
多くのチームが犯す致命的な設計ミスは、新規作成されたIssueを直接「Backlog」に直行させることだ。Backlogとは本来、「仕様が固まり、価値が検証され、スプリントに投入可能な状態にあるアイテムのプール」であるべきだ。ここに「動かないんだけど」「こういう機能ほしい」という生煮えのインプットが混入した瞬間、バックログは機能しなくなる。
LinearのTriage機能は、この「インプットの受入(Ingestion)」と「バックログへの昇格(Refinement)」を分離するデカップリング・レイヤーとして機能する。
[External Inputs] (GitHub, Sentry, Slack, User Voice)
│
▼
┌──────────────────────────────┐
│ Linear Triage Inbox │ ◄───[非同期トリアージの要]
│ – 担当者未定 / 状態: Triage │
└──────────────┬───────────────┘
│
├─► [Discard] (重複・スコープ外・ノイズ)
│
└─► [Accept & Refine] ──► [Backlog (Clean State)]
この分離を維持するための鉄則はただ一つ:「開発者はTriageインボックス以外を見てはならない(見る必要がない)」ということだ。
—
2. 権限と運用のアーキテクチャ:Triage Ownershipのローテーション
Triageの最大の見落としは、「誰がトリアージするのかが決まっていない」ことにある。「全員がやれる」は「誰もやらない」と同義であり、インボックスは数千件のゾンビチケットで溢れ返る。
運用プロトコル:「Triage Rotation(当番制)」
1. Triage Driver(担当者)の選任:
- 開発チームの中から、週替わり(あるいはスプリントごと)で1名の「Triage Driver」をアサインする。
- 通常の開発タスクから30%の帯域を剥がし、インボックスのゼロ維持を責務とする。
2. SLAの設定:
- すべての新規Triageアイテムに対し、24時間以内に「Accept(受入)」「Decline(拒否)」「Redirection(担当者アサイン)」のいずれかのステータスに遷移させることを義務付ける。
—
3. 自動化とカスタマイズ:API / CLIを駆使したTriageパイプラインの完全自動制御
UIポチポチによる手動トリアージは、10人以下のチームでしかスケールしない。50人、100人を超える組織では、Slack、Sentry、GitHubからの流入を自動的に前処理し、LinearのGraphQL APIまたはCLIを叩いてTriageの初期アノテーションを完全に自動化する必要がある。
以下に、Webhook経由で受け取った外部アラートを解析し、LinearのTriageへ最適なメタデータを付与して投入する、TypeScript製のサーバーレス・自動化スクリプトのコアロジックを示す。
TypeScriptによるTriage自動化・エンリッチメントスクリプト
import { LinearClient } from ‘@linear/sdk’;
/
- Linear Triage Auto-Enrichment Pipeline
- 外部の異常検知システム(Sentry等)からのアラートをキャッチし、
- 適切なプロジェクト、ラベル、推測されるPriorityを付与してTriageへ流し込む。
/
interface AlertPayload {
title: string;
description: string;
sourceUrl: string;
errorHash: string;
environment: ‘production’ | ‘staging’;
}
const linearClient = new LinearClient({ apiKey: process.env.LINEAR_API_KEY });
export async function handleIncomingAlert(alert: AlertPayload) {
try {
// 1. チーム情報の取得(ここではCore Productチームを想定)
const teams = await linearClient.teams({ filter: { key: { eq: ‘ENG’ } } });
const targetTeam = teams.nodes[0];
if (!targetTeam) throw new Error(‘Target team not found’);
// 2. 既存のTriageアイテムから重複(Error Hash)を検知
// ノイズをトリアージ段階で排除するクエリ最適化
const existingIssues = await linearClient.issues({
filter: {
team: { id: { eq: targetTeam.id } },
description: { contains: alert.errorHash },
state: { type: { eq: ‘triage’ } }
}
});
if (existingIssues.nodes.length > 0) {
// 既にTriageに同件が存在する場合はコメントを追記して終了(ノイズ抑制)
const existingIssue = existingIssues.nodes[0];
await linearClient.createComment({
issueId: existingIssue.id,
body: `🔄 [Auto-Triage] 同一エラーの発生を検知しました。環境: ${alert.environment}. [詳細](${alert.sourceUrl})`
});
return { status: ‘deduplicated’, issueId: existingIssue.id };
}
// 3. 優先度の自動算出アルゴリズム
// 本番環境のエラーであれば即座にUrgent、ステージングであればMediumとする
const priority = alert.environment === ‘production’ ? 1 : 3;
// 4. Linear TriageへIssueを作成
// stateを設定しない、あるいは明示的にtriageステータスを指定することでインボックスへ直行
const newIssuePayload = await linearClient.createIssue({
teamId: targetTeam.id,
title: `[Auto] ${alert.title}`,
description: `
概要\n${alert.description}\n\n- Source: ${alert.sourceUrl}\n- Hash: \`${alert.errorHash}\`\n- Environment: ${alert.environment}`,
priority: priority,
// 自動的に「Bug」ラベルを付与
labelIds: [process.env.LINEAR_BUG_LABEL_ID as string],
});
const issue = await newIssuePayload.issue;
console.log(`[Linear Triage] Successfully ingested issue: ${issue?.identifier}`);
return { status: ‘created’, issueId: issue?.id };
} catch (error) {
console.error(‘[Linear Triage Error] Failed to process alert:’, error);
throw error;
}
}
—
4. パフォーマンス最適化・ハック:大規模チームにおけるTriageビューの限界突破
Linearは高速だが、数千件の未整理Triageアイテムを単一のビューで抱え込むと、フロントエンドの仮想DOMレンダリング(DOMノードの過剰描画)およびバックエンドのクエリレイテンシに悪影響を及ぼし、チーム全体の認知フリクションを増大させる。
これを回避するための高度な設計ハックを共有する。
1. カスタムビュー(Custom Views)による関心の分離
デフォルトの「Triage」タブをそのまま使うな。チーム規模が大きくなったら、LinearのCustom Views機能を駆使して、フィルタリングされたサブ・インボックスを構築せよ。
- View A: 「要トリアージ(未アサイン・直近48時間以内)」
- `state: triage AND assignee: none AND createdAt > -48h`
- 👉 Triage Driverのメイン戦場。 ここを常にゼロにする。
- View B: 「ステalled(放置されたトリアージ)」
- `state: triage AND updatedAt < -7d`
- 👉 週次グロースミーティングで一括処理(Decline or Escalate)するゾンビプール。
2. キーボードショートカットドリブン・オペレーション
マウス操作は思考のコンテキストスイッチを引き起こす。Triage処理はすべてキーボードで完結させなければならない。
- `C` : Issue作成
- `E` : Triageアイテムの受入(Accept to Backlog)
- `Shift + S` : ステータス変更(Decline / Cancelへ直行)
- `A` : 担当者の即時アサイン
このショートカットの高速連打により、1分間に10件以上のトリアージを処理する「トリアージ・フロー状態」を作り出すことができる。これが、真に洗練されたエンジニアリング組織のバックログ防衛ラインである。
—
結び:混沌を飼い慣らす者だけが、高速なプロダクトをビルドできる
ツールは思想を映す鏡に過ぎない。LinearのTriage機能は、単なる機能の名前ではなく、「外部からのノイズを遮断し、内部の創造的エネルギーを純化するための防壁」である。
インボックスを常に美しく保て。流れてくるすべてのリクエストに冷徹な審判を下し、価値あるものだけをバックログの聖域へと通せ。その規律こそが、あなたのチームのベロシティを極限まで加速させる唯一にして最大のブースターとなる。