程序原本(六十三):应用开发基础——应用开发的背景与成因(语言的内建机制剥离了面向计算机的功能需求)

阅读数:33 2019 年 10 月 1 日 16:48

程序原本(六十三):应用开发基础——应用开发的背景与成因(语言的内建机制剥离了面向计算机的功能需求)

对于一个软件产品,我们需要将功能性需求与非功能性需求分开,但这并不是一件容易的事情。程序员总是按他们的习惯来理解眼前的事物,例如一个用户身份卡(User Id Card)首先是一个内存块,而不是一个抽象数据类型(ADT,Abstract Data Type)或真实的塑料卡片。那么基于这样的认识,什么才是对这个User_IdCard的功能性需求,什么又是其非功能性需求呢?

问题在于:User_IdCard具有多个层面的数据信息,并且对于不同的程序员来说,对其不同层面的理解都是正确、可实施、可计算的。缘于此,在不同层面上对其功能性需求的定义也就不同。例如对于偏向操作系统的开发人员,User_IdCard只有一个信息是有用的,即2

2 这里基于 Delphi 语法惯例,用前缀字符“T”来表示数据类型,而SizeOf()函数用于取数据类型所需存储的大小。

复制代码
SizeOf(TUser_IdCard)

这个长度值决定了程序如何分配和管理该数据的存储。因此这个开发人员会将他所理解的、以该长度值为核心的操作作为一个相对独立的部分区别出来,这些操作可能是如下一些函数或方法的运用3

3 该例援引的是 Delphi 中的一些内存管理函数,在不同的语言或平台中可能存在差异。

FreeMem GetMem ReallocMem

例如,一种可能的情况是:

复制代码
// 身份卡的批量分配
// - Delphi/Pascal Syntax
function BatchAllocCards(count: Integer): PCards;
begin
GetMem(Result, count * SizeOf(TUser_IdCard));
end;

这个函数与User_IdCard这种数据是有关的,但又与在最终界面上操作该应用软件的用户(例如户籍管理员张三)毫无关系。

接下来我们还会面临对这个数据的第二类理解:如果这个数据是一系列性质的集合(例如结构体或对象),则每一个性质将对应于现实系统的数据。简单地说,例如:

复制代码
User_IdCard.Age`

其性质Age代表了现实系统中某个用户的年龄。与此相类似,User_IdCard的每个性质都有其确定意义,并有相应的行为。这些行为与User_IdCard有关,但仍然是与张三无关。例如:

User_IdCard.setAge() User_IdCard.getAge()

到现在为止,随着计算机应用软件开发技术的发展,我们已经将上述两类对User_IdCard的理解放在一个语言的基础部分去实现了。大多数情况下,(高级的)计算编程语言通过抽象数据类型及其管理技术(例如对象、读写器、数据验证器4以及垃圾回收机制等)来将这些问题隔离在应用程序开发者的视野之外。

4 这里的验证器指的是类似 JAVA 中的通过注解来进行数据验证的技术。

忽略了类似上述的问题之后,我们才触到了应用开发的边缘。5

5 “如何屏蔽底层细节”也是应用开发技术的一部分,但对大多数应用开发语言 / 环境来说,这些都是内建机制。

评论

发布