捲動以翻頁
Computer Science Principles · AP Computer Science Principles
協作、設計與除錯
程式不是一次寫成的。它們要經過調查、設計、粗略建構、測試與重新審視,一圈又一圈,直到做到使用者所需要的。
圖形執行一種常見的開發流程:調查與反思, designing, prototyping and testing。紅球是手邊的工作;在每一站,它都可能把團隊送回較早的階段。每繞一圈,程式(藍色)就更完整一些:經過 3 圈後是版本 3。
流程可以是有序且有意為之的,依計畫進行各階段;也可以是探索式的,嘗試各種想法並保留可行的。流程有很多種;這四個階段是大多數流程共有的。
本章是 AP Computer Science Principles 的大概念 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 中的程式碼,作答時可以看到它。
任務與書面作答合計占 AP 成績的 30%;選擇題考試(70 題、120 分鐘)占其餘的 70%。
所以本章的問題會回到你自己的程式:它的目的與功能是什麼、輸入與輸出是什麼、你測試了什麼、用了哪些輸入,以及你發現並修正了什麼錯誤。