第十八章

Download Report

Transcript 第十八章

可信賴的軟體開發

建立可信賴軟體系統的程式
設計技術
©Ian Sommerville 2000
Dependable Software Development
Slide 1
軟體的可信賴度(dependability)


一般來說,軟體客戶期望所有的軟體都是可信
賴的。但是,對於非關鍵應用程式而言,它們
可能願意接受某種小的系統故障。
然而,某些應用程式確有極高的可信賴度需求
,必須使用特殊的程式技術來達到這個需求。
©Ian Sommerville 2000
Dependable Software Development
Slide 2
可信賴度的達成

避免錯誤(Fault avoidance)
•
•

軟體的開發應該避免人為的錯誤而將系統錯誤減到最少
開發程序應該被建構成可以偵查軟體中的錯誤,並且在錯
誤傳送給客戶之前予以修復
容錯(Fault tolerance)
•
軟體應該被設計成軟體的錯誤不會造成系統的故障
©Ian Sommerville 2000
Dependable Software Development
Slide 3
錯誤最小化



最新的軟體工程方法可以開發出無錯誤(faultfree)的軟體。
無錯誤軟體是指符合規格的軟體,但並不代表
軟體會永遠正確的運作,因為規格也可能會發
生錯誤。
生產無錯誤軟體的費用非常高,只有在特殊的
情況下才會符合成本效益。如果接受軟體錯誤
則會比較便宜。
©Ian Sommerville 2000
Dependable Software Development
Slide 4
錯誤移除成本
©Ian Sommerville 2000
Dependable Software Development
Slide 5
無錯誤的軟體開發






需要一個精確的(最好是正規的)規格。
需要一個重視品質的公司文化。
以資訊隱藏和封裝為主的軟體設計。
應該使用強式型別和執行時期檢查功能的程式
語言。
應該避免容易出錯的程式設計結構。
可信賴和可重複的開發程序。
©Ian Sommerville 2000
Dependable Software Development
Slide 6
結構化程式設計






最早於1970年代被提出討論
不使用goto敘述的程式設計
程式中的控制結構只能使用迴圈和 If 敘述
由上而下的設計
重要的概念,因為它推動了程式設計的概念和
相關的討論
可產生易讀且易了解的程式
©Ian Sommerville 2000
Dependable Software Development
Slide 7
容易錯誤的結構

浮點數
• 原本就不是很精確,所以不精確的浮點數會導致無效的比較。

指標
• 參考到錯誤記憶體區域的指標會損毀資料,「別名」(Aliasing)
技術會讓程式很難理解及變更。

動態記憶體配置
• 在執行時期配置記憶體可能會造成記憶體溢位(用完)。

平行處理
• 因為很難預知平行程序之間在時序上的互動情形,平行處理會
造成難以捉摸的時序錯誤。
©Ian Sommerville 2000
Dependable Software Development
Slide 8
容易錯誤的結構

遞廻(Recursion)
•

中斷
•

遞廻中的錯誤會造成記憶體溢位。
中斷會引起某個關鍵操作被終止,且使程式很難被了解。
它們可比得上goto敘述。
繼承
• 相關的程式碼不會全部放在同一個地方,在進行程式變更
時會引起非預期的行為,使得行為更難以理解。

這些結構不須避免但必須謹慎使用。
©Ian Sommerville 2000
Dependable Software Development
Slide 9
資訊隱藏


資訊只能洩漏給那些需要存取資訊的部份程式
。此動作包含物件或抽象資料型別的建立,它
們是用來保存狀態和對狀態的操作。
基於下列三個理由,資訊隱藏可以避免錯誤的
發生:
•
•
•
資訊被意外損壞的可能性。
資訊是以「防火牆」被保護住,所以問題較不可能蔓延到
程式的其他部分。
因為所有資訊不會全部放在同一個地方,所以程式設計師
較不可能出錯,而審核者則較可能發現錯誤。
©Ian Sommerville 2000
Dependable Software Development
Slide 10
Java的佇列規格
interface Queue {
public void put (Object o) ;
public void remove (Object o) ;
public int size () ;
} //Queue
©Ian Sommerville 2000
Dependable Software Development
Slide 11
Java的Signal宣告
class S igna l {
pub lic f ina l int red = 1 ;
pub lic f ina l int a mbe r = 2 ;
pub lic f ina l int g reen = 3 ;
... othe r dec larat ions he re ...
}
©Ian Sommerville 2000
Dependable Software Development
Slide 12
可靠的軟體程序



為了確保最少的軟體錯誤,擁有良好定義且可
重複執行的軟體程序是很重要的。
一個有良好定義的可重複執行程序是完全不依
賴個人的技巧,也不會由不同的人來詮釋。
為了達到錯誤最小化,很明顯的程序活動必須
包含重要的確認和驗證動作。
©Ian Sommerville 2000
Dependable Software Development
Slide 13
程序的確認活動







需求檢查(Requirements inspections)
需求管理(Requirements management)
模型檢查(Model checking)
設計與編碼檢查(Design and code inspection)
靜態分析(Static analysis)
測試規劃與管理(Test planning and management)
組態管理(Configuration management )也是不可
或缺的
©Ian Sommerville 2000
Dependable Software Development
Slide 14
容錯(Fault tolerance)



在重要的情況下,軟體系統必須能夠容錯。在
高可用率需求或系統故障成本極高的情形下,
都需要有容錯的機制。
容錯是指不管軟體是否故障,系統都能夠繼續
運作。
即使系統為不會發生錯誤的系統,它也必須有
容錯機制,因為也許會有規格的錯誤或是確認
有誤的情形發生。
©Ian Sommerville 2000
Dependable Software Development
Slide 15
容錯的動作

錯誤偵測(Fault detection)
•

損害評估(Damage assessment)
•

已受到錯誤影響的系統狀態部分必須能夠被偵測出來。
錯誤復原(Fault recovery)
•

系統必須能夠偵測錯誤(不正確的系統狀態)是否發生。
系統必須能夠回復到已知的安全狀態。
錯誤修復(Fault repair)
• 系統可以被修改使錯誤不再復發。因為許多軟體錯誤都只
是短暫的狀態,所以通常不需要錯誤修復。
©Ian Sommerville 2000
Dependable Software Development
Slide 16
容錯的方法

防禦式程式設計(Defensive programming)
• 程式設計師先假設系統的程式碼有錯誤然後加入重複的程式
碼,檢查修改後的系統狀態,以確認狀態的改變是否一致。

容錯架構(Fault-tolerant architectures)
• 包含能支援硬體和軟體備援的硬體和軟體系統架構,以及一
個能偵測問題和支援錯誤復原的容錯控制器。

上述這兩個方法是互補的,不是互相對立的技
術。
©Ian Sommerville 2000
Dependable Software Development
Slide 17
例外管理



一個程式的例外狀況(exception)是一個錯誤或
一些意外的事件,例如電源發生故障。
例外狀況的處理結構可以處理這些事件,而不
用持續檢查系統狀態來偵測這些例外狀況。
使用正常控制結構在一連串巢狀程序呼叫中偵
測例外狀況時需要加入許多額外敘述與處理時
間。
©Ian Sommerville 2000
Dependable Software Development
Slide 18
Java的例外狀況
class SensorFailureException extends Exception {
SensorFailureException (String msg) {
super (msg) ;
Alarm.activate (msg) ;
}
} // SensorFailureException
class Sensor {
int readVal () throws SensorFailureException {
try {
int theValue = DeviceIO.readInteger () ;
if (theValue < 0)
throw new SensorFailureException ("Sensor failure") ;
return theValue ;
}
catch (deviceIOException e)
{ throw new SensorFailureException (“ Sensor read error ”) ; }
} // readVal
} // Sensor
©Ian Sommerville 2000
Dependable Software Development
Slide 19
例外式的程式設計


例外也可以作為正常的程式設計技術,而不
只是充當從錯誤復原的方法。
例如,以冷凍庫溫度控制系統為例,如后說
明。
©Ian Sommerville 2000
Dependable Software Development
Slide 20
溫度控制程式




控制一個冷凍庫並且將溫度保持在一個特定的
範圍內。
可開啟或關閉冷凍幫浦。
如果超過所需溫度就啟動警報器。
使用例外做為一般的程式設計技術。
©Ian Sommerville 2000
Dependable Software Development
Slide 21
class FreezerController {
Sensor tempSensor = new Sensor () ;
Dial tempDial = new Dial () ;
float freezerTemp = tempSensor.readVal () ;
final float dangerTemp = (float) -18.0 ;
final long coolingTime = (long) 200000.0 ;
public void run ( ) throws InterrupedException {
try {
Pump.switchIt (Pump.on) ;
do { if (freezerTemp > tempDial.setting ())
if (Pump.status == Pump.off)
{
Pump.switchIt (Pump.on) ;
Thread.sleep (coolingTime) ;
} else
if (Pump.status == Pump.on)
Pump.switchIt (Pump.off) ;
if (freezerTemp > dangerTemp)
throw new FreezerTooHotException () ;
freezerTemp = tempSensor.readVal () ;
} while (true) ;
} // try block
catch (FreezerTooHotException f)
{
Alarm.activate ( ) ; }
catch (InterruptedException e)
{
System.out.println (“Thread exception”) ;
throw new InterruptedException ( ) ;
}
} //run
} // FreezerController
©Ian Sommerville 2000
Dependable Software Development
冷凍庫溫度控制器
(Java)
Slide 22
錯誤偵測



像 Java 和 Ada 之類的程式語言有很嚴密的型別
系統,這種系統可以在編譯時偵測出許多錯誤
。
但是有一些錯誤類別只能在執行時期被發現。
錯誤偵測包含偵測一個錯誤的系統狀態以及丟
出一個例外來管理偵測到的錯誤。
©Ian Sommerville 2000
Dependable Software Development
Slide 23
錯誤偵測

預防性錯誤偵測(Preventative fault detection)
•

錯誤偵測機制會在狀態改變被提交之前啟動。如果偵測出
可能出錯的狀態,那麼就不會改變此狀態。
回溯性錯誤偵測(Retrospective fault detection)
•
錯誤偵測機制會在系統狀態已經改變之後才啟動。當正確
動作的不正確序列導致錯誤的狀態,或是當預防性錯誤偵
測牽涉到太多額外負載時則使用回溯性錯誤偵測。
©Ian Sommerville 2000
Dependable Software Development
Slide 24
類型系統的擴展


預防性錯誤偵測事實上都會在型別定義中加入
一些額外的限制條件(constraint),以擴展型別
系統。
這些限制會定義成類別定義中的基本操作。
©Ian Sommerville 2000
Dependable Software Development
Slide 25
class PositiveEvenInteger {
int val = 0 ;
PositiveEven數字型
別的Java程式碼
PositiveEvenInteger (int n) throws NumericException
{
if (n < 0 | n%2 == 1)
throw new NumericException () ;
else
val = n ;
} // PositiveEvenInteger
public void assign (int n) throws NumericException
{
if (n < 0 | n%2 == 1)
throw new NumericException ();
else
val = n ;
} // assign
int toInteger ()
{
return val ;
} //to Integer
boolean equals (PositiveEvenInteger n)
{
return (val == n.val) ;
} // equals
} //PositiveEven
©Ian Sommerville 2000
Dependable Software Development
Slide 26
損害評估



分析系統狀態以評估系統故障所引起的損害範
圍。
必須評估狀態空間中有哪些部分受到故障的影
響。
通常會依據可應用在狀態元素的「有效性函式
」 (validity functions)來評估它們的值是否在許
可範圍內。
©Ian Sommerville 2000
Dependable Software Development
Slide 27
損害評估技術



資料傳輸的損害評估可以使用checksum。
檢查資料結構完整性時可以使用重複性指標。
監控計時器(Watch dog timers)可以用來檢查無
法終止的程序。如果經過一段時間沒有回應,
便可以假定有問題發生。
©Ian Sommerville 2000
Dependable Software Development
Slide 28
class RobustArray {
// Checks that all the objects in an array of objects
// conform to some defined constraint
boolean [] checkState ;
CheckableObject [] theRobustArray ;
具有損害評估的 Java類別
RobustArray (CheckableObject [] theArray)
{
checkState = new boolean [theArray.length] ;
theRobustArray = theArray ;
} //RobustArray
public void assessDamage () throws ArrayDamagedException
{
boolean hasBeenDamaged = false ;
for (int i= 0; i <this.theRobustArray.length ; i ++)
{
if (! theRobustArray [i].check ())
{
checkState [i] = true ;
hasBeenDamaged = true ;
}
else
checkState [i] = false ;
}
if (hasBeenDamaged)
throw new ArrayDamagedException () ;
} //assessDamage
} // RobustArray
©Ian Sommerville 2000
Dependable Software Development
Slide 29
錯誤復原

前向復原(Forward recovery)
•

後向復原(Backward recovery)
•


修復被損壞的系統狀態
將系統狀態回復到已知的安全狀態
前向復原通常必須利用應用程式的特定領域知
識來計算可能的狀態修正。
後向錯誤復原是比較簡單的技術。它能維持安
全的狀態並且將損壞的系統狀態回復到安全狀
態。
©Ian Sommerville 2000
Dependable Software Development
Slide 30
前向復原

編碼資料遭毀損(Corruption of data coding)
•

將重複資料加入編碼資料的錯誤編碼技術,它可以用來修
復資料傳輸時被毀損的資料。
重複性指標(Redundant pointers)
• 當資料結構中包含重複性指標(例如雙向串列),若有足夠
數量的指標未遭毀損,就可以重新建立被毀損的串列或儲
存位置。
• 通常可以用來修復資料庫和檔案系統。
©Ian Sommerville 2000
Dependable Software Development
Slide 31
後向復原


異動(transaction)是一種常被使用的後向復原
方法。更新動作必須等到計算完成才可進行
,如果發生錯誤,系統就會停留在異動之前
的狀態。
週期性的查核點(checkpoint)允許系統回存
(rollback)到正確的狀態。
©Ian Sommerville 2000
Dependable Software Development
Slide 32
安全排序程序




排序操作程序會監視自己的運作並且評估排序
是否正確執行。
此程序會保留一份輸入資料,以便在發生錯誤
時,該輸入資料不致遭到損毀。
以辨識和處理例外狀況為基礎。
在這種情況下已知有可能是「有效的」排序。
但是,在很多情況下很難去撰寫有效的檢查程
式。
©Ian Sommerville 2000
Dependable Software Development
Slide 33
安全排序程序 (Java)
class SafeSort {
static void sort ( int [] intarray, int order ) throws SortError
{
int [] copy = new int [intarray.length];
// copy the input array
for (int i = 0; i < intarray.length ; i++)
copy [i] = intarray [i] ;
try {
Sort.bubblesort (intarray, intarray.length, order) ;
if (order == Sort.ascending)
for (int i = 0; i <= intarray.length-2 ; i++)
if (intarray [i] > intarray [i+1])
throw new SortError () ;
else
for (int i = 0; i <= intarray.length-2 ; i++)
if (intarray [i+1] > intarray [i])
throw new SortError () ;
} // try block
catch (SortError e )
{
for (int i = 0; i < intarray.length ; i++)
intarray [i] = copy [i] ;
throw new SortError ("Array not sorted") ;
} //catch
} // sort
} // SafeSort
©Ian Sommerville 2000
Dependable Software Development
Slide 34
重點整理




具容錯的軟體可以在軟體發生錯誤時仍然持續
運作。
容錯程序包含故障偵測、損害評估、復原和修
復。
防禦性程式設計是實作容錯的一個方式,它所
依賴的是程式中重複性的檢查。
例外狀況處理功能簡化了防禦性程式設計的程
序。
©Ian Sommerville 2000
Dependable Software Development
Slide 35
容錯架構




防禦性程式設計不能有效處理硬體和軟體互動
所產生的系統錯誤。
對需求的誤解可能會讓檢查和相關的程式碼不
正確。
對於那些有高可用率需求的系統來說,可能需
要設計支援容錯的特定系統架構。
容錯架構必須能夠容忍硬體和軟體的錯誤。
©Ian Sommerville 2000
Dependable Software Development
Slide 36
硬體容錯




以三模組備援(triple-modular redundancy,
TMR)為基礎。
它會有三份完全相同的複製元件,並且接受相
同的輸入資料,而它們的輸出資料可以互相做
比較。
如果有一個不同的輸出資料,該資料會被忽略
而造成元件故障。
這種容錯方法主要是用在因元件故障而造成的
錯誤,而非設計上的錯誤,而且同時發生元件
故障的機率會很低。
©Ian Sommerville 2000
Dependable Software Development
Slide 37
具有三模組備援的硬體可靠性
A1
Ou t pu t
com p arat or
A2
A3
F au lt
m anag er
©Ian Sommerville 2000
Dependable Software Development
Slide 38
輸出選擇



輸出比較器是一個比較簡單的硬體裝置。
與輸入訊號比較時,如果彼此不同,就會互相
拒絕。實際上,真正的輸出以大多數一致認為
的輸出為準。
輸出比較器與錯誤管理連結直到可以修復錯誤
的單元或從服務中移除為止。
©Ian Sommerville 2000
Dependable Software Development
Slide 39
容錯軟體架構

三模組備援在提供容錯方面的成功是依據以下
兩個基本的假設:
•
•

以上兩個假設都不適用於軟體:
•
•

硬體元件不包含常見的設計錯誤。
元件隨時會失去作用而且元件同時發生故障的可能性很低
。
不可能只複製相同的元件,因為它們可能會有同樣的設計
錯誤。
元件同時發生故障無法真正避免。
軟體系統必須具多樣性。
©Ian Sommerville 2000
Dependable Software Development
Slide 40
設計多樣性


不同版本的系統以不同的方式設計和實作,因
此它們應當有不同的故障模式。
不同的設計方式(例如,物件導向和功能導向
等):
•
•
•
不同程式設計語言的實作
不同工具和開發環境的使用
不同實作演算法的使用
©Ian Sommerville 2000
Dependable Software Development
Slide 41
類似三模組備援的軟體

N版本程式設計(N-version programming)
•
•

不同小組的一些不同版本中實作相同的規格。所有的版本
會同時計算而且大多數的輸出是透過投票系統選取出來。
這是最常見的使用方式,例如 Airbus 320。
復原區塊(Recovery blocks)
•
•
一些規格相同但有數個不同版本的軟體依序撰寫與執行。
使用可接受的測試來選擇欲傳送的輸出。
©Ian Sommerville 2000
Dependable Software Development
Slide 42
N版本程式設計
©Ian Sommerville 2000
Dependable Software Development
Slide 43
輸出比較


如同硬體系統一樣,輸出比較器是一個簡單的
軟體,它也是使用投票機制選出輸出。
在即時系統中,可能需要有一個需求,讓不同
版本的軟體在某一個時間範圍內同時都產生結
果。
©Ian Sommerville 2000
Dependable Software Development
Slide 44
N版本程式設計


不同的系統版本由不同小組設計和實作,這些
系統會犯相同錯誤的可能性會很低,而使用的
演算法應該不同,但也可能會相同。
根據一些經驗指出,開發小組通常會以相同的
方式誤解規格,並且選擇相同的演算法來開發
他們的系統。
©Ian Sommerville 2000
Dependable Software Development
Slide 45
復原區塊
©Ian Sommerville 2000
Dependable Software Development
Slide 46
復原區塊



讓每個版本使用不同的演算法可以降低共同錯
誤的可能性。
但是接受測試的設計卻很困難,因為它必須獨
立於使用的運算方式。
由於重複版本的循序式運作,復原區塊這種方
式用在即時系統時將會有問題。
©Ian Sommerville 2000
Dependable Software Development
Slide 47
設計多樣性的問題


開發小組不全然都具有多樣性,所以他們會以
相同的方法來處理問題。
典型的錯誤
• 不同小組犯相同的錯誤。實作的某些部分可能比其他部分
困難,所以所有小組可能都會在同一個地方犯錯。
• 規格錯誤
• 如果規格有錯誤,那麼就會在實作中反映出來。
• 由於使用多個規格表示法,所以還會出現許多這種設計多
樣性的問題。
©Ian Sommerville 2000
Dependable Software Development
Slide 48
規格的相依性



軟體備援的兩種方式易受規格錯誤的影響,如
果規格不正確,系統可能就會發生故障。
硬體也會遇到同樣的問題,但是軟體規格通常
比硬體規格還要複雜,而且比較難確認。
若根據相同使用者規格開發各自獨立的軟體規
格,就可以看出這種規格相依性。
©Ian Sommerville 2000
Dependable Software Development
Slide 49
是否需要軟體備援?



軟體不像硬體系統,在實際世界中軟體錯誤不
是不可避免。
某些人相信可以藉由努力降低軟體複雜性而達
到更高程度的可靠性和可用率。
因為具備援的軟體比較複雜,所以還有許多會
影響系統可靠度的額外錯誤是由容錯控制器所
引起的。
©Ian Sommerville 2000
Dependable Software Development
Slide 50
重點整理



系統的可信賴度可以透過避免系統錯誤和容錯
功能來達成。
某些程式語言結構和技術原本就容易造成錯誤
,例如goto、遞迴和指標等。
資料型態可以讓許多可能的錯誤在編譯時就被
抓出來。
©Ian Sommerville 2000
Dependable Software Development
Slide 51
重點整理




容錯架構依賴複製的硬體和軟體元件。
它是用包含機制來偵測錯誤元件,並且將它從
系統中排除。
N版本程式設計和復原區塊是設計容錯軟體架
構的兩種不同方法。
設計多樣性是軟體備援的基本條件。
©Ian Sommerville 2000
Dependable Software Development
Slide 52