軟件工程及軟件工藝
軟件工程是一個相當耳熟能詳的名詞,軟件工程(Software Engineering)由來已久,亦因此程式設計師(Programmer)又稱為軟件工程 師(Software Engineer)。 而有讀過以前《Programmer 做到三十歲就要轉行?》的朋友,應該對軟件工藝(Software Craftsmanship)這個字不陌生,同時科啟 學院其中一個創院價值,就是於香港資訊科技界推廣軟件工藝,於我們而言,軟件工藝代表的是軟件開發中創造的一面。
軟件工程
軟件開發真的是工程嗎?最容易理解的方法是看看軟件開發與其他工程範疇是否有類近之處:挑戰者號穿梭機因為一個密封圈失靈,就釀成意外。
軟件也會因為一個小錯誤,就會
有大問題,著名的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),在軟件工程中也有 很多相對應的例子:
- 效能調較(Performance Tuning)
- 使用者測試(User Acceptance Testing)
- 單元測試(Unit Testing)
- 資訊保安(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)而又準確的代碼。 軟件工藝所追求,正是重視軟件工程師本身編程的技藝,寫美的代碼,建立好的軟件。
宣言
美國一群軟件工程師曾經提出一個相當精彩的宣言,去綜合軟件工藝的意涵:
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
謹以此四句,送給一直堅持寫好代碼的軟件工程師,共勉之。