Software Development Lifecycle (SDLC)
Learning Objectives
By the end of this reading, you will be able to:
- Understand the phases of the Software Development Lifecycle
- Compare different SDLC methodologies (Waterfall, Agile, Scrum, Kanban)
- Apply Agile principles in software development
- Conduct requirements gathering and analysis
- Plan and estimate software projects effectively
- Choose appropriate methodologies for different project types
Introduction
The Software Development Lifecycle (SDLC) is a systematic process for planning, creating, testing, and deploying software systems. Understanding SDLC methodologies is crucial for delivering high-quality software on time and within budget.
Why SDLC Matters
- Structure: Provides a framework for development activities
- Quality: Ensures systematic testing and validation
- Predictability: Makes timelines and costs more predictable
- Communication: Establishes clear expectations among stakeholders
- Risk Management: Identifies and mitigates risks early
SDLC Phases
All SDLC methodologies include these core phases, though their implementation varies:
1. Planning
Defining project scope, objectives, and feasibility.
class ProjectPlan:
"""Represents a software project plan."""
def __init__(self, name, stakeholders):
self.name = name
self.stakeholders = stakeholders
self.objectives = []
self.constraints = {}
self.risks = []
def add_objective(self, objective, success_criteria):
"""Add a project objective with measurable criteria."""
self.objectives.append({
'description': objective,
'success_criteria': success_criteria,
'status': 'pending'
})
def add_constraint(self, type_, description):
"""
Add project constraints.
Args:
type_: 'budget', 'time', 'resources', 'technical'
description: Details of the constraint
"""
if type_ not in self.constraints:
self.constraints[type_] = []
self.constraints[type_].append(description)
def assess_risk(self, risk, probability, impact, mitigation):
"""
Document project risks.
Args:
risk (str): Description of the risk
probability (str): 'low', 'medium', 'high'
impact (str): 'low', 'medium', 'high'
mitigation (str): Mitigation strategy
"""
self.risks.append({
'risk': risk,
'probability': probability,
'impact': impact,
'mitigation': mitigation,
'priority': self._calculate_priority(probability, impact)
})
def _calculate_priority(self, probability, impact):
"""Calculate risk priority based on probability and impact."""
levels = {'low': 1, 'medium': 2, 'high': 3}
score = levels[probability] * levels[impact]
if score >= 6:
return 'critical'
elif score >= 4:
return 'high'
else:
return 'medium'
# Example usage
project = ProjectPlan("E-commerce Platform", ["CEO", "CTO", "Product Manager"])
project.add_objective(
"Support 10,000 concurrent users",
"Load testing shows <2s response time at 10k users"
)
project.add_constraint("budget", "$500,000 total development cost")
project.add_constraint("time", "6 months to MVP launch")
project.assess_risk(
"Third-party payment API downtime",
probability="medium",
impact="high",
mitigation="Implement fallback payment provider"
)
2. Requirements Gathering
Collecting and documenting what the software should do.
from enum import Enum
from typing import List, Optional
class RequirementType(Enum):
FUNCTIONAL = "functional"
NON_FUNCTIONAL = "non_functional"
TECHNICAL = "technical"
BUSINESS = "business"
class Priority(Enum):
MUST_HAVE = "must_have"
SHOULD_HAVE = "should_have"
COULD_HAVE = "could_have"
WONT_HAVE = "wont_have" # MoSCoW prioritization
class Requirement:
"""Represents a single requirement."""
def __init__(self, id_, description, type_, priority):
self.id = id_
self.description = description
self.type = type_
self.priority = priority
self.acceptance_criteria = []
self.dependencies = []
self.status = "draft"
def add_acceptance_criterion(self, criterion):
"""Add criterion that must be met for requirement to be satisfied."""
self.acceptance_criteria.append(criterion)
def add_dependency(self, requirement_id):
"""Add dependency on another requirement."""
self.dependencies.append(requirement_id)
class RequirementsDocument:
"""Manages all project requirements."""
def __init__(self, project_name):
self.project_name = project_name
self.requirements = {}
def add_requirement(self, requirement):
"""Add a requirement to the document."""
self.requirements[requirement.id] = requirement
def get_by_priority(self, priority):
"""Get all requirements with specified priority."""
return [req for req in self.requirements.values()
if req.priority == priority]
def get_dependencies(self, requirement_id):
"""Get all requirements that depend on the given requirement."""
dependents = []
for req in self.requirements.values():
if requirement_id in req.dependencies:
dependents.append(req)
return dependents
# Example: E-commerce requirements
reqs = RequirementsDocument("E-commerce Platform")
# Functional requirement
user_login = Requirement(
"FR-001",
"Users must be able to log in with email and password",
RequirementType.FUNCTIONAL,
Priority.MUST_HAVE
)
user_login.add_acceptance_criterion(
"Email validation follows RFC 5322 standard"
)
user_login.add_acceptance_criterion(
"Passwords must be at least 8 characters"
)
user_login.add_acceptance_criterion(
"Failed login attempts are rate-limited"
)
reqs.add_requirement(user_login)
# Non-functional requirement
performance = Requirement(
"NFR-001",
"System must handle 10,000 concurrent users",
RequirementType.NON_FUNCTIONAL,
Priority.MUST_HAVE
)
performance.add_acceptance_criterion(
"Page load time < 2 seconds at 95th percentile"
)
performance.add_acceptance_criterion(
"API response time < 500ms at 99th percentile"
)
reqs.add_requirement(performance)
# Business requirement
revenue = Requirement(
"BR-001",
"Platform must support multiple payment methods",
RequirementType.BUSINESS,
Priority.MUST_HAVE
)
revenue.add_acceptance_criterion("Support credit/debit cards")
revenue.add_acceptance_criterion("Support PayPal")
revenue.add_acceptance_criterion("Support Apple Pay and Google Pay")
reqs.add_requirement(revenue)
3. Design
Creating the architecture and detailed design of the system.
class SystemDesign:
"""Represents high-level system architecture."""
def __init__(self, system_name):
self.system_name = system_name
self.components = {}
self.interfaces = []
self.data_models = {}
def add_component(self, name, responsibility, technology):
"""
Add a system component.
Args:
name: Component name (e.g., "API Server")
responsibility: What the component does
technology: Tech stack (e.g., "Python/FastAPI")
"""
self.components[name] = {
'responsibility': responsibility,
'technology': technology,
'dependencies': []
}
def add_interface(self, from_component, to_component, protocol):
"""Define how components communicate."""
self.interfaces.append({
'from': from_component,
'to': to_component,
'protocol': protocol
})
# Example: Microservices architecture
design = SystemDesign("E-commerce Platform")
design.add_component(
"API Gateway",
"Route requests, authentication, rate limiting",
"Kong/Nginx"
)
design.add_component(
"User Service",
"User authentication, profiles, preferences",
"Python/FastAPI + PostgreSQL"
)
design.add_component(
"Product Service",
"Product catalog, search, inventory",
"Python/FastAPI + Elasticsearch"
)
design.add_component(
"Order Service",
"Shopping cart, checkout, order management",
"Python/FastAPI + PostgreSQL"
)
design.add_component(
"Payment Service",
"Payment processing, transaction management",
"Python/FastAPI + Stripe API"
)
design.add_interface("Client", "API Gateway", "HTTPS/REST")
design.add_interface("API Gateway", "User Service", "gRPC")
design.add_interface("API Gateway", "Product Service", "gRPC")
design.add_interface("Order Service", "Payment Service", "gRPC")
4. Implementation
Writing the actual code.
# This is where development happens - covered in other modules
# Focus here is on organizing the implementation phase
class Sprint:
"""Represents a development sprint (Agile concept)."""
def __init__(self, number, duration_days=14):
self.number = number
self.duration_days = duration_days
self.stories = []
self.capacity_hours = 0
def add_story(self, story_id, description, points):
"""Add a user story to the sprint."""
self.stories.append({
'id': story_id,
'description': description,
'points': points,
'status': 'todo',
'tasks': []
})
def set_team_capacity(self, team_size, hours_per_person):
"""Set available development hours for the sprint."""
self.capacity_hours = team_size * hours_per_person
def get_velocity(self):
"""Calculate completed story points."""
return sum(s['points'] for s in self.stories
if s['status'] == 'done')
# Example sprint planning
sprint_1 = Sprint(number=1, duration_days=14)
sprint_1.set_team_capacity(team_size=5, hours_per_person=60)
sprint_1.add_story(
"US-101",
"As a user, I can create an account",
points=5
)
sprint_1.add_story(
"US-102",
"As a user, I can log in",
points=3
)
sprint_1.add_story(
"US-103",
"As a user, I can reset my password",
points=5
)
5. Testing
Verifying the software works correctly.
class TestPlan:
"""Manages testing strategy and execution."""
def __init__(self, project_name):
self.project_name = project_name
self.test_cases = []
self.coverage_target = 80 # Percentage
def add_test_case(self, id_, description, type_, priority):
"""
Add a test case.
Args:
type_: 'unit', 'integration', 'system', 'acceptance'
"""
self.test_cases.append({
'id': id_,
'description': description,
'type': type_,
'priority': priority,
'status': 'pending',
'steps': [],
'expected_result': None
})
def get_test_summary(self):
"""Generate testing progress summary."""
total = len(self.test_cases)
passed = sum(1 for tc in self.test_cases if tc['status'] == 'passed')
failed = sum(1 for tc in self.test_cases if tc['status'] == 'failed')
return {
'total': total,
'passed': passed,
'failed': failed,
'pending': total - passed - failed,
'pass_rate': (passed / total * 100) if total > 0 else 0
}
# Example test planning
test_plan = TestPlan("E-commerce Platform")
test_plan.add_test_case(
"TC-001",
"Verify user can register with valid email",
type_='integration',
priority='high'
)
test_plan.add_test_case(
"TC-002",
"Verify user cannot register with invalid email",
type_='integration',
priority='high'
)
6. Deployment
Releasing the software to production.
class DeploymentPipeline:
"""Represents a CI/CD deployment pipeline."""
def __init__(self, app_name):
self.app_name = app_name
self.stages = []
def add_stage(self, name, steps):
"""Add a deployment stage."""
self.stages.append({
'name': name,
'steps': steps,
'status': 'pending'
})
# Example deployment pipeline
pipeline = DeploymentPipeline("ecommerce-api")
pipeline.add_stage("Build", [
"Install dependencies",
"Run linting",
"Compile code",
"Create Docker image"
])
pipeline.add_stage("Test", [
"Run unit tests",
"Run integration tests",
"Check code coverage (>80%)",
"Run security scan"
])
pipeline.add_stage("Deploy to Staging", [
"Deploy to staging environment",
"Run smoke tests",
"Run acceptance tests"
])
pipeline.add_stage("Deploy to Production", [
"Create backup",
"Deploy with blue-green strategy",
"Run health checks",
"Monitor error rates"
])
7. Maintenance
Ongoing support and updates.
class MaintenanceTracker:
"""Track maintenance activities."""
def __init__(self):
self.incidents = []
self.enhancements = []
def log_incident(self, severity, description):
"""Log a production incident."""
self.incidents.append({
'severity': severity, # 'critical', 'high', 'medium', 'low'
'description': description,
'timestamp': None, # Would use datetime.now()
'status': 'open',
'resolution': None
})
def plan_enhancement(self, description, effort):
"""Plan a system enhancement."""
self.enhancements.append({
'description': description,
'effort': effort, # Story points or hours
'status': 'planned'
})
Waterfall Methodology
Sequential approach where each phase must complete before the next begins.
Waterfall Phases
"""
Waterfall Flow:
Requirements → Design → Implementation → Testing → Deployment → Maintenance
↓ ↓ ↓ ↓ ↓ ↓
Complete Complete Complete Complete Complete Ongoing
Characteristics:
- Linear and sequential
- Extensive documentation
- Clear milestones
- Changes are costly
- Works well for stable requirements
"""
class WaterfallProject:
"""Manages a waterfall-style project."""
PHASES = [
'requirements',
'design',
'implementation',
'testing',
'deployment',
'maintenance'
]
def __init__(self, name):
self.name = name
self.current_phase = 0
self.phase_artifacts = {phase: [] for phase in self.PHASES}
def complete_phase(self, deliverables):
"""
Complete current phase and move to next.
Args:
deliverables: List of artifacts/documents produced
"""
current = self.PHASES[self.current_phase]
self.phase_artifacts[current] = deliverables
# Phase gate: verify deliverables
if not self._verify_deliverables(current, deliverables):
raise ValueError(f"Phase {current} deliverables incomplete")
self.current_phase += 1
return self.PHASES[self.current_phase] if self.current_phase < len(self.PHASES) else 'Complete'
def _verify_deliverables(self, phase, deliverables):
"""Verify phase deliverables are complete."""
required = {
'requirements': ['Requirements Document', 'Use Cases'],
'design': ['Architecture Document', 'Database Schema', 'UI Mockups'],
'implementation': ['Source Code', 'Code Documentation'],
'testing': ['Test Cases', 'Test Results', 'Bug Reports'],
'deployment': ['Deployment Guide', 'User Manual'],
'maintenance': ['Maintenance Plan', 'SLA Document']
}
return all(req in deliverables for req in required.get(phase, []))
# Example waterfall project
waterfall = WaterfallProject("Banking System")
next_phase = waterfall.complete_phase([
'Requirements Document',
'Use Cases'
])
print(f"Moving to: {next_phase}") # Moving to: design
Waterfall Pros and Cons
"""
PROS:
✓ Simple to understand and manage
✓ Clear milestones and deliverables
✓ Extensive documentation
✓ Works well for projects with stable requirements
✓ Easy to estimate costs and timelines
CONS:
✗ Inflexible to changing requirements
✗ Late testing discovers issues late
✗ No working software until late in project
✗ High risk for complex projects
✗ Difficult to incorporate customer feedback
BEST FOR:
- Small, well-defined projects
- Projects with stable requirements
- Regulatory/compliance-heavy projects
- Projects with fixed budgets and timelines
"""
Agile Methodology
Iterative approach emphasizing flexibility, collaboration, and customer feedback.
Agile Manifesto Principles
"""
Agile Values:
1. Individuals and interactions > Processes and tools
2. Working software > Comprehensive documentation
3. Customer collaboration > Contract negotiation
4. Responding to change > Following a plan
12 Principles:
1. Customer satisfaction through early and continuous delivery
2. Welcome changing requirements
3. Deliver working software frequently (weeks not months)
4. Business people and developers work together daily
5. Build projects around motivated individuals
6. Face-to-face conversation is best
7. Working software is primary measure of progress
8. Sustainable development pace
9. Continuous attention to technical excellence
10. Simplicity - maximize work not done
11. Self-organizing teams
12. Regular reflection and adjustment
"""
Agile Implementation
class AgileProject:
"""Manages an Agile project with iterations."""
def __init__(self, name, iteration_length_days=14):
self.name = name
self.iteration_length = iteration_length_days
self.iterations = []
self.backlog = []
self.current_iteration = None
def add_to_backlog(self, story):
"""Add user story to product backlog."""
self.backlog.append(story)
# Sort by priority
self.backlog.sort(key=lambda s: s.get('priority', 999))
def start_iteration(self, iteration_number):
"""Start a new iteration."""
self.current_iteration = {
'number': iteration_number,
'stories': [],
'committed_points': 0,
'completed_points': 0,
'status': 'active'
}
def commit_story(self, story_id):
"""Commit a story from backlog to current iteration."""
story = next((s for s in self.backlog if s['id'] == story_id), None)
if story and self.current_iteration:
self.backlog.remove(story)
self.current_iteration['stories'].append(story)
self.current_iteration['committed_points'] += story['points']
def complete_story(self, story_id):
"""Mark story as complete."""
if self.current_iteration:
story = next((s for s in self.current_iteration['stories']
if s['id'] == story_id), None)
if story:
story['status'] = 'done'
self.current_iteration['completed_points'] += story['points']
def end_iteration(self):
"""End current iteration and calculate velocity."""
if self.current_iteration:
self.current_iteration['status'] = 'complete'
self.current_iteration['velocity'] = \
self.current_iteration['completed_points']
# Incomplete stories go back to backlog
incomplete = [s for s in self.current_iteration['stories']
if s.get('status') != 'done']
self.backlog.extend(incomplete)
self.iterations.append(self.current_iteration)
velocity = self.current_iteration['velocity']
self.current_iteration = None
return velocity
def get_average_velocity(self):
"""Calculate team's average velocity over recent iterations."""
if not self.iterations:
return 0
recent = self.iterations[-3:] # Last 3 iterations
return sum(i['velocity'] for i in recent) / len(recent)
# Example Agile project
agile = AgileProject("Mobile App", iteration_length_days=14)
# Build backlog
agile.add_to_backlog({
'id': 'US-001',
'description': 'As a user, I can create an account',
'points': 5,
'priority': 1
})
agile.add_to_backlog({
'id': 'US-002',
'description': 'As a user, I can log in',
'points': 3,
'priority': 1
})
agile.add_to_backlog({
'id': 'US-003',
'description': 'As a user, I can view my profile',
'points': 2,
'priority': 2
})
# Iteration 1
agile.start_iteration(1)
agile.commit_story('US-001')
agile.commit_story('US-002')
agile.complete_story('US-001')
agile.complete_story('US-002')
velocity = agile.end_iteration()
print(f"Iteration 1 velocity: {velocity}") # 8 points
Scrum Framework
Specific Agile framework with defined roles, events, and artifacts.
Scrum Roles
class ScrumTeam:
"""Represents a Scrum team with defined roles."""
def __init__(self, name):
self.name = name
self.product_owner = None
self.scrum_master = None
self.developers = []
def set_product_owner(self, person):
"""
Product Owner responsibilities:
- Maximize product value
- Manage product backlog
- Ensure backlog is visible and understood
- Prioritize work
"""
self.product_owner = person
def set_scrum_master(self, person):
"""
Scrum Master responsibilities:
- Coach team on Scrum
- Facilitate events
- Remove impediments
- Shield team from distractions
"""
self.scrum_master = person
def add_developer(self, person):
"""
Developer responsibilities:
- Create plan for Sprint (Sprint Backlog)
- Adapt plan each day toward Sprint Goal
- Hold each other accountable as professionals
"""
self.developers.append(person)
class ScrumEvents:
"""Scrum ceremonies/events."""
@staticmethod
def sprint_planning(backlog, capacity):
"""
Sprint Planning event.
Questions answered:
1. What can be delivered in this Sprint?
2. How will the work get done?
Duration: Max 8 hours for 1-month Sprint
"""
sprint_goal = "Define what we want to achieve"
sprint_backlog = []
points = 0
# Select items from backlog that fit in capacity
for item in backlog:
if points + item['points'] <= capacity:
sprint_backlog.append(item)
points += item['points']
return {
'goal': sprint_goal,
'backlog': sprint_backlog,
'committed_points': points
}
@staticmethod
def daily_standup():
"""
Daily Scrum event.
Each team member answers:
1. What did I do yesterday?
2. What will I do today?
3. Are there any impediments?
Duration: 15 minutes max
"""
return {
'duration_minutes': 15,
'questions': [
'What did you complete yesterday?',
'What will you work on today?',
'Any blockers or impediments?'
]
}
@staticmethod
def sprint_review(increment, stakeholders):
"""
Sprint Review event.
Purpose: Inspect increment and adapt backlog
Attendees: Scrum Team + stakeholders
Duration: Max 4 hours for 1-month Sprint
"""
feedback = []
# Demonstrate working software
# Gather feedback
# Update backlog based on feedback
return feedback
@staticmethod
def sprint_retrospective(team):
"""
Sprint Retrospective event.
Purpose: Inspect how last Sprint went
Questions:
1. What went well?
2. What could be improved?
3. What will we commit to improve?
Duration: Max 3 hours for 1-month Sprint
"""
return {
'went_well': [],
'to_improve': [],
'action_items': []
}
# Example Scrum implementation
team = ScrumTeam("Platform Team")
team.set_product_owner("Alice")
team.set_scrum_master("Bob")
team.add_developer("Charlie")
team.add_developer("Diana")
team.add_developer("Eve")
# Sprint planning
backlog = [
{'id': 'US-001', 'points': 5, 'description': 'User login'},
{'id': 'US-002', 'points': 3, 'description': 'Password reset'},
{'id': 'US-003', 'points': 8, 'description': 'User dashboard'},
]
sprint = ScrumEvents.sprint_planning(backlog, capacity=13)
print(f"Sprint committed points: {sprint['committed_points']}") # 8
Scrum Artifacts
class ProductBacklog:
"""Ordered list of what is needed to improve the product."""
def __init__(self):
self.items = []
def add_item(self, id_, description, value, effort):
"""Add item to backlog."""
self.items.append({
'id': id_,
'description': description,
'business_value': value,
'effort': effort,
'priority': value / effort, # Simple prioritization
'status': 'backlog'
})
# Re-sort by priority
self.items.sort(key=lambda x: x['priority'], reverse=True)
class SprintBacklog:
"""Work selected for the Sprint plus plan for delivering it."""
def __init__(self, sprint_goal):
self.sprint_goal = sprint_goal
self.items = []
self.tasks = []
def add_item(self, item):
"""Add item from product backlog to sprint."""
self.items.append(item)
def break_into_tasks(self, item_id, tasks):
"""Break user story into specific tasks."""
for task in tasks:
self.tasks.append({
'item_id': item_id,
'description': task,
'status': 'todo',
'assigned_to': None
})
class Increment:
"""Sum of all Product Backlog items completed in Sprint + previous Sprints."""
def __init__(self):
self.completed_items = []
self.version = "0.0.0"
def add_completed_item(self, item):
"""Add completed item to increment."""
if self._meets_definition_of_done(item):
self.completed_items.append(item)
def _meets_definition_of_done(self, item):
"""
Check if item meets Definition of Done.
Example DoD:
- Code written and reviewed
- Unit tests written and passing
- Integration tests passing
- Documentation updated
- Accepted by Product Owner
"""
return True # Simplified
Kanban Methodology
Flow-based approach focusing on continuous delivery and limiting work in progress.
Kanban Board
class KanbanBoard:
"""Visual workflow management system."""
def __init__(self, name):
self.name = name
self.columns = {}
self.wip_limits = {}
self.items = []
def add_column(self, name, wip_limit=None):
"""
Add a column to the board.
Common columns: Backlog → To Do → In Progress → Review → Done
"""
self.columns[name] = []
if wip_limit:
self.wip_limits[name] = wip_limit
def add_item(self, item):
"""Add work item to the board (starts in first column)."""
first_column = list(self.columns.keys())[0]
item['column'] = first_column
self.items.append(item)
self.columns[first_column].append(item['id'])
def move_item(self, item_id, to_column):
"""Move item to different column."""
item = next((i for i in self.items if i['id'] == item_id), None)
if not item:
return False
# Check WIP limit
if to_column in self.wip_limits:
current_wip = len(self.columns[to_column])
if current_wip >= self.wip_limits[to_column]:
raise ValueError(f"WIP limit reached for {to_column}")
# Move item
from_column = item['column']
self.columns[from_column].remove(item_id)
self.columns[to_column].append(item_id)
item['column'] = to_column
def get_metrics(self):
"""Calculate Kanban metrics."""
return {
'lead_time': self._calculate_lead_time(),
'cycle_time': self._calculate_cycle_time(),
'throughput': self._calculate_throughput(),
'wip': sum(len(items) for col, items in self.columns.items()
if col not in ['Backlog', 'Done'])
}
def _calculate_lead_time(self):
"""Time from request to delivery."""
# Simplified - would calculate from timestamps
return 0
def _calculate_cycle_time(self):
"""Time from start to finish."""
# Simplified - would calculate from timestamps
return 0
def _calculate_throughput(self):
"""Items completed per time period."""
done_column = 'Done'
return len(self.columns.get(done_column, []))
# Example Kanban board
board = KanbanBoard("Development Board")
board.add_column("Backlog")
board.add_column("To Do")
board.add_column("In Progress", wip_limit=3)
board.add_column("Code Review", wip_limit=2)
board.add_column("Testing", wip_limit=2)
board.add_column("Done")
board.add_item({
'id': 'TASK-001',
'title': 'Implement user authentication',
'type': 'feature',
'priority': 'high'
})
board.move_item('TASK-001', 'To Do')
board.move_item('TASK-001', 'In Progress')
Kanban Principles
"""
KANBAN PRINCIPLES:
1. Visualize Workflow
- Make work visible
- See bottlenecks
- Track progress
2. Limit Work in Progress (WIP)
- Focus on finishing over starting
- Reduce context switching
- Improve flow
3. Manage Flow
- Measure lead time and cycle time
- Optimize process
- Predict delivery
4. Make Process Policies Explicit
- Clear definitions
- Shared understanding
- Consistent application
5. Implement Feedback Loops
- Regular reviews
- Continuous improvement
- Adapt to change
6. Improve Collaboratively
- Evolutionary change
- Team-driven improvements
- Experiment and adapt
KANBAN vs SCRUM:
Kanban:
- Continuous flow
- No fixed iterations
- No prescribed roles
- Change anytime
- WIP limits
- Lead time focused
Scrum:
- Fixed-length sprints
- Prescribed ceremonies
- Defined roles (PO, SM, Dev)
- Change between sprints
- Velocity focused
- Commitment driven
"""
Choosing a Methodology
class MethodologySelector:
"""Help choose appropriate SDLC methodology."""
@staticmethod
def recommend(project_characteristics):
"""
Recommend methodology based on project characteristics.
Args:
project_characteristics: Dict with keys:
- requirements_stability: 'stable' or 'changing'
- team_size: int
- timeline: 'short' or 'long'
- complexity: 'low', 'medium', 'high'
- customer_involvement: 'low' or 'high'
"""
score = {
'waterfall': 0,
'agile_scrum': 0,
'kanban': 0
}
# Stable requirements favor waterfall
if project_characteristics['requirements_stability'] == 'stable':
score['waterfall'] += 2
else:
score['agile_scrum'] += 2
score['kanban'] += 2
# Small teams work well with kanban
team_size = project_characteristics['team_size']
if team_size <= 5:
score['kanban'] += 1
elif team_size <= 9:
score['agile_scrum'] += 2
else:
score['waterfall'] += 1
# High complexity benefits from agile
if project_characteristics['complexity'] == 'high':
score['agile_scrum'] += 2
score['kanban'] += 1
# Customer involvement
if project_characteristics['customer_involvement'] == 'high':
score['agile_scrum'] += 2
score['kanban'] += 1
else:
score['waterfall'] += 1
# Return recommendation
best = max(score, key=score.get)
return {
'recommended': best,
'scores': score,
'rationale': f"Based on project characteristics, {best} scores highest"
}
# Example usage
project = {
'requirements_stability': 'changing',
'team_size': 6,
'timeline': 'long',
'complexity': 'high',
'customer_involvement': 'high'
}
recommendation = MethodologySelector.recommend(project)
print(recommendation['recommended']) # Likely agile_scrum
Estimation Techniques
Story Points
class StoryPointEstimation:
"""Estimate work using story points (Fibonacci sequence)."""
FIBONACCI = [1, 2, 3, 5, 8, 13, 21]
@staticmethod
def planning_poker(story, team_estimates):
"""
Planning poker estimation technique.
Args:
story: User story to estimate
team_estimates: List of estimates from team members
Returns:
Consensus estimate
"""
# If all estimates are close, use average
if max(team_estimates) - min(team_estimates) <= 3:
avg = sum(team_estimates) / len(team_estimates)
# Round to nearest Fibonacci number
return min(StoryPointEstimation.FIBONACCI,
key=lambda x: abs(x - avg))
# Otherwise, discuss and re-estimate
return None # Need another round
@staticmethod
def t_shirt_sizing(story):
"""
Simple relative sizing: XS, S, M, L, XL.
Useful for initial rough estimates.
"""
sizes = {
'XS': 1,
'S': 2,
'M': 5,
'L': 8,
'XL': 13
}
# Return size that can be converted to points later
return sizes
# Example estimation
team_estimates = [5, 5, 8, 5] # Four team members
consensus = StoryPointEstimation.planning_poker("User login feature", team_estimates)
print(f"Consensus estimate: {consensus} points") # Likely 5
Exercises
Basic Exercises
SDLC Phases
- List all 7 SDLC phases
- For each phase, describe the main activities and deliverables
- Create a simple project plan for a calculator app
Requirements Gathering
- Create a requirements document for a library management system
- Include at least 5 functional requirements
- Include at least 3 non-functional requirements
- Write acceptance criteria for each requirement
Methodology Comparison
- Create a comparison table of Waterfall, Scrum, and Kanban
- List pros and cons of each
- Identify project types best suited for each methodology
Intermediate Exercises
Agile Sprint Simulation
- Create a product backlog with 10 user stories
- Plan a 2-week sprint with a team velocity of 20 points
- Simulate the sprint with daily progress
- Conduct a sprint retrospective
Scrum Implementation
- Implement the
ScrumTeamandScrumEventsclasses - Add methods for tracking impediments
- Create a burndown chart calculation
- Implement sprint metrics (velocity, commitment reliability)
- Implement the
Kanban Board
- Implement a full Kanban board with WIP limits
- Add methods to calculate lead time and cycle time
- Implement a cumulative flow diagram
- Create alerts when WIP limits are violated
Advanced Exercises
Hybrid Methodology
- Design a hybrid methodology combining Scrum and Kanban (Scrumban)
- Define when to use sprints vs continuous flow
- Create transition criteria between modes
- Implement in code
Project Simulation
- Create a complete project simulation from requirements to deployment
- Include random events (requirements changes, bugs, team changes)
- Calculate success metrics (on time, on budget, quality)
- Compare outcomes with different methodologies
Estimation Accuracy
- Implement multiple estimation techniques (story points, hours, t-shirt sizes)
- Track actual vs estimated for simulated work
- Calculate estimation accuracy over time
- Implement learning to improve estimates
Continuous Improvement
- Create a system to track retrospective action items
- Implement metrics to measure improvement
- Build a knowledge base of lessons learned
- Create recommendations for process improvements
Summary
The Software Development Lifecycle provides structure for building software:
- SDLC Phases: Planning, requirements, design, implementation, testing, deployment, maintenance
- Waterfall: Sequential, documentation-heavy, good for stable requirements
- Agile: Iterative, flexible, customer-focused, embraces change
- Scrum: Agile framework with sprints, roles (PO/SM/Dev), and ceremonies
- Kanban: Flow-based, visualize work, limit WIP, continuous delivery
- Choosing Methodology: Consider requirements stability, team size, complexity, and customer involvement
Key takeaways:
- No single methodology fits all projects
- Understanding principles matters more than rigid adherence
- Continuous improvement is essential
- Communication and collaboration are critical
- Deliver value incrementally when possible
Next Reading
Continue to 03-design-patterns.md to learn about common software design patterns that solve recurring design problems.