今天的话题是收集需求。
Gathering Requirements
每个人都喜欢满意的客户。我们已经知道做一个好的软件的第一步是确保软件做了客户想要做的事情。但是你如何理解客户到底想要什么呢?如何确保客户知道他们自己想要什么呢?
个人认知:
个人觉得有时候用户也不太确定他们想要系统做什么具体的功能,也就是说他们也提不出来什么需求。但是他们有问题要解决,他们上系统的目的是解决问题。他们可以说明白的就是问题,具体的需求可能需要需求分析人员来分析问题,针对具体客户的具体问题,得出客户可能的需求,帮助客户梳理问题,同时梳理需求,达到共识。最后确定需求,产生需求文档,记录双方都认同的需求。
下面是一段用户自己的问题需求
每天晚上,用户的小狗Fido都会在门旁边一直的叫,直到用户起床把它放出去。用户不喜欢在夜里起床,他的爱人在夜里又不会起床,你可以帮助我们吗?
他们想要一个狗门,想用按钮就可以进行操作狗门的打开和关闭。
构造下面的一个狗门类
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class DogDoor
{
private bool _open;
public DogDoor()
{
_open = false;
}
public void Open()
{
Console.WriteLine("the dog door opens");
this._open = true;
}
public void Close()
{
Console.WriteLine("the dog door closes");
this._open = false;
}
public bool IsOpen()
{
return _open;
}
}
}
我们还需要一个操作类,Remote,因为用户希望使用遥控器的按钮来操作,而不是起床手动操作。
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class Remote
{
private DogDoor _door;
public Remote(DogDoor door)
{
this._door = door;
}
public void PressButton()
{
Console.WriteLine("pressing the remote control button....");
if (_door.IsOpen())
{
_door.Close();
}
else
{
_door.Open();
}
}
}
}
这下好了,现在用户只需要使用遥控器,然后再任何地方操作狗门的打开和关闭了,不用再起床了。
remote.PressButton();
用户比较满意了,回去使用了一段时间。但是新的问题又来了,小狗Fido进来之后,其他的小动物也从狗门进入了家门。
代码没有问题,是用户错误的使用了遥控器,在Fido进来之后没有及时的关闭狗门。
但是用户不这么认为,用户认为这个狗门和遥控器没有达到他的要求,不是他想要的。他们不想再Fido出去之后还要按一下按钮让门关闭,他们想只在Fido需要出去的时候按一下按钮就可以了。
这就是我们常说的用户的反复,需求的反复。就是用户对于他们的具体需求不能描述的很清楚,需要迭代,在实际场景中用户才会碰到更多的问题,才会提出更加具体的需求。这也是我们经常头疼的地方,其实可以换个思考的角度,用户的需求越多,给我们的机会就越大,如果用户没有需求了,那我们就没有生存的余地了。只是我们需要引导客户说出他们的具体需求,进行合理的设计开发,提供复用性,减少耦合性,就会使得我们可以更好的面对需求的变更。
面对新需求的时候,最好的办法是首先听客户描述他们的问题所在。他们分析出系统需要做什么,可以想出系统如何来做。
用户又提出来新的需求,希望门在打开几秒之后自动关闭。而且他们家的小狗Fido的高度是一只脚的长度,希望在它出门的时候不要伤害到它。
这时候你得出一个清单:
1、小狗叫了,他想出去
2、用户听到狗叫的声音
3、用户按下遥控器的按钮
4、狗门打开
5、小狗出去
6、在外面玩
7、小狗回来了
8、门自动关闭
然后针对这个清单进行分析,看看里面有没有什么潜在的问题。
1、小狗叫,狗叫不一定就是想出去,也可能是饿了。
2、听到狗叫声,听不到呢?主人不在家呢?
3、狗叫不是因为饿了,还需要打开门吗?
4、狗门打开,如果发生故障怎么办?硬件故障?
5、小狗出去,如果小狗没有出去呢?怎么办?
6、小狗玩耍
7、小狗回来了,可是门在这时候已经关闭了怎么办呢?
8、如果小狗还在外面,用户能否听见狗叫,然后打开门让它进来呢?
上面的清单需要局部的修改。
1、小狗叫了,他想出去
2、用户听到狗叫的声音
3、用户按下遥控器的按钮
4、狗门打开
5、小狗出去
6、在外面玩
6.1 狗门自动关闭
6.2 小狗又叫了,想要回来
6.3 用户又听到叫声
6.4 再次按下遥控器按钮
6.5 狗门再次打开
7、小狗回来了
8、门自动关闭
其实你一直在写用例。在写下这些步骤的时候,你实际上就是在做用例了。
用例就是系统实现某一个功能的步骤。用例就是在达到用户目标的时候,你的系统需要做的事情。
一个好的用例,包括三个部分:
- 用例对于系统来说必须是清晰的。如果用例不能帮助用户达到目标,这个用例就没有意义。
- 开始和结束。一个用例必须有开始点,然后再满足某一个条件之后,达到完成。
- 外部的发起者。每个用例都会由系统外的发起者发起,发起者有可能是人,也可能是外部系统。
上面的小狗Fido就是发起者,第一次的叫就是开始,最后一步的门关闭就是结束。
然后对着需求再次检查用例是否有问题,以及需求是否被满足。
有一些步骤是不需要你来实现的,在用例中找到并且标示出来。
让我们来更新一下代码,需要加入门的自动关闭功能。
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BeautyCode.Common.ConApp.Head.First.OO.Design
{
public class Remote
{
private DogDoor _door;
public Remote(DogDoor door)
{
this._door = door;
}
public void PressButton()
{
Console.WriteLine("pressing the remote control button....");
if (_door.IsOpen())
{
_door.Close();
}
else
{
_door.Open();
}
System.Threading.Thread.Sleep(5000);
_door.Close();
}
}
}
结论
OOA&D工具:需求和用例。
好的需求确保你的系统运行在客户预期的范围。确保需求覆盖了用例中的所有步骤。使用用例找出用户忘记告诉你的一些内容。用例可以揭示一些你需要加入系统的,未完成或者是容易丢失的需求。