顯示具有 標籤的文章。 顯示所有文章
顯示具有 標籤的文章。 顯示所有文章

星期五, 5月 20, 2011

[書]JavaScript: 優良部份

擷取
  • 企圖擷取不存在的屬性,會產生undefined
    stooge['middle-name'] //undefined
    flight.status //undefined

    較好的做法 - 給予預設值
    var middle = stooge['middle-name'] || "(none)";
    var status = flight.status || "unknown";
  • 企圖從undefined取值,將丟出TypeError
    可利用&&防衛此狀況
    flight.equipment //undefined
    flight.equipment.model //丟出"TypeError"
    flight.equipment && flight.equipment.model //undefined
減少全域變數
全域變教會削弱程式的彈性,利用物件包裝
var MYAPP = { };
//利用這個變數保存全域變數
MYAPP.flight = {
airline: "Oceanic",
number:815
};




Reference

JavaScript: The Good Parts - 中譯:JavaScript: 優良部份

星期日, 4月 18, 2010

Code Complete 2

作者:Steve McConnell

Ch6 工作類別

類別基礎:抽象資料型別(ADT)
將字型大小變更為12點,即16個像素高
//易混淆
currentFont.size = 16; //不知是pixel還是點

//較具意義
currentFont.size = PointsToPixels(12); 
currentFont.bold = true;
currentFont.setBoldOn();

Ch7 高品質常式

從常式名稱中可猜出其作用
單一且明確定義的目的
參數不易超過7個,造成閱讀不易
具備抵禦錯誤資料,不會造成當機

良好的常式名稱
  • 描述常式的所有工作
  • 避免無意義、模糊式空泛的動詞命令
  • FormatAndPrintOut()會比HandleOutput()更加的清楚
  • 勿僅用數字后別常式名稱
  • part1(),part2()
  • 用回傳值述命名函式
  • printer.isReady(),user.next()
如何使用常式參數
  • 文件化有關參數的介面假設
  • 不要回頭再寫註解,數字參考單位,預期值的範圍、永不應出現的特定值
  • 考慮輸入、修改和輸出參數的命名慣例
  • input_,modify_,output_

Ch8 防禦性程式設計

用判斷提示證明和驗證前置條件及後置條件
又稱為design by contract (Meyer 1997)
function velocity(float latitude, float longitude,float elevation){
//Preconditions
Debug.Asert ( -90 <= latitude && latitude <= 90); 
Debug.Assert ( 0 <= longitude && longitude<= 360); 
Debug.Assert ( -500 <= elevation && elevation <= 75000); ... 

//Postcondition 
Debug.Assert()0 <= returnVelocity && returnVelocity <= 600);  
//return value 
return returnVelocity ; 
}

對於錯誤的條件,常式通常會用判斷提示直接處理錯誤的程式碼
判斷提示
Debug.Assert()0 <= returnVelocity && returnVelocity <= 600); 

直接處理錯誤的程式碼
...
//cloest legal value
if(latitude <-90) latitude = -90; else if (latitude > -90)
latitude = 90;
...

8.3 處理錯誤的技巧
傳回中性值
有時對錯誤資料的最佳反應就是持續操作,回傳預設值。數字計算=>0,文字操作=>空字串
關鍵情況下,就回傳錯誤,不要回傳錯誤的資料。
以下一個有效資料取代
處理資料串流時
傳回與上一次相同的回答
考慮建立集中的例外況報告程式
確保例外狀況處理一致性,也能提供中央儲存機制九
function reportException(string className, Exception ex){
string caption="Exception";
string message = 
"Exception: " + ex.Message + Enviroment.NewLine +
"Class: " + className + Enviroment.NewLine +
"Routine: " + ex.TargetSite.Name;

MessageBox.Show(message,caption);
}

//example
try{
...
}catch(Exception ex){
reportException(CLASSNAME,ex);
}

8.5 建立路障,避免程式內含錯誤造成的損毀
撰寫驗證類別,在所有介面運算資料前,透過驗證類別確保資料有效

Ch14 組織直線
14.1.須依特定順序排列的陳述式
1.連續呼叫相依的methods
//計算年營收前,得先計算季營收,而計算季營收前,要先計算月營收
revenue.ComputeMonthly(); //
revenue.ComputeQuarterly();
revenue.ComputeAnnual();
相依性不明顯,將來順序對換,會造成錯誤, 要讓程式碼可看出其相依關係
 2.初始化
//求各部門支出前,要先利用ComputeMarketingExpense()初始化
ComputeMarketingExpense(); //
ComputeSalesExpense();
ComputeTravelExpense();
無法在第一時間看出計算前要先初始化,將來順序對換會錯誤

使常式參數使相依性明顯 
//利用初始化及輸出值,提示相依性
expenseData = InitializeExpenseData(expenseData);

expenseData = ComputeMonthly(expenseData);
expenseData = ComputeQuarterly();
expenseData = ComputeAnnual();  

Ch15 使用條件式
15.1 if
指導方針
  • 先寫pass判斷的正常路徑;再寫異常案例後,避免模糊掉執行邏輯
  • 將正常的case置於if block, 而非else後方
OpenFile(inputFile, status); 
if( status = Status_Success )  //pass
    ReadFile( inputFile, fileData, status); //名目案例
    if(status = Status_Success)
    { 
        end(); 
        errorType= ErrorType_None;
    }
    else
        errorType = ErrorType_FileReadError; //錯誤案例
else
    errorType = FileOpenError; //錯誤案例
重點在讀取主要流程,而非費力專研例外案例
Ch26. 程式碼微調技巧
26.2 迴圈
決策外置(Unswitching)
如果if判斷不會在迴圈執行時變更,就把if搬到迴圈外

合併
將兩個相同集合項目的迴圈合併,一次就把兩次事做完
for(i=0;i<n;i++)
  a++;
for(i=0;i < n;i++)
  b++;
------------------------合併成------------------------
for(i=0;i < n;i++){
  a++;
  b++;
}

減少迴圈內的工作
要使迴圈有效率,其中的關鍵在減少迴圈內部的工作。
如果可在外部運算部份或全部的陳述式,只讓結果進入迴圈內,就可提升效率

26.3 資料轉換
使用整數而非浮點數
盡量不要使用陣列維度
減少陣列參考
利用變數存陣列值,就可避免在迴圈內讀取陣列值
for(...)
  rate[level] *= discount[type]; //discount[type]可抽出來
---------------------用變數取代---------------------------------
discounttype =  discount[type];
for(...)
  rate[level] *=  discounttype;

26.4 運算式
利用代數恆等式
not a and not b = not (a or b)
後者會比前者快上將近1份的時間
使用強度降代
  • 用加法取代乘法
  • 用乘法取代乘冪
  • 用三角恆等式取代三角常式
  • 整數運算會比浮點數快
  • 使用位移運算取代整數乘除

星期五, 4月 16, 2010

與熊共舞:軟體專案的風險管理 Waltzing with Bears: Managing Risk on Software Projects


與熊共舞:軟體專案的風險管理
Waltzing with Bears: Managing Risk on Software Projects

作者:湯姆.狄馬克、提摩西.李斯特/著












風險管理的主要活動
  • 風險探索(risk discovery):風險腦力激盪,把風險歸類,再訂出可長久運作的機製
  • 承擔分析(exposure analysis):以風險成形的機率,及其潛在的衝擊程度為基礎,量化每個風險
  • 應變規劃(contingency planning):萬一風險真的成形,你期望採取的行動
  • 紓緩(mitigation):在風險蛻變前必須進行的步驟,使事先規劃的應變行動在必要時能發揮作用
  • 蛻變的持續監視(ongoing transition monitoring):風險被納管之後,就要進行風險追蹤,留意是否成形

Ch8.將不確定性量化

- 風險圖
最早的完成時間會自動變成最後期限
但完成機率是零...
說定最中間的日期(5/1)
加減10~15%


Ch9.風險管理的技巧

  • 風險庫
  • 選擇偵測風險成形的指標
卡車司機的座右銘:
每個滾動的球後面都跟著一位追逐的孩童
並不是指都有孩童將被撞到,但看到球,還是立刻踩下煞車比較好

Ch10.風險管理的處方


如何做風險管理
  1. 透過風險抭索程序找出專案面臨的風險,彙整成風險調查報告
  2. 確定軟體專案的主要風險都已納入調查報告
  3. 針對每個風險,完成以下事項:
    • 命名風險,賦予唯一編號
    • 找出蛻變指標-能及早預告風險即將成形的事物
    • 預估風險成形對成本和時程的衝擊
    • 預估風險成形的機率
    • 計算時程和預算的風險承擔
    • 預先決定執行應變行動而必須預先進行的紓緩措施
    • 把紓緩措施納入專案計劃
    • 把所有細節記錄在類似附錄B的制式文件內
  4. 指出致命風險(showstopper)
  5. 假設不會有任何風險成形,估計最早完成日期(奈米機率日,N點)
  6. 參考自己或業界的不確定性係數,以N點為起點,畫出風險圖
  7. 利用風險圖表示出所有承諾,風跟規劃日期和預算有關的不確定性也標示出來
  8. 監視所有風險,注意是否成形或解除,一旦成形,便立即啟動應變計劃
  9. 在專案進行時,持續風險探索程序,以對付較晚才浮現出來的風險
承諾與目標
時程 = 目標 = N <=非常笨的做法
時程 > 目標 > N <=比較合乎情理

不確定性的取捨
如果交付日期已敲定,且不留任何延誤的餘地
可利用版本交付時程來達成


Ch13.軟體專案的核心風險

  1. 先天的時程錯誤(schedule flaw)
  2. 不把規模想清楚就敲定時程,逾期50%~80%不足為奇,主管很少會怪時程,相反地,會怪人沒有盡力
  3. 需求膨脹(requirement inflation) ... 沒完沒了的需求變動
  4. 每月合理的需求變更應小於1%,因此預留時間
  5. 人力流失(employee turnover)
  6. 技術人員的年平均流動率 接替人員完全進入狀況時間(ramp-up time)
  7. 規格崩潰(specification breakdown)
  8. 一般人傾向於促成案子,有談不攏的衝突都會先被掩飾起來,於是專案就在缺陷、模糊的目標下進行,但開發產品時就會爆發,通常是在專案後期,預算、時間都花光了。
  9. 低生產力(poor productivity)
  10. 開發人員的表現好壞差異相當大,但在團隊中,個人因素或多或少都會被中和掉,所以差異不大。
把核心風險當作風險管理是否完備的指標
不敢說核心風險是完善,但沒考量五個核心風險,就說有做風險管理....

Ch16.漸進式風險紓緩

預先採取的一套作為,萬一風險成形,便可有效地處理風險
漸進式式交付的好處:
  • 迫使為組件進行優先順序
  • 反暈真實的開發效率
交付計劃

  • 設計藍圖(design blueprint):顯示要實作的低階模組或類別,及彼此之間的關係
  • 工作分解結構(work breakdown structure, WBS):顯示要完成的工作,及彼此之間的相依關係
  • 一組版本驗收測試(version acceptance test, VAT):把產品的驗收測試按版本細分,顯示哪個測試可用在哪個中間產品上
實獲率
工作編號工作量工作百分比完成的版本小計VAT通過日期
1.11人週11%版本1
2.7人週7%版本1
3.12人週12%版本130%第100天
4.10人週10%版本2
5.9人週9%版本249%第154天
6.8人週8%版本3
7.13人週13%版本369%第173天
8.9人週90%版本478%第185天
9.14人週14%版本5
10.7人週7%版本5100%第206天

ch17 終極的風險紓緩策略
計劃準時參加會議,途中可能遇到預料外的耽擱,最簡單的做法只要提早出發...
假如專案交付日期非常關鍵,那麼早點出發才是真正的風險紓緩措施

星期一, 1月 04, 2010

書 - 完美程式設計指南

Ch2 自我維護
程式釋出前都要做unit test,即使是只改一點點

測試人員存在的目的是找尋程式員沒找到的錯誤,寫程式的人應該自己找尋自己製造的臭蟲。

coding時
1.用防禦性程式寫作,但別隱藏錯誤(bug)
2.加上除錯檢查(ex:assert) - 印出錯誤方便debug

*維護程式的發行版跟除錯版。發行版用來打包發行,除錯版用來盡可能快速抓蟲。
*除錯檢查巨集是寫出除錯檢查的快速方式。用它們來捕捉不應該發生的非法狀況。不要把這些狀況跟錯誤狀況混在一起;錯誤狀況在最後的產品中一定得被處理掉。
*用除錯檢查巨集來核對函式參數,並警告程式原有東西是未定義的。你愈嚴格定義你的函式,核對它的參數就愈簡單。
*一旦你寫好了一個函式,把它重新檢查一遍,並問問你自己,"我假設了什麼條件一定成立的嗎?"如果你找到一個假設條件,用除錯檢查巨集檢查這條件是否永遠成立,或者重寫程式以去除這樣的假設。也問問自己,"程式中哪裡最可能出錯,我怎樣才能自動找到錯誤?"盡可能將捕捉錯誤的測試放在愈早執行到的地方愈好。
*教科書鼓勵程式員防禦性的寫程式,可是記住這種寫作方式會隱藏錯誤。當你寫出防禦性的程式時,用除錯檢查巨集來提醒你自己是否有"不可能"發生的狀況發生了。

Ch3 增強子系統
檢查你的子系統,問問你自己,程式員們可能會怎麼誤用它。加上除錯維護敘述跟核對檢查來捕捉不好找跟常見的錯誤。

如果你不重複找尋,就修不好錯誤。找尋任何可能造成隨機行為的東西,把它們從除錯版程式中拿掉。將未初始化的記憶體以某個垃圾值填滿只是一種去除隨機行為的辦法,那樣子如果有參考到未初始化記憶體的情形發生,你就可以在每次執行到出錯的程式時都能重複同樣的現象。

如果你的子系統釋放記憶體(或其他資源)然後製造垃圾,請清理被釋放的記憶體中的內容,讓裡頭的東西看起來像垃圾;不然別處的程式可能會繼續使用這些已釋放記憶體中的東西而不被察覺。

類似的,如果你的子系統有些可能會發生卻不一定發生的行為,加上除錯碼來確定這些行為一定會發生。讓每件事都發生過可以增進你捕捉到較少執行到的程式中出現的怪異現象。

確定你的測試工作在程式員沒注意到時都在進行著。最佳的測試方式就是那些完全不用在乎它們的存在的測試。

如果可能,將測試碼建立在子系統裡頭,而不要寫在它們上頭。不要等到子系統已經寫好了,才來想辦法查對它們的動作正不正確。對每個你考慮的設計方式,問問你自己,"我該怎樣徹底查對這個實作?"如果你發現幾乎不可能或難於測試這個實作方式,好好考慮一下是不是該換個設計方式,即使那表示拿程式大小跟執行速度為代價來讓系統可被測試。26

在拿掉一個讓程式跑得很慢或吃很多記憶體的查核測試前,多想一遍。記住,查核程式碼不會出現在發行版的程式裡。如果你發現自己想著,"這些測試太慢了(或太大了)",停下來,問問自己,"我該怎樣讓這些測試繼續留著,而讓程式跑快一點(或變小一點)?"

星期一, 12月 07, 2009

Refactoring: Impoving The Design of Existing Code

中譯:重構-改善既有程式的設計

前言

古老的工程諺語:「如果它還能執行,就不要動它」
 但專案功能不斷修改程碼,使原先系統結構逐漸衺弱,程式碼也更加複雜,無法除錯,也無法獲得可被接受的性能/效率
最後重新編寫整個系統,作者指出堅持以持續不斷的重構行為是成功專案的重要角色

重構:「在不改變程式碼外在行為的前提下,對程式碼做出修改,以改進程式的內部結構」

軟體會慢慢腐爛
 重構的步驟只要把某欄位(field)從一個class移到另一個class,把某段程式碼從method拉出成另一個method,或是在class hierarchy中把某些程式碼推上推下就行了,聚沙成塔,小小的修改累積就可以改善設計品質,這和「軟體會慢慢腐爛」的觀點恰恰相反

Ch1 Refactoring, a First Example

分解並重組method
案例中的錄影帶出租statement()做太多事,程式碼太長,可以其目的拆成至不同的class
每個method的程式碼越少越容易維護,且拆成 更多的method更容易reuse(copy-paste相同的程式碼,常發生改了a method忘了改相同容內的b method)
重構技術係以微小的步伐修改程式。改錯時,很容易發現它

更改變數是值得的行為嗎?(p.15)
好的程式碼應清楚表達自己的功能,變數名稱是程式碼清晰的關鍵
任何一個傻瓜都能寫出計算機可以理解的程式碼。唯有寫出人類容易理解的程式碼,才是優秀的程式員


Replace Temp with Query(p.21)
int thisAmount => each.getCharge()
儘量除去暫時變數,暫時變數會導致大量參數被傳來傳去。也很容易失去蹤跡=>相對要付出效率上的代價,但可由最佳化來調整(細節p.69)

運用多型取代與價格相關的條件邏輯(p.34)
=>引用State pattern
在父類別宣告abstract int getPriceCode(),讓子類別實作其條件,使其有自己的計費法
*另外邏輯判斷也該在物件本身的class(指switch(getMovie().getPriceCode())=>應在class movie裡寫switch (getPriceCode())
當有傳入值有可能有變化時,選擇可能變化小的,折起的side effect也較小
=>引用State pattern的重點在「修改與價格有關的行為」,或「新增定價標準」會較容易

Ch2 Principles in Refactoring

為何重構
-改進軟體設計=>消除duplicate code
-使軟體更易被理解
-助找到bugs=>程式碼易於理解,而不是從一個500行的method找

何時重構 The Rule of Three (p.58)
1.反感,第三次又做類似的事就該重構
2.添加功能時
3.修補錯誤時
4.code review時

Ch3 Bad smells in Code

何時重構、何時停止及重構的機制
1.Duplicated Code p.76
2.Long Method p.76
3.Large Class p.78
class太大,instance變數就會多,Duplicated Code也接腫而至
4.Long Parameter List p.78
5.Divergent Change(發散式變化) p.79
隨外界變化而有所修改,找出原因運幅Extract Clss提煉到另一個class
6.Shotgun Surgery(霰彈式修改) p.80
每遇修改就得在不同的classes內做小修改
7.Feature Envy(依戀情結)
某method內呼叫該class幾乎半打的getting method
8.Data Clumps
每次都會同時出現的幾個field
9.Primitive Obsession
日期年月日,3個int不如定義成object
原則
應放在一起的fields =>Extract Class
參數列中有基本型資料=>Introduce Parameter Object
從array挑資料 =>Replace Array with Object
10.Switch Statements