軟件工程及軟件工藝

 Gordon Lau 劉偉中

Gordon Lau 劉偉中

2018-12-24

軟件工程是一個相當耳熟能詳的名詞,軟件工程(Software Engineering)由來已久,亦因此程式設計師(Programmer)又稱為軟件工程 師(Software Engineer)。 而有讀過以前《Programmer 做到三十歲就要轉行?》的朋友,應該對軟件工藝(Software Craftsmanship)這個字不陌生,同時科啟 學院其中一個創院價值,就是於香港資訊科技界推廣軟件工藝,於我們而言,軟件工藝代表的是軟件開發中創造的一面。

軟件工程

軟件開發真的是工程嗎?最容易理解的方法是看看軟件開發與其他工程範疇是否有類近之處:挑戰者號穿梭機因為一個密封圈失靈,就釀成意外。

challenger.jpg

Source:https://www.google.com/url?sa=i&source=images&cd=&cad=rja&uact=8&ved=2ahUKEwjFwsruy7ffAhURfnAKHVM1AO8QjRx6BAgBEAU&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DHHjp4cz3KJ4&psig=AOvVaw2DZK3RuxHUiJchlxjiAKPc&ust=1545710871178637

軟件也會因為一個小錯誤,就會 有大問題,著名的Apple Goto fail Bug就造成全世界加密系統的漏洞,而其實查明原因,錯 誤只是因為少了兩個標點符號:{}

原本是這樣:

if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
    goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;  
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
    goto fail;

正確應該是這樣:

if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
    goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0){ 
    goto fail;
    goto fail;  
}
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
    goto fail;

造成滿城風雨的Heartbleed bug也是一樣是很小很小的錯誤,也因為出問題的是加密較件,導 致後果嚴重。

此些事例,充份顯示軟件開發的工程一面,工程着重準確(precise),要求精細(detail-minded),講究可測量(measurability),在軟件工程中也有 很多相對應的例子:

  1. 效能調較(Performance Tuning)
  2. 使用者測試(User Acceptance Testing)
  3. 單元測試(Unit Testing)
  4. 資訊保安(Cyber-security)

以上各項,都是典型軟件工程的例子,效能調較測試的是運行速度(Speed)、可負載量(Load);使用者測試也是根據清單逐個逐個測試,不論有任何一個細 項不合格,都不能正式推出;單元測試更會計算測試覆蓋率(Coverage percentage),去判斷單元測試是否到位;資訊保安經常要做滲透測試 (Penetration Testing ),來判斷軟件是否安全。以上種種,都可以看到軟件開發有非常精細、準確的一面。

軟件工藝

資深軟件工程師經常會衝口而出,道:「段code寫得好靚!」或道:「段code寫得好核突!」這可奇怪了,為何會使用美感的形容詞如美或醜去形容一段代 碼呢?因為軟件工程不只工程一面,還有非常具創造性的一方面。 以下是三段javascript 的代碼,意思上一模一樣,即使大家不一定懂得編程,但大家覺得那一個清晰,最美的呢?

第一個例子:

const msg = "Hello World!\nThis is my first code"
fs.writeFile('file.txt',msg,(err)=>{
    if(err){
        console.log(err);
        return;
    }
    fs.readFile('file.txt',(err,data)=>{
        if(err){
            console.log(err);
            return;
        }
        const content = data.toString();
        fs.writeFile('file2.txt',content,(err)=>{
            if(err){
                console.log(err);
                return;
            }
        });
    })
});

第二個例子:

const msg = "Hello World!\nThis is my first code";
fs.promises.writeFile('file.txt',msg)
    .then(()=>fs.promises.readFile('file.txt'))
    .then((data)=>{
        const content = data.toString();
        return fs.promises.writeFile('file2.txt',content);
    })
    .catch(err=>{
        console.log(err);
        return;
    })

第三個例子:

const msg = "Hello World!\nThis is my first code";
async function run(){
    try{
        await fs.promises.writeFile('file.txt',msg);
        const data = await fs.promises.readFile('file.txt');
        content = data.toString();
        await fs.promises.writeFile('file2.txt',content);
    }catch(e){
        console.log(e);
    }
}
run();

注:用console.log 是因為缺乏上文下理,無法處理異常狀況,如果在web Server的情況下就應該返回500 response code。

憑直覺論,大家可能有五分八門的選擇。但資深軟件工程師則有明顯偏好,選擇的不是2就是3,我個人則偏好3,因為意思上簡 潔明確。 其實這三個都是Javascript處理非同步(Asynchronous Code)的方法,第一個例子最古老,第二個例子較新,第三個例子則是新近才加進標 準。

有何分別

如果三個意思上一樣,代表對電腦而言,三個在效能上毫無分別,那為何資深軟件工程師會選擇2或3,而不是1呢?因為寫代碼的要求其實不只正確那麼簡單, 還要着重易讀(Readable)及易寫(Writable)。著名軟件工程師Harold Abelson曾言:

Programs must be written for people to read, and only incidentally for machines to execute

所謂美的代碼,正是兼具易讀(Readable)、易寫(Writable)而又準確的代碼。 軟件工藝所追求,正是重視軟件工程師本身編程的技藝,寫美的代碼,建立好的軟件。

宣言

美國一群軟件工程師曾經提出一個相當精彩的宣言,去綜合軟件工藝的意涵:

As aspiring Software Craftsmen we are raising the bar of professional software development by practicing it and helping others learn the craft. Through this work we have come to value:

Not only working software, but also well-crafted software

Not only responding to change, but also steadily adding value

Not only individuals and interactions, but also a community of professionals

Not only customer collaboration, but also productive partnerships

謹以此四句,送給一直堅持寫好代碼的軟件工程師,共勉之。

留言

延伸閱讀

好Programmer是怎樣煉成的?

寫Blog與寫Code

平常人都能掌握的Programming 原則

Dart vs JavaScript vs TypeScript