lilpacy.infoJA
Aligning Linear Issue Granularity: INVEST Principles and Vertical Slicing in Practice

Aligning Linear Issue Granularity: INVEST Principles and Vertical Slicing in Practice


TL;DR

The reason issue granularity is inconsistent and a Backlog gets chaotic is that a single issue mixes “design decisions”, “DB changes”, “UI implementation”, and “tests”. By validating each issue’s quality against the INVEST principles, splitting them with vertical slicing, and screening them with a Definition of Ready before starting, you create a rhythm of 1 issue = 1–3 days = 1 PR.

The Root Cause of Inconsistent Granularity

In the previous article, I introduced “a 3-layer structure that separates problems from tasks”. Splitting into Project + Document + Issue resolves the problem of issues like “Overcoming ADHD” creeping into the Backlog.

But even after correctly carving out tasks, granularity inconsistency among the tasks themselves remains. Looking at the Backlog of the business management tool I’m developing, here’s what I had:

  • PROJ-01 Data partitioning: handle and validate the addition of profiles
  • PROJ-02 Multi-assignee support and DB validation
  • PROJ-03 Is the data structure split this way correct? — design decision

At a glance, they all look like “tasks”. But on closer inspection, each contains multiple concerns:

  • Design decision (which DB structure to choose)
  • Migration implementation (ALTER TABLE)
  • Updating seed data
  • UI implementation
  • E2E tests

This is a different dimension from the “problem vs. task” separation; it’s a state where granularity and scope are not aligned across tasks.

INVEST Principles: A Quality Checklist for Issues

The most practical framework for aligning issue granularity is the INVEST principles. They were originally proposed as quality criteria for user stories, but apply directly to Linear issues.

PrincipleMeaningCheck
IndependentIndependentCan it be started alone, without depending on other issues?
NegotiableNegotiableIs it described by outcome rather than by implementation?
ValuableValuableOn completion, does it provide clear value to a user or developer?
EstimableEstimableIs the scope clear enough that the workload can be imagined?
SmallSmallCan it be completed in 1–3 days?
TestableTestableCan completion/incompletion be judged pass/fail?

Validating PROJ-02 from earlier against INVEST:

  • I: DB changes and UI implementation are mixed → not independent ❌
  • N: Described by the implementation method “DB validation” → not outcome-oriented ❌
  • V: There is value ✅
  • E: Scope is too broad to estimate ❌
  • S: DB + UI + tests easily exceed a week ❌
  • T: Completion criteria for “validation” are vague ❌

5 out of 6 fail. With this, even if you start, it won’t finish, and you can’t tell if it’s done.

Vertical Slicing: Don’t Split in the Wrong Direction

Once you know an issue is too big, you split it — and here, the direction of the split matters.

Horizontal slice — common but dangerous

graph LR
    A["DB change"] --> B["Backend API"] --> C["Frontend UI"] --> D["Tests"]

Slicing by layer. “First the DB”, “then the API”, “finally the UI”. It looks reasonable, but has issues:

  • Finishing only DB changes provides zero user value
  • If you discover a DB design mistake during UI work, the rework is huge
  • Each issue depends on the previous one, so parallelization is impossible
graph LR
    subgraph S1["Slice 1: extend DB"]
        A1["DB: add column"] --> B1["Seed: confirm compatibility"]
    end
    subgraph S2["Slice 2: display the new attribute"]
        A2["UI: show in list"] --> B2["E2E: confirm display"]
    end
    subgraph S3["Slice 3: multiple assignees"]
        A3["UI: add button"] --> B3["API: create"] --> C3["E2E: multi-assignees"]
    end
    S1 ~~~ S2 ~~~ S3

Slicing vertically in units of user value. Each slice can be deployed independently and provides some value on completion.

Decomposing PROJ-02 vertically:

Resulting issueTypeSize
Add an attribute column to the tableTask0.5 days
Display the new attribute on the detail pageFeature1 day
Implement add/remove UI for attributesFeature1–2 days
Allow assigning per-attribute ownersFeature1–2 days

The first Task is already done — it took 0.5 days as planned. The remaining three can each be started independently, and each delivers user value upon completion.

Distinguishing Issue Types

Another tool for aligning granularity is clearly distinguishing issue types.

TypeDefinitionSize guidelineTitle style
FeatureAdds a feature delivering user value1–3 days”Enable users to …”
TaskExecutes a clear step0.5–1 day”Add …”, “Configure …”
BugFix a defect in an existing feature0.5–2 days”Fix the issue where …”
SpikeResolve uncertainty (time-boxed)0.5–1 day”Investigate and decide …”

The crucial point is don’t mix Spike and Feature/Task. “Decide the multi-assignee DB design” (Spike) and “Add a column to the table” (Task) should be separate issues, with the Task arising from the Spike’s outcome.

In our example:

graph LR
    S["🔍 Spike: Decide<br/>multi-assignee DB design<br/>(PROJ-03)"] --> T["🔧 Task: Add column<br/>to table<br/>(part of PROJ-02)"]
    T --> F1["✨ Feature: Display<br/>new attribute"]
    T --> F2["✨ Feature: Add/remove<br/>attribute UI"]
    F1 --> F3["✨ Feature: Assign<br/>per attribute"]
    F2 --> F3

Because Spike PROJ-03 was completed and the design decision was settled, the scope of subsequent Tasks/Features became clear. Without that order, you end up with “a giant issue containing both design and implementation”.

Definition of Ready: Pre-Start Screening

After breaking down issues, the Definition of Ready (DoR) is useful as a final check before pulling them into a sprint. Going through every item every time is heavy, so narrow it to four essentials:

  1. Outcome can be stated in one sentence — “Users can …”
  2. Acceptance criteria are 3 items or fewer — clear acceptance
  3. Finishes in 1–3 days — split if it exceeds that
  4. Dependent issues are explicit — don’t start while a blocker is unresolved

If even one of these four fails, continue refinement, or split off a Spike to investigate.

The “1 issue = 1 PR” Principle

Issues with consistent granularity naturally produce a “1 issue = 1 PR” relationship. This directly improves code review efficiency. Google’s engineering practices recommend “small CLs (Change Lists)”, which presupposes “issues are at the right granularity”.

Conversely, when one PR closes multiple issues, that’s a sign that issue granularity is too fine, or that unrelated changes have crept into the PR.

Summary

Three tools for aligning issue granularity:

  1. INVEST principles — Validate each issue’s quality across six items
  2. Vertical slicing — Split by user value, not by layer
  3. Definition of Ready — Screen with four items before starting

And distinguish issue types (Feature / Task / Bug / Spike). In particular, don’t mix Spikes with implementation issues.

Granularity consistency isn’t a one-and-done setting; it has to be confirmed in regular retrospectives — “Were there issues that exceeded 3 days?”, “Were there carry-overs?”. Embedding it as a shared team understanding rather than a tool configuration ends up being the most effective.

That’s all.