TechLead
Lesson 9 of 30
5 min read
Project Management

Requirements Gathering and Analysis

Master requirements elicitation techniques, user stories, acceptance criteria, MoSCoW prioritization, and requirements traceability

Why Requirements Matter

Poor requirements are the #1 cause of IT project failure. Studies consistently show that 40-60% of defects originate from requirements errors, and fixing a requirement error in production costs 100x more than catching it during analysis. Effective requirements gathering is not about creating perfect documents — it is about building shared understanding between stakeholders and the delivery team.

Elicitation Techniques

Technique Best For Effort Limitations
InterviewsDeep understanding from key stakeholdersMediumTime-consuming, may miss group dynamics
WorkshopsBuilding consensus across groupsHighDominant voices can overshadow others
SurveysGathering input from many usersLowShallow data, low response rates
ObservationUnderstanding actual workflowsHighHawthorne effect (people change behavior when watched)
Document AnalysisLegacy system replacementMediumDocuments may be outdated
PrototypingValidating assumptions visuallyMedium-HighRisk of "building the prototype"

Functional vs. Non-Functional Requirements

Understanding the Difference

Functional requirements describe what the system should DO. Non-functional requirements (NFRs) describe HOW the system should perform.

  • Functional: "The system shall allow users to reset their password via email"
  • Non-Functional (Performance): "The password reset email must be sent within 30 seconds"
  • Non-Functional (Security): "Reset tokens must expire after 1 hour"
  • Non-Functional (Availability): "The auth service must maintain 99.9% uptime"
  • Non-Functional (Scalability): "The system must handle 10,000 concurrent password resets"

User Stories and Acceptance Criteria

// User Story and Requirements Data Model
interface UserStory {
  id: string;
  title: string;
  asA: string;          // Role
  iWant: string;        // Feature
  soThat: string;       // Benefit
  acceptanceCriteria: AcceptanceCriterion[];
  priority: 'must-have' | 'should-have' | 'could-have' | 'wont-have';
  storyPoints: number;
  epic: string;
  dependencies: string[];
}

interface AcceptanceCriterion {
  id: string;
  given: string;     // Context
  when: string;      // Action
  then: string;      // Expected result
}

interface Requirement {
  id: string;
  type: 'functional' | 'non-functional';
  category: string;
  description: string;
  priority: 'must-have' | 'should-have' | 'could-have' | 'wont-have';
  source: string;          // Who requested it
  rationale: string;       // Why it is needed
  acceptanceCriteria: string[];
  traceability: {
    userStories: string[];
    testCases: string[];
    designDocs: string[];
  };
}

// Example user stories
const userStories: UserStory[] = [
  {
    id: 'US-101',
    title: 'User Login with Email',
    asA: 'registered user',
    iWant: 'to log in with my email and password',
    soThat: 'I can access my personalized dashboard and order history',
    acceptanceCriteria: [
      {
        id: 'AC-101-1',
        given: 'I am on the login page',
        when: 'I enter a valid email and correct password and click Login',
        then: 'I am redirected to my dashboard within 2 seconds'
      },
      {
        id: 'AC-101-2',
        given: 'I am on the login page',
        when: 'I enter an invalid email format',
        then: 'I see an inline error message "Please enter a valid email address"'
      },
      {
        id: 'AC-101-3',
        given: 'I am on the login page',
        when: 'I enter a valid email but wrong password',
        then: 'I see a generic error "Invalid email or password" (not revealing which is wrong)'
      },
      {
        id: 'AC-101-4',
        given: 'I have failed login 5 times in 15 minutes',
        when: 'I attempt to login again',
        then: 'My account is temporarily locked and I see a message to try again in 15 minutes'
      }
    ],
    priority: 'must-have',
    storyPoints: 5,
    epic: 'Authentication',
    dependencies: []
  },
  {
    id: 'US-102',
    title: 'Social Login with Google',
    asA: 'new or returning user',
    iWant: 'to sign in using my Google account',
    soThat: 'I can access the app without creating a new password',
    acceptanceCriteria: [
      {
        id: 'AC-102-1',
        given: 'I am on the login page',
        when: 'I click "Sign in with Google"',
        then: 'I am redirected to Google OAuth consent screen'
      },
      {
        id: 'AC-102-2',
        given: 'I have authorized the app on Google',
        when: 'Google redirects me back',
        then: 'My account is created (if new) or I am logged in (if existing), and I see my dashboard'
      },
      {
        id: 'AC-102-3',
        given: 'I deny Google authorization',
        when: 'I am redirected back to the app',
        then: 'I see the login page with a message "Google sign-in was cancelled"'
      }
    ],
    priority: 'should-have',
    storyPoints: 8,
    epic: 'Authentication',
    dependencies: ['US-101']
  }
];

// MoSCoW Prioritization
interface MoSCoWAnalysis {
  mustHave: Requirement[];    // Non-negotiable for launch
  shouldHave: Requirement[];  // Important but not critical
  couldHave: Requirement[];   // Nice to have if time allows
  wontHave: Requirement[];    // Explicitly deferred to future
}

// INVEST criteria check for user stories
function validateUserStory(story: UserStory): {
  isValid: boolean;
  issues: string[];
} {
  const issues: string[] = [];

  // Independent
  if (story.dependencies.length > 2) {
    issues.push('Too many dependencies - story may not be Independent');
  }

  // Negotiable
  if (story.acceptanceCriteria.length > 8) {
    issues.push('Too many acceptance criteria - may be over-specified (not Negotiable)');
  }

  // Valuable
  if (!story.soThat || story.soThat.length < 10) {
    issues.push('Weak "so that" clause - Value is unclear');
  }

  // Estimable
  if (story.storyPoints === 0) {
    issues.push('Not estimated - story is not Estimable');
  }

  // Small
  if (story.storyPoints > 13) {
    issues.push('Story is too large (>13 points) - not Small enough, consider splitting');
  }

  // Testable
  if (story.acceptanceCriteria.length === 0) {
    issues.push('No acceptance criteria - story is not Testable');
  }

  return { isValid: issues.length === 0, issues };
}

Requirements Traceability Matrix

A Requirements Traceability Matrix (RTM) links requirements to their source, design, code, and test cases. This ensures every requirement is implemented and tested.

Req ID Description User Story Design Doc Test Case Status
REQ-001Email loginUS-101DD-Auth-01TC-101, TC-102Implemented
REQ-002Google OAuthUS-102DD-Auth-02TC-103, TC-104In Progress
REQ-003Account lockoutUS-101 (AC-4)DD-Auth-03TC-105Not Started

Requirements Gathering Best Practices

  • Talk to Users, Not Just Stakeholders: Stakeholders think they know what users need, but direct user research reveals the truth
  • Write "So That" Clauses: The benefit statement forces you to validate that the feature has real value
  • Use Given/When/Then: Structured acceptance criteria are unambiguous and directly translatable to tests
  • Prioritize Ruthlessly: Not everything is a must-have. Use MoSCoW to force hard trade-off conversations early
  • Keep Stories Small: If a story is bigger than 13 points, split it. Large stories hide complexity

Continue Learning