滚动翻页
Computer Science Principles · AP Computer Science Principles
协作、设计与调试
程序不是一遍写成的。它们要经过调查、设计、粗略构建、测试和再次修订,一圈又一圈,直到满足用户的需要。
图中运行一种常见的开发过程:调查与反思, designing, prototyping and testing。红球是手头的工作;在每个站点,它都可能让团队回到更早的阶段。每一圈都让程序(蓝色)更完整:3 圈之后是版本 3。
过程可以是有序且有意的,按计划分阶段进行,也可以是探索式的,尝试各种想法并保留可行的。过程有很多种;这四个阶段是其中大多数所共有的。
本章是 AP 计算机科学原理的大概念 1,创意开发:占选择题考试的 10–13%。内容包括协同工作(1.1)、程序做什么以及有哪些输入和输出(1.2)、程序如何设计、构建和编写文档(1.3),以及如何发现和修正错误(1.4)。它也是本章最后一页 Create 表现任务 的工作内容。
以及改进它们的各种视角
计算创新包含一个程序,作为其功能不可分割的一部分。
它可以是实体的,如自动驾驶汽车;非实体的计算软件,如图片编辑软件;或非实体的计算概念,如电子商务。
创新通过协作得到改进。有效的协作产生的创新,反映了设计它的人的才能和视角的多样性,而多元的视角有助于避免偏差:成员都有同一种经历的团队,往往会为那种经历去构建。
图中是一个假想的团队,列出了它的应用必须处理的各种情形。开发者 A 一人只想到了 12 种中的 5 种。三位开发者合起来想到 10 种。其余的来自咨询用户:12 种中的 12 种。
这就是为什么与用户商议和沟通很重要。从潜在用户那里收集的信息,帮助开发者从多元的视角理解程序的目的,并构建出充分吸纳这些视角的程序。
结对编程、在线工具、人际交往技能
小组用常见的协作模式来开发创新。其中之一是结对编程。
两位程序员共用一台计算机。驾驶员(红色)输入代码;领航员(蓝色)在每行写出时进行审查,抓出错误并往前思考。图进行到一半时,他们交换角色:角色跟着键盘走,而不是跟着人走。他们编写的程序就是下一页的那个。
在线工具支持协作,让程序员无论是否在同一个房间里工作,都能分享想法和文档并对其给出反馈。
高效的团队会练习人际交往技能,包括但不限于:
程序做什么,以及怎么做
程序是一组程序语句的集合,由计算机运行时执行某项特定任务。程序常被称为软件。
total ← 0 REPEAT 3 TIMES { n ← INPUT() total ← total + n } DISPLAY(total / 3) 代码段是一组程序语句的集合,是程序的一部分:这里是第 2–6 行的循环(图中的蓝色部分)。
程序可以概括地描述,说它做什么:“它显示用户输入的三个数的平均值。”也可以更详细地描述,说它做什么以及它的语句怎样做到:“它把 total 设为 0;重复三次,每次读入一个数到 n 并加到 total 上;然后显示 total / 3。”
程序需要对各种输入和情形都能工作。图中把它运行了两次:
| 输入 | 循环后的 total | 显示 |
|---|---|---|
| 4, 8, 9 | 21 | 7 |
| −2, 0, 5 | 3 | 1 |
它的行为是它在执行过程中如何起作用,通常用用户如何与它交互来描述:用户输入三个数,出现一个数。
每项创新都有一个目的:解决问题,或通过创造性表达追求某种兴趣。理解目的的开发者能更好地开发程序。
数据进,数据出,形式多样
程序输入是发送给计算机、供程序处理的数据。程序输出是从程序发送到某个设备的任何数据。
二者都有多种形式:触觉(触摸、振动)、听觉(说出的一个词、一个声音)、视觉(摄像头图像、屏幕)或文本。图中依次把每种形式的一个输入送进程序,并让每种形式的一个输出从中送出。
输入可以来自用户或其他程序;右下角的文本输出送给另一个程序,对它来说就是输入。
输入通常会影响程序产生的输出。输出通常基于程序的输入或它先前的状态:即它存储的值。这个程序保存着它已收到输入的计数(蓝色),所以对屏幕的同一次触摸,第二次可能产生不同的输出。
在上一页的平均值程序中,对 INPUT() 的三次调用就是它的输入,DISPLAY 把它的输出送到屏幕。
语句在被触发时运行
事件与某个动作相关联,并向程序提供输入数据。
按下某个键、点击鼠标、程序启动,或发生任何其他影响执行流程的已定义动作时,都会产生事件。
在事件驱动编程中,程序语句在被触发时才执行,而不是通过顺序的控制流。没有任何东西从顶部开始一行接一行地运行:每个事件运行处理它的过程,然后程序等待下一个事件。
PROCEDURE onStart() { count ← 0 DISPLAY(count) } PROCEDURE onClick() { count ← count + 1 DISPLAY(count) } PROCEDURE onKeyPress() { count ← count - 1 DISPLAY(count) } 考试参考页没有事件语法,所以这里每个处理程序都是一个过程,事件发生时由一个假想的环境调用它。图中程序启动,按钮被点击三次,按下一个键,然后按钮再被点击一次。显示的值是 0, 1, 2, 3, 2, 3。
count 属于整个程序,所以每次点击的输出都取决于它之前的事件。
迭代式与增量式
开发过程可以是有序且有意的,也可以是探索式的。过程有很多种;大多数都包含调查与反思、设计、原型制作和测试这几个阶段。
迭代式过程要求在整个过程中,根据反馈、测试或反思进行完善和修订。这可能需要回到更早的阶段。在下面一行中,整个程序从第一遍起就已存在,只是粗糙;每一轮反馈(红色)都把它送回去,每个部分都变得更完整。
增量式过程把问题分成较小的部分,并确保每个部分都能工作后,再把它加入整体。在上面一行中,一次构建并测试一个部分,只有它的测试通过后才加入整体。
两者并非对立。大多数团队两者兼用:一块一块地构建,并随着反馈到来修订每个部分以及整体。
需求、规格说明、故事板、模块
程序的设计从调查开始,以确定它的需求。
调查要找出程序的约束,以及将使用它的人的关切和兴趣。可以通过 surveys, 用户测试, interviews and 直接观察 来进行。
程序需求描述程序如何运行,可能包括对它必须提供的用户交互的描述。程序的规格说明定义它的需求。以一个假想的预订图书馆自习室的应用为例:(1) 用户选择一个日期。; (2) 用户看到当天空闲的房间。; (3) 用户预订其中一间并获得一个代码。。
设计阶段概述如何实现规格说明。它可能包括:
图中画了其中两项:界面的故事板,每一步一个界面,用户的点击带着他们从一个界面到下一个;以及按模块组织的程序,每项需求一个模块。
并注明来自他人的代码
程序文档是对代码段、事件、过程或程序的功能,以及它是如何开发出来的书面描述。
注释是写在程序中、供人阅读的一种文档;它们不影响程序如何运行。并非所有编程环境都支持注释,考试参考页也没有注释,所以图中每个过程的文档改放在它旁边。
PROCEDURE average(numList) { total ← 0 FOR EACH num IN numList { total ← total + num } RETURN(total / LENGTH(numList)) } PROCEDURE isEven(n) { RETURN(n MOD 2 = 0) } average([6, 9, 3, 10]) 返回 7。文档要在整个开发过程中编写:average 的卡片随它的代码一起增长。它有助于开发和维护正确的程序,无论独自还是团队,因为下一位读者(往往是日后的作者本人)能看出每个部分的用途。
重要的是要注明任何合作开发或来自其他来源的代码段。注明可以写在程序文档中,并应包括出处或原作者的姓名。图中,isEven(蓝色)来自另一个来源,它的卡片上就这样写明了。
各自何时显现
三个程序,每个都应显示 [90, 75, 82] 中的每个分数;每个程序各有一处错误。
语法错误是程序中不符合编程语言规则的错误。第一个程序的第 5 行缺少右括号。程序根本无法运行:没有任何一行被执行,也不显示任何内容。
运行时错误是程序执行期间发生的错误;各编程语言定义自己的运行时错误。第二个程序在显示之前先给 i 加 1,所以它显示 75 and 82,然后访问 scores[4]。按参考手册,小于 1 或大于列表长度的索引是错误,程序随即终止。
逻辑错误是算法或程序中导致其行为不正确或出乎意料的错误。第三个程序少重复了一次。没有任何东西阻止它:它一直运行到结束,却只显示了 3 个分数中的 2 个。只有把输出与预期输出对照,才能发现这个错误。
scores ← [90, 75, 82] i ← 1 REPEAT LENGTH(scores) - 1 TIMES { DISPLAY(scores[i]) i ← i + 1 } 改正后,第 3 行是 REPEAT LENGTH(scores) TIMES。
超出范围的数
溢出错误发生在计算机试图处理超出已定义取值范围的数时。
许多编程语言用固定的位数存储整数,这限制了取值范围。以一种假想的语言为例,它用 4 位存储整数:它能容纳的最大值是 1111,也就是 15。
图中从 12 开始往上数。每一步翻转发生变化的位。到 15 时,加 1 需要多一位(16 是 10000),而存储只有 4 位:发生溢出。接下来会怎样取决于语言:有些会报错停止,另一些会保留放得下的位,带着错误的值继续(这里是 0)。
现实中的语言使用更多位,所以它们的限制要大得多,但依然是限制。考试参考页上的语言则不同:在那里,整数的大小只受计算机内存的限制。
定义好的输入,预期的输出
测试使用预先定义的输入,确保算法或程序产生预期的结果。程序员根据测试结果修改程序。
假设一家剧院的需求是:13 岁以下,或 65 岁及以上,票价为 $8;其他人票价为 $12。测试人员根据需求来确定要试哪些输入,以及每个输入应得到什么结果。
PROCEDURE price(age) { IF(age < 13 OR age ≥ 64) { RETURN(8) } RETURN(12) } 好的测试输入要能体现不同的预期结果,并且取在输入数据的极值(最小值和最大值)处或略超出极值处,因为错误往往集中在那里:这里是在一个边界两侧的 12 和 13,另一个边界两侧的 64 和 65,以及最小年龄 0。
| age(输入) | 期望 | 实际 | |
|---|---|---|---|
| 0 | $8 | $8 | pass |
| 12 | $8 | $8 | pass |
| 13 | $12 | $12 | pass |
| 40 | $12 | $12 | pass |
| 64 | $12 | $8 | 不通过 |
| 65 | $8 | $8 | pass |
对 64 的测试未通过:代码写的是 age ≥ 64,而需求的意思是 age ≥ 65,这是逻辑错误。只测 40 这样的典型年龄,永远发现不了它。
跟踪、可视化、调试、显示输出
查找并改正错误的有效方法:测试用例、手动跟踪、可视化、调试器,以及增加额外的输出语句。
findMax 应返回列表中最大的数。用 [-3, -7, -2] 测试时,它返回 0,而不是 −2。为了找出原因,程序员在循环中加入 DISPLAY(max)(蓝色):这就是一条额外的输出语句。
PROCEDURE findMax(numList) { max ← 0 FOR EACH num IN numList { IF(num > max) { max ← num } DISPLAY(max) } RETURN(max) } 对它进行手动跟踪,每个元素一行:
| num | num > max? | 之后的 max | DISPLAY 显示 |
|---|---|---|---|
| −3 | false | 0 | 0 |
| −7 | false | 0 | 0 |
| −2 | false | 0 | 0 |
max 始终没有变化:没有任何元素大于 0。调试器通过暂停程序并显示其变量,呈现同样的情况(图中的单元格就是其状态的可视化)。错误在第 3 行:max 从 0 开始,比全为负数的列表中的每个元素都大。
修正方法是 max ← numList[1]:从列表中的一个元素开始。再次运行,额外的输出显示 −3, −3, −2,返回的是 −2。然后把多加的 DISPLAY 删掉。
你自己的程序,以及关于它的问题
Create 表现任务是把本章所学付诸实践:自选一个程序,运用 1.1–1.4 中的开发过程、文档和测试来完成。
你要在 AP Digital Portfolio 中提交三样东西:程序代码、程序运行的视频,以及个性化项目参考(PPR)。学校至少会给你 9 小时的课堂时间来完成。你的程序必须包含某些元素,例如列表和过程。
考试当天是书面回答:60 分钟,2 道关于你自己 PPR 中代码的题,答题时可以查看 PPR。
该任务与书面回答合计占 AP 成绩的 30%;选择题部分(70 题,120 分钟)占其余的 70%。
所以本章的问题会回到你自己的程序上:它的目的和功能是什么,输入和输出是什么,你测试了什么、用了哪些输入,你发现并改正了什么错误。