【テクニカル・上級編】複数チーム・大組織向けLinear運用:Cross-team ProjectsとParent-Child Issuesで部門間連携をスムーズにする設計手法 – プロジェクト・ナレッジ管理活用バイブル

Linear組織設計の極意:Cross-team ProjectsとParent-Child Issuesがもたらす巨大開発生産性の劇的最適化

数名のスタートアップから十数チームのスケールへ移行した瞬間、多くのプロダクト組織は「情報のサイロ化」という名の重力に押しつぶされる。各チームが独立して動くことでベロシティは一時的に向上したように見えるが、プロダクト全体の整合性が失われ、部門間連携のコストは爆発的に増大する。

Jiraの複雑怪奇なワークフローとカスタムフィールドの沼に沈んだ組織がLinearへ移行する際、彼らが最初に直面する罠は「単にツールが軽くなったからといって、組織の構造的欠陥が自動的に治るわけではない」という現実だ。

本稿では、数名から数十名、さらに複数チーム(Product, Platform, SRE, Designなど)が混在する大組織において、Linearの真骨頂である Cross-team Projects と Parent-Child Issues を極限まで使い倒し、組織のベロシティを数倍に跳ね上げるための設計手法を、私の苦い失敗談を交えて徹底的に解説する。

—

1. 失敗の構造:なぜ複数チームのLinear運用は破綻するのか?

かつて私が参戦したある大規模リファクタリングプロジェクトでのことだ。マイクロサービス群とモノリスの境界を再定義するため、5つの開発チームがアサインされた。

私たちは初期設定のまま、チームごとに独立したTeam(例: `CORE`, `PLAT`, `FE`)を切った。そして、巨大な新機能を一つの「Project」にぶち込み、各チームがそれぞれのバックログからチケットを掘り起こして実装を進めた。

結果はどうなったか?

  • ステータスのブラックボックス化: Projectの進捗バーは常に「45%完了」のまま2ヶ月間微動だにしなかった。各チームの定義する「完了(Done)」の解釈が異なっていたからだ。
  • 依存関係のデッドロック: PlatformチームのAPI改修が終わっていないのに、Frontendチームがモックで先行実装を進め、結合時に致命的なスキーマの不整合が発覚した。これを検知したのはリリース前日のインテグレーションテスト時である。
  • 通知のノイズ汚死: Slack連携があらゆるチームの全チケットの移動を流し込み、エンジニアは重要なアラートを見逃すようになった。

原因は明白である。「ツールのフラットな構造」に「組織の縦割り構造」をそのままマッピングしたことだ。Linearは本来、境界を越えたコラボレーションを加速させるために設計されている。それを旧来の縦割り組織の防壁として使ってしまったのだ。

この地獄から抜け出すために我々が構築した、Cross-team ProjectsとParent-Child Issuesを軸とする設計パターンを公開しよう。

—

2. Cross-team Projectsのアーキテクチャ設計

Linearの Projects は、単なるタグ付け機能ではない。複数のTeamにまたがるゴールを同期させるための「仮想的な司令塔」である。

権限とスコープの設計思想

大組織において、全てのプロジェクトを全社公開にするとノイズが多すぎて機能しない。かといってプライベートにすると情報のサイロ化が再発する。

  • Team-owned Projects (非推奨): 特定の1チームしか触らないプロジェクト。これは通常のTeam内バックログで十分であり、Projectを切る必要すらない場合が多い。
  • Cross-team Projects (推奨): 2つ以上のTeamが成果物の納品に責任を持つ場合。例えば「決済基盤のv2移行」であれば、`Backend`, `Frontend`, `Security`, `SRE` の4チームがコントリビューターとして参画する。

状態管理の同期とMilestoneの活用

複数チームが絡むプロジェクトでは、チームごとのベロシティの差により進捗が歪む。これを防ぐためには、Project Milestones を厳密に設定し、各チームのイシューをマイルストーンに紐付ける必要がある。

[Project: 決済基盤 v2 移行]
├── Milestone 1: APIスキーマの凍結とセキュリティレビュー
│ ├── [Backend] GraphQLスキーマの策定 (Team: CORE)
│ └── [Security] 脆弱性アセスメントの実施 (Team: SEC)
└── Milestone 2: デュアルリード運用とトラフィック移行
├── [Frontend] 新APIクライアントの組み込み (Team: FE)
└── [SRE] Canaryリリースのルーティング設定 (Team: SRE)

この階層構造により、「どのチームがどのマイルストーンのブロッカーになっているか」がLinearのロードビュー上で一目瞭然となる。

—

3. Parent-Child Issuesによる巨大機能の分解パターン

複数チームで巨大な機能を分担する際、最もやってはいけないのが「各チームがバラバラにチケットを切ること」である。共通の親を持たない子チケットの群れは、ただの混沌を生み出す。

3階層イシュー分解デザインパターン

我々は、複雑なクロスチーム案件を扱う際、以下の厳格な階層構造(3レイヤー)を義務付けている。

1. Initiative / Project (Level 0): 経営・プロダクト視点のゴール(例: 「Q3 グローバル決済の刷新」)
2. Parent Issue (Level 1 – Cross-team Epic): 各機能ドメインのエピック。これは特定のチームに所有権を持たせるが、説明欄に他チームへの依存関係を明記する。
3. Child Issues (Level 2 – Atomic Tasks): 実際に手を動かす開発者のタスク。別チームのメンバーであっても、このParent Issueの下に子イシューとしてぶら下げることが可能。

実践:Parent-Child間でのステータス伝播の罠

Linearの仕様上、親イシューのステータスは自動で子イシューの完了率によって計算されるわけではない(手動、またはカスタム自動化が必要)。ここで重要になるのが、「子イシューの完了が何を意味するか」の定義の統一である。

複数チーム間での連携では、子イシューをアサインする際に以下のルールを徹底する。

  • Contract-First: APIやデータモデルの変更を伴う子イシューは、必ず「インターフェースの合意(PRやOpenAPIの定義)」を子イシューの最初のSub-taskまたはコメントとして残し、他チームのレビュー承認をブロック条件にする。

—

4. 自動化とスケーリング:Linear API & CLIによる独自インフラ連携

GUIのポチポチ作業によるオペレーションミスをゼロにするため、大組織ではLinearのAPI(GraphQL)とWebhookを駆使した独自のガバナンスレイヤーを構築すべきである。

ここでは、複数チームにまたがる親イシューに対し、子イシューの進捗状況を監視し、依存関係にあるチームのSlackチャンネルへ自動通知、あるいはステータスを同期するNode.jsスクリプトの核心部分を解説する。

依存関係のブロッカー検知・自動同期スクリプト

以下のスクリプトは、Linear APIを叩いて、特定のエピック(Parent Issue)に紐づく子イシューのステータスを走査し、他チームの未完了タスクがブロッカーになっているものを検出するガバナンスデーモンの一部である。

import { LinearClient } from ‘@linear/sdk’;

// 環境変数からAPIキーを取得
const linearClient = new LinearClient({ apiKey: process.env.LINEAR_API_KEY });

async function auditCrossTeamBlockers(parentIssueId: string) {
try {
// 親イシューと子イシュー(Children)を取得
const parentIssue = await linearClient.issue(parentIssueId);
const children = await parentIssue.children();

console.log(`Auditing Parent Issue: ${parentIssue.title} (${parentIssue.identifier})`);

for (const child of nodes(children)) {
const team = await child.team;
const assignee = await child.assignee;
const state = await child.state;

// 「In Progress」だが、他チームの依存関係がある場合のカスタムロジック
if (state.name === ‘In Progress’) {
const relations = await child.inverseRelations();

for (const relation of nodes(relations)) {
const relatedIssue = await relation.issue;
const relatedState = await relatedIssue.state;

// 依存先のタスクが完了していないのに着手している場合の警告ログ
if (relatedState.type !== ‘completed’) {
console.warn(
`[WARNING] Cross-team bottleneck detected! ` +
`Task ${child.identifier} (${team.name}) is blocked by ` +
`${relatedIssue.identifier} which is currently ‘${relatedState.name}’.`
);
// ここでSlack Webhookを叩く、あるいはLinearにコメントを自動投稿する処理を記述
}
}
}
}
} catch (error) {
console.error(‘Failed to audit linear issues:’, error);
}
}

// ヘルパー関数(Linear SDKのページネーション用)
function nodes(connection: { nodes: T[] } | { pageInfo: any; nodes: T[] }): T[] {
return connection.nodes;
}

// 実行例
auditCrossTeamBlockers(‘uuid-of-the-parent-issue’);

パフォーマンスとキャッシュの最適化ハック

組織が拡大し、数千のイシューが飛び交うようになると、LinearクライアントからのN+1クエリ問題やレートリミット(Rate Limiting)に直面する。

  • GraphQL Fragmentの最適化: 必要なフィールド(`id`, `state`, `team`など)のみを絞って取得し、無駄なペイロードの肥大化を防ぐ。
  • Webhookの活用: ポーリング(定期実行)ではなく、LinearのWebhookサーバーを立ち上げ、`Issue.update`や`IssueRelation.create`のイベントをトリガーにリアルタイムで処理をイベント駆動型(Event-Driven)で処理するアーキテクチャへ移行せよ。

—

5. 伝説的アーキテクトからの提言:ツールに組織を合わせるな

Linearは、現代のソフトウェアエンジニアリングにおいて最も洗練されたツールの一つである。しかし、それはあくまで「触媒」に過ぎない。

複数チーム・大組織におけるLinear運用の成否を分けるのは、ツール自体の機能ではなく、「境界の定義(Boundary Definition)」にある。

1. Teamの境界は「デプロイメントの独立性」や「コードベースの責任範囲」に一致させよ。
2. Projectsの境界は「プロダクトの価値提供の単位(Value Stream)」に一致させよ。
3. Parent-Childの境界は「契約と依存関係の可視化」のために使え。

組織のコミュニケーションの欠陥を、ツールの複雑さで隠蔽しようとしてはならない。Linearの圧倒的なスピード感を組織の隅々まで行き渡らせるためには、シンプルで強固な設計思想という「骨格」が必要不可欠なのだ。

さあ、今すぐあなたのLinearワークスペースを見直し、無秩序に乱立したプロジェクトとサイロ化したチームの壁をぶち壊せ。ベロシティの限界突破は、そこからしか始まらない。

タイトルとURLをコピーしました