Agile software development models in Python 3
Agile software development models in Python 3
Some links:
Managing development teams
Trying to effectively manage several teams of developers is a challenge, to say the least.
Obviously, in a typical software development process there are quite a few different actors and entities, including (in no specific order):
- backlog items
- bugs
- developers
- iterations (in the Agile/Scrum sense of the word)
- (project) portfolio
- projects
- products
- release criteria
- requirements
- risks
- stakeholders
- tasks
- teams
Each one of the above actors or entities have their own properties and/or include references to the other actors/entities. For example, a bug has a description, a severity and a priority. A bug in itself, is linked back to a specific backlog-item. Backlog-items, however, also have a list of associated tasks, and so on.
Anyway, code speaks louder than words, so take a look at the (unfinished, Python 3) source below:
entity.py:
import uuid
from datetime import datetime
#===============================================================================
class Entity():
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True):
self.__identifier = (uuid.uuid1() if identifier is None else identifier)
self.__creation_date = datetime.now()
self.name = name
self.comment = comment
self.active = active
@property
def identifier(self):
return self.__identifier
@property
def creation_date(self):
return self.__creation_date
developer.py:
import uuid
from entity import Entity
#===============================================================================
class Developer(Entity):
def __init__(self,
identifier=uuid.uuid1(),
name='undefined',
comment='',
position='undefined'):
super().__init__(identifier, name, comment)
self.__position = position
self.__knowledge_areas = []
@property
def position(self):
return self.__position
@property
def knowledge_area(self):
return self.__knowledge_areas
def add_knowledge_area(self, knowledge_area):
self.__knowledge_areas.append(knowledge_area)
def remove_knowledge_area(self, knowledge_area):
self.__knowledge_areas =
list(item for item in self.__knowledge_areas if item != knowledge_area)
task.py:
from entity import Entity
from developer import Developer
#===============================================================================
class Task(Entity):
def __init__(self,
description,
identifier=None,
name='undefined',
comment='',
active=True):
super().__init__(identifier, name, comment, active)
self.description = description
# one of: not started, in progress, impeded or done
self.__status = 'not started'
# list of Developer objects of which the first one is the point person
self.__developers = []
# minimum amount of time that a task can take
self.__estimated_hours = 1
@property
def status(self):
return self.__status
@status.setter
def status(self, value):
states = {'not started', 'in progress', 'impeded', 'done'}
if len(states - {value.lower()}) == 4:
# temporary code, should raise an appropriate exception,
# i.e., unknown status
pass
else:
self.__status = value
@property
def developers(self):
return self.__developers
@property
def estimated_hours(self):
return self.__estimated_hours
@property
def point_person(self):
return self.__developers[0]
@point_person.setter
def point_person(self, value):
# check to see if the point person (passed through as a parameter)
# is already in the list of developers assigned to this task and
# if she is, set her as the first person in the list of developers
# effectively making her the point person for this task
# (see the 'point_person' property). If the point person is not
# in the list of developers (i.e., assigning a new developer to
# the task), then prepend her to the list of developers.
pass
def add_developer(self, developer):
self.__developers.append(developer)
def remove_developer(self, identity):
pass
backlogitem.py:
from entity import Entity
from task import Task
#===============================================================================
class BacklogItem(Entity):
def __init__(self,
description,
identifier=None,
name='undefined',
comment='',
active=True):
super().__init__(identifier, name, comment, active)
self.description = description
self.__tasks = [] # list of Task objects
self.__bugs = [] # list of Bug objects
@property
def tasks(self):
return self.__tasks
@property
def bugs(self):
return self.__bugs
def add_task(self, task):
self.__tasks.append(task)
def remove_task(self, identity):
pass
def add_bug(self, bug):
self.__bugs.append(bug)
def remove_bug(self, identity):
pass
Updated on May 03, 2010
team.py:
from entity import Entity
class Team(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True):
super().__init__(identifier, name, comment, active)
self.__developers = [] # list of Developer objects
@property
def developers(self):
return self.__developers
def add_developer(self, developer):
self.__developers.append(developer)
def remove_developer(self, identity):
pass
stakeholder.py:
from entity import Entity
#===============================================================================
class Stakeholder(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True):
super().__init__(identifier, name, comment, active)
risk.py:
from entity import Entity
#===============================================================================
class Risk(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True,
description='undefined',
probability=1,
impact=0,
response_plan=False):
super().__init__(identifier, name, comment, active)
self.description = description
self.probability = probability
self.impact = impact
self.response_plan = response_plan
@property
def score(self):
return self.probability * self.impact
requirement.py:
from entity import Entity
from stakeholder import Stakeholder
#===============================================================================
class Requirement(Entity):
def __init__(self,
description,
identifier=None,
name='undefined',
comment='',
active=True,
requestor=None):
super().__init__(identifier, name, comment, active)
self.description = description
self.__requestor = requestor # reference to a Stakeholder object
@property
def requestor(self):
return self.__requestor
@requestor.setter
def requestor(self, value):
# Do we want to limit the requestor to being the product owner? If that is the case,
# then we can remove this property completely from the Requirement class as the
# product owner is already tracked in the Product class.
self.__requestor = value
releasecriterion.py:
#===============================================================================
class ReleaseCriterion:
def __init__(self,
description,
comment=''):
self.description = description
self.comment = comment
self.specific = True
self.measurable = True
self.attainable = True
self.relevant = True
self.trackable = True
@property
def is_valid(self):
return self.specific
and self.measurable
and self.attainable
and self.relevant
and self.trackable
projectscope.py:
from product import Product
#===============================================================================
class ProjectScope:
def __init__(self, description):
self.description = description
self.__products = [] # list of Product objects
self.__dependencies = [] # list of other Project objects, i.e., dependencies
self.__release_critera = [] # list of ReleaseCriterion objects
@property
def products(self):
return self.__products
@property
def dependencies(self):
return self.__dependencies
@property
def release_criteria(self):
return self.__release_criteria
@property
def is_valid(self):
result = True
for release_criterion in self.__release_criteria:
if release_criterion.is_valid == False:
result = False
break
return result
project.py:
from entity import Entity
from projectscope import ProjectScope
from risk import Risk
from iteration import Iteration
#===============================================================================
class Project(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True,
description='undefined'):
super().__init__(identifier, name, comment, active)
self.__scope = ProjectScope(description)
self.__stakeholders = [] # list of Stakeholder objects
self.__risks = [] # list of Risk objects
self.__iterations = [] # list of Iteration/Sprint objects
# What about the 'project driver' matrix? That is:
# Priority Rank
# ======================
# Release date 1
# Feature set 2
# Low defects 3
@property
def scope(self):
return self.__scope
@property
def stakeholders(self):
return self.__stakeholders
@property
def risks(self):
return self.__risks
@property
def iterations(self):
return self.__iterations
def add_stakeholder(self, stakeholder):
pass
def remove_stakeholder(self, identity):
pass
def add_risk(self, risk):
pass
def remove_risk(self, identity):
pass
def add_iteration(self, iteration):
pass
def remove_iteration(self, identity):
pass
product.py:
import uuid
from entity import Entity
#===============================================================================
class Product(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True,
description='undefined',
product_owner=None):
super().__init__(identifier, name, comment, active)
self.description = description
self.__requirements = [] # list of Requirement objects
self.__product_owner = product_owner
@property
def requirements(self):
"""Return a list of the software functionality."""
return self.__requirements
@property
def product_owner(self):
return self.__product_owner
@product_owner.setter
def product_owner(self, value):
self.__product_owner = value
def add_requirement(self, requirement):
self.__requirements.append(requirement)
def remove_requirement(self, identity):
pass
portfolio.py:
from entity import Entity
from project import Project
from team import Team
#===============================================================================
class Portfolio(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True):
super().__init__(identifier, name, comment, active)
self.__projects = [] # list of Project objects (sinks)
self.__teams = [] # list of Team objects (sources)
@property
def projects(self):
return self.__projects
@property
def teams(self):
return self.__teams
def add_project(self, project):
self.__projects.append(project)
def remove_project(self, identity):
pass
def add_team(self, team):
self._teams.append(team)
def remove_team(self, identity):
pass
iteration.py:
from entity import Entity
from backlogitem import BacklogItem
#===============================================================================
class Iteration(Entity):
def __init__(self,
start_date,
end_date,
identifier=None,
name='undefined',
comment='',
active=True):
super().__init__(identifier, name, comment, active)
self.start_date = start_date
self.end_date = end_date
self.__backlog_items = [] # list of (committed) BacklogItem objects
@property
def backlog_items(self):
return self.__backlog_items
def add_backlog_item(backlog_item):
self.__backlog_items.append(backlog_item)
def remove_backlog_item(backlog_item):
pass
bug.py:
from entity import Entity
#===============================================================================
class Bug(Entity):
def __init__(self,
identifier=None,
name='undefined',
comment='',
active=True,
description='undefined',
severity='critical',
priority='now'):
super().__init__(identifier, name, comment, active)
self.description = description
self.__severity = severity
self.__priority = priority
@property
def severity(self):
return self.__severity
@property
def priority(self):
return self.__priority
@severity.setter
def severity(self, value):
# Severity is Technical but Absolute: an assessment of the impact of the bug
# without regard to other work in the queue or the current schedule.
states = {'critical', 'high', 'medium', 'low'}
if len(states - {value.lower()}) == 4:
# temporary code, should raise an appropriate exception, e.g., unknown severity
pass
else:
self.__severity = value
@priority.setter
def priority(self, value):
# Priority is Business, but Relative: a subjective evaluation of how important
# an issue is, given other tasks in the queue and the current schedule.
states = {'now', 'p1', 'p2', 'p3'}
# Now: drop everything and take care of it as soon as you see this (usually
# for blocking bugs)
# P1: fix before next build to test
# P2: fix before final release
# P3: we probably won't get to these, but we want to track them anyway
if len(states - {value.lower()}) == 4:
# temporary code, should raise an appropriate exception, e.g., unknown priority
pass
else:
self.__priority = value
To be continued
Click here to be able to create pages, upload images and file attachments, and link to other users and their pages.
blog comments powered by Disqus
Page trail: