跳至主內容

軟件工程及軟件工藝

軟件工程及軟件工藝
Gordon Lau 劉偉中
2018-12-24

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

軟件工程

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

挑戰者號穿梭機發射圖

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 ),來判斷軟件是否安全。以上種種,都可以看到軟件開發有非常精細、準確的一面。

軟件工藝

筆者按於2020-11-12: 有讀者認為之前的例子不能反映軟件工藝之分野,只是反映了不同版本的Node.js處理非同步之做法,因此筆者決定更改此例子,以闡術筆者之想法。

資深軟件工程師經常會用到寫得「美妙」、「很醜」等形容詞,這可奇怪了,為何會使用美感的形容詞如美或醜去形容一段程式碼 碼呢?因為軟件工程不只工程一面,還有非常具創造性的一方面。 以下是三段Python 函數的程式碼,所運行的算法是非常相似的,都是嘗試找出所有在n以下0以上之整數的畢氏定理整數組合(Pythagorean Triplets),即使大家不一定懂得編程,但大家覺得那一個最為簡潔明確呢?

第一個例子用傳統迴圈(Loop)做法:

def pythagoras(n):
    triples = []
    for x in range(1,n+1):
        for y in range(1,n+1):
            for z in range(1,n+1):
                if x**2 + y**2 == z**2:
                    triples.append((x,y,z))
    return triples

第二個例子運用了列表推導式(list comprehension):

def pythagoras(n):
    return [(x,y,z) 
                for x in range(1,n+1 )
                for y in range(1,n+1 ) 
                for z in range(1,n+1 ) 
                if x**2 + y**2 == z**2
            ]

第三個例子運用了產生函數推導式(generator comprehension):

from itertools import permutations
def pythagoras(n):
    return ((x,y,z) 
                for (x,y,z) in permutations(range(1,n+1),3)
                if x**2 + y**2 == z**2
            )

這三個方法有何分別呢?且等筆者一一解說:

  • 第一個方法運用最傳統的for迴圈及if,本身較容易理解,但寫出來感覺上較累贅,而且也多了許多縮排(Indentation)
  • 第二個方法運用了列表推導式(List Comprehension),是 Python一個較獨有之功能,開發者可以用一個類似寫數學中的集合(Set)的方法去構建列表(List)
  • 第三個方法更進一步,運用了Generator,也就是整個運算是Lazy的,所謂Lazy ,就是會等待我們使用一個函數next()才會計算下一個整數組合,另一方面又用了permutations的function ,避免使用了nested loop。也加上了x + y > z 去避免搜尋不可能是整數組合之數字。

以下是一個使用的例子:

from itertools import permutations
def pythagoras(n):
    return ((x,y,z) 
                for (x,y,z) in permutations(range(1,n+1),3)
                if x**2 + y**2 == z**2
                if x + y >  z
            );

>>> gen  = pythagoras(10)
>>> next(gen)
(3, 4, 5)
>>> next(gen)
(4, 3, 5)
>>> next(gen)
(6, 8, 10)
>>> next(gen)
(8, 6, 10)
>>> next(gen)

所以,就算你輸入一個很大的n例如pythagoras(1000),效能也會較好,因此可以判定方法三比方法二及一都要好

因為寫程式碼要求其實不只正確那麼簡單,還要着重易讀(Readable)、易寫(Writable)、高效能(Performant)。著名軟件工程師Harold Abelson曾言:

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

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

有何分別

如果三個意思上一樣,代表對電腦而言,三個在效能上毫無分別,那為何資深軟件工程師會選擇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是怎樣煉成的?

好Programmer是怎樣煉成的?

好Programmer是怎樣煉成的?
Gordon Lau 劉偉中
2018-12-20

有一個大部份僱主都面對的難題,在芸芸履歷之中,如何萬中挑一,找到好programmer呢?聘請程式設計師很難,不像其他行業,打開 履歷就一目了然:有時履歷上滿滿証書的,其實連FizzBuzz也寫不了;有時看起來像個fresh graduate的,卻又有無限潛力。 如果你是一個要聘請程式設計師的僱主,你應該如何是好呢?


寫Blog與寫Code

寫Blog與寫Code

寫Blog與寫Code
Gordon Lau 劉偉中
2019-01-07

在外國,程式設計師在課餘時間寫Blog是很平常的一回事,大家在找尋技術問題的解決方法時,除了全知的Stack Overflow之外, 很多時候閱讀的就是一些其他高手所撰寫的技術文章,博客平台如Medium等也應運而生。相較之下,香港甚少有聽聞程式設計師有寫博客的習慣,大概是由於 工作繁忙,抽身不暇。筆者此前也只是曾經在一些Facebook專頁寫過一些技術文,現在才算上是恆常出文。短短數月中,已感受到為何外國程式設計師如此樂 此不疲,即使要抽出私人時間,也會寫Blog出文。


平常人都能掌握的Programming 原則

平常人都能掌握的Programming 原則

平常人都能掌握的Programming 原則
Gordon Lau 劉偉中
2019-01-29

大家會定時整理自己電腦中的文件嗎?大家看軟件工程師工作時,往往會發現他們的檔案總是井井有條,資料有條不紊地排列。難道學習軟件工程能使人變得 整齊?原因其實在於軟件工程師經常需要處理大量檔案及資料,因此發展出一套完整的工程原則(Engineering Practice),久而久之,就掌握了資料管理 的要訣。而如果平常人也掌握了這些工程原則,在日常電腦使用,其實也有不少好處。


Dart vs JavaScript vs TypeScript

Dart vs JavaScript vs TypeScript

Dart vs JavaScript vs TypeScript
Gordon Lau 劉偉中
2019-02-17

隨著Flutter受到開發者的重視,Google於2011年推出的Dart又重新進入大家關注的視野之內,不過除了Flutter以外,其實Google的開發者早在2016年也推出過Angular Dart,讓開發者以Dart開發網站應用,不過由於Angular Dart對比TypeScript版Angular文本長期不足,因此沒有引起太多關注。Google推出Flutter,可以說為大家對Dart的信心注入了一劑强心針,大家又重新開始關注這個已有8年歷史的程式語言。 本文想介紹的是,就是到底Dart有何特色?與JavaScript比較,又有何優劣?由於TypeScript開始於前端日漸盛行,我們亦可以趁機比較一下三種語言的異同。


索取課程大綱
提交後, 請檢查你的電郵
hello@tecky.iot.me/TeckyAcademy
+852 9725 6400+44 07570 549084+1 (647) 556-3084
商界展關懷 2019-2022
英國頒證機構 TQUK 認可中心
aws_partner
薯片叔叔共創社 重塑教育挑戰大獎
© 2022 Tecky Academy Limited