经过QPG团队的努力,我们马上将推出共享软件――需求看板V1.0
a) 图形化界面,操作十分简单,不需要帮助手册,一般只用鼠标的两个键就可以操作;
b) 目标管理而非任务管理(今后在工作包看板里实现);
c) 客观、真实反映项目的进度;
d) 区分不同需求的价值点,自动汇总项目的总价值点,辅助项目经理防止需求蔓延。
e) 目前是C/S架构,今后将推出B/S板
经过QPG团队的努力,我们马上将推出共享软件――需求看板V1.0。
下面是系统的目前的主界面:
![](/images/cnblogs_com/qpg2006/face.jpg)
我这里简单介绍一下这个共享软件的特点和核心代码思路:
一) 产品特点
a) 图形化界面,操作十分简单,不需要帮助手册,一般只用鼠标的两个键就可以操作;
b) 目标管理而非任务管理(今后在工作包看板里实现);
c) 客观、真实反映项目的进度;
d) 区分不同需求的价值点,自动汇总项目的总价值点,辅助项目经理防止需求蔓延。
e) 目前是C/S架构,今后将推出B/S板
二) 设计思路点评
2.1) 基本概念
我们经过对常见项目的总结,建议通常用三层来表达系统的需求:
需求类型 |
节点特征 |
备注 |
项目需求 |
没有父节点 |
项目根节点 |
需求 |
有父有子 |
子系统、模块节点 |
规格 |
有父无子 |
对应FDD中的特征,是可以验证和测试的叶子节点 |
状态――需求的推进状况;
完成率――0~100%
价值点――衡量一个规格或者价值的贡献度
对于规格,可以设定(1~10)
对于需求,系统将自动汇总
2.2) 核心逻辑
对于一个规格,我们通过状态的变化来映射其完成百分比,下表是一种可能的设定方法:
顺序号 |
状态 |
累计完成率(%) |
1 |
纳入开发 |
0% |
2 |
需求评审 |
20% |
3 |
设计评审 |
30% |
4 |
单元测试通过 |
60% |
5 |
集成测试通过 |
80% |
6 |
验收测试通过 |
100% |
对于包含规格或者子需求的需求,则是查看其所有规格的有效完成率来计算自身的完成率的。
2.3) 核心逻辑代码实现
a) 算法接口定义
1![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
namespace KanBan.Data
{
2
3
using System;
4
using System.Collections;
5
using System.Xml.Serialization;
6![](/Images/OutliningIndicators/InBlock.gif)
7![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public enum RequimentState : int
{New=0,Going=1,Finished=2 }
8![](/Images/OutliningIndicators/InBlock.gif)
9![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public interface IRequimentRule
{
10
int getFinishPercent(RequimentState rs);
11
}
12
}
13![](/Images/OutliningIndicators/None.gif)
b)一个缺省的实现:
1
namespace KanBan.BizRule
2![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
3
using System;
4
using System.Collections;
5
using KanBan.Data;
6
7![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public class DefaultRule:IRequimentRule
{
8
private System.Collections.IDictionary _map;
9
public DefaultRule()
10![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
_map = new Hashtable();
12
_map.Add(RequimentState.New, 0);
13
_map.Add(RequimentState.Going, 50);
14
_map.Add(RequimentState.Finished, 100);
15
}
16![](/Images/OutliningIndicators/ContractedSubBlock.gif)
IRequimentRule#region IRequimentRule
17
public int getFinishPercent(KanBan.Data.RequimentState rs)
18![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
19
return (int)_map[rs];
20
}
21
#endregion
22
}
23
}
24![](/Images/OutliningIndicators/None.gif)
c) 需求服务的关键部分代码:
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public virtual IList getSpecifications(Requiment req)
{
IList tops = new ArrayList();
if(req.NextLevelRequiments==null||req.NextLevelRequiments.Count == 0) return tops;
IList items=req.NextLevelRequiments;
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
foreach(Requiment sr in items)
{
if (sr.IsSpecification)
tops.Add(sr);
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
IList temp = getSpecifications(sr);
foreach (object f in temp) tops.Add(f);
}
}
return tops;
}
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public virtual int getFinishPercent(Requiment req)
{
if(req.NextLevelRequiments==null||req.NextLevelRequiments.Count == 0)
return _logic.getFinishPercent(req.State);
IList tops = getSpecifications(req);
int sum = 0;
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
foreach (Requiment part in tops)
{
int k = (int)getFinishPercent(part);
sum += k;
Console.WriteLine("特征[{0}]完成:{1}%", part.Name, k);
}
Console.WriteLine("{0} Finish:{1}%", req.Name, sum / tops.Count);
return (int)(sum / tops.Count + 0.499M);
}
![](/Images/OutliningIndicators/None.gif)
d) 集成起来!
如果客户有特殊的需求,那我们也可以很简单的开发一个逻辑dll,在配置文件中配置一下就可以了,类似下面这样:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<components>
![](/Images/OutliningIndicators/None.gif)
<component id="myrule" service="KanBan.Data.IRequimentRule, KanBan.Data"
type="KanBan.BizRule.MyRule, KanBan.BizRule2">
</component>
![](/Images/OutliningIndicators/None.gif)
<component id="reqdao" type="KanBan.DAS.RequimentDAO, DAS">
</component>
![](/Images/OutliningIndicators/None.gif)
<component id="rs" type="KanBan.BizRule.RequimentService, KanBan.BizRule">
<parameters>
<logic>${myrule }</logic>
</parameters>
</component>
<component id="rf" type="KanBan.Facade.RequimentFacade, KanBan.Facade">
</component>
</components>
</configuration>
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
2.3) 数据处理
我们不会重复去发明轮子,开始我们用了castle ActiveRecord组件,发现在有递归的情况bug不少,后来就转回Nhibernate, 下面是需求的映射配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="KanBan.Data.Requiment, KanBan.Data" table="Requiments">
<id name="ID" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<property name="Name" not-null="true" length="100" />
<property name="Code" not-null="true" unique="true" length="20"/>
<property name="Catalog" not-null="false" length="40" />
<property name="Priority" not-null="false" length="20" />
<property name="Important" not-null="false" length="20" />
<property name="Description" not-null="false" length="250" />
<property name="ValuePoint" not-null="true" />
<property name="State" not-null="true" />
<many-to-one name="Parent" column="p_ID" />
<bag name="NextLevelRequiments" inverse="false" lazy="true" cascade="all" order-by="Code" >
<key column="p_ID" />
<one-to-many class="KanBan.Data.Requiment, KanBan.Data" />
</bag>
</class>
</hibernate-mapping>
![](/Images/OutliningIndicators/None.gif)
![](/Images/OutliningIndicators/None.gif)
Alex 2005.12