星期三, 12月 22, 2021

2021 年度回顧



 


【今年的亮點】

 

2021 年,是我自己工作滿十年的一年。所以,這個回顧可能不一定是一年的回顧,也讓我自己檢視跟思考這段時間以來的工作。

 

過去很長一段時間,自己都著重於實際工作的交付上,雖然有很多的心得與想法,但最終並沒有將這些內容發布出來。許多的資產,只是躺在自己的電腦內。很多時候,只是一直不斷地忙於工作上的交付。

 

在工作上,比較幸運的是在某些領域,我們獲得不錯的成績,獲得顧客有指名的效果。當然,除此之外,我們也陸續經營了一些其他的技術領域,深耕客戶,提供專業的服務。

 

最近這兩年,公司開始要進行轉型,找了一些行銷的夥伴來幫忙,所以我才開始把腦袋裡的東西往外倒,在他們的協助下,進行一些對外的公開活動。

 

所以,在今年與原廠一起分享金融業雲端平台的建置藍圖以及參與雲端大會,進行一些資訊的交流與分享。

 

隨然面對著疫情,但是今年有幸可以到外面上上實體課程,替自己腦補一下,在年中的時候參與了領與驅動設計與整潔架構的課程,內容相當實用,也把自己很多經驗做了一些修正。

 

透過這個訓練,深深覺得夥伴們也應該有這樣的技能,所以在公司內部也舉辦了這樣的課程,跟大家分享領域驅動設計與軟體架構的概念,讓大家在面對微服務的應用時,手邊能有一些素材,來進行分析與設計的作業。

 

這部分,我自己覺得有個開始,從知識的消費者,往生產者的方向走。工作十年,某些事情可能也需要有點改變。

 


【做得不好待改善的事情】


雖然開始整理一些知識開設課程,但是同仁的吸收狀況似乎不是很好,需要加強授課的方法與技巧。

 

【看了哪些書】

平常沒事(不過好像很少沒事,所以就算工作很忙,還是找空檔充實自己),自己就是個書蟲,透過閱讀補強自己的各種觀念,特別是自己每次接觸一個新領域時,都先透過書籍來建立該領域的心智模型。同仁們也稱我為行動圖書館,通常他們找我聊一聊後,我可以推薦或是借幾本書給他們做更深入的鑽研。以下就分享在寫這回顧當下,最快出現在腦袋中的十本非技術書籍:

 

公司賺錢有這麼難嗎

        在書中,以作者打算出售自己的公司為故事主軸,透過 17 招改善公司營運本質,在最後讓故事主人翁從一開始整天被錢追著跑,到最後建立一個正向現金流的公司,也獲得良好賣相。

 

造局者-思考框架的威力

        這是在上班途中,聽廣播推薦的一本書,書上敘述著思考框架的應用模式並且據此來推斷事情的因果關係。整本書的內容,有許多相當具啟發性的故事組成,讓讀者了解如何在日常生活中透過學習累積自己思考框架的庫存,並且應用不同思考框架來克服現實之問題。

 

1 小時做完,1 天的工作,亞馬遜怎麼辦到的?

        本書的標題,給人一種可以很高效率完成工作的感覺,但是書中讓我比較深刻體驗到的是「不斷地讓顧客滿意」的核心概念,並以此為行動的核心概念發展出各種讓企業營運效率更好的模式。當然,這也是因為效率的提升,可以讓客戶更快地享受到服務,也讓顧客更加的滿意。因此,他們發展出一種相當高效率的營運模式,並且不斷地改善現況,使得效率高達七倍之多,這也是為什麼書的標題以「1 小時做完,1 天的工作」為主題。

 

20 個字的精準文案

        這本書是我本來想找《在 TOYOTA 學到的只要「紙1張」的整理技術》,但是發現的另外一本書。書中提供一些整理讀書心得的框架與技巧,透過刻意練習可以讓自己閱讀書籍的時候,有技巧的歸納重點,並試著產出自己的觀點。透過這些方法,可以讓自己從閱讀的消費者,進一步地變成知識的生產者。

 

原子習慣

        這本書是買來放了一陣子之後才看,書中的概念是你每天進步 1%,一年後你會進步 37 倍。每天退步1%,一年後你會退化到趨近於 0。每天一點小改變,一個好習慣將會產生複利的效應。書中提供一些觀念,協助我們持續維持習慣的方法,看完之後覺得或許可以將概念跟「刻意練習」與「完美練習」兩本書的概念融合在一起,但直到現在這個想法尚未落地。

 

 

有機會,拼就對了

        賽斯 高汀的書很熱銷,之前上 Scrum 課程的時候有好幾個概念都來自於這位行銷大師。所以,後來我就想說搜集一下他的書單。《有機會,拼就對了》是少數還買得到的兩本書之一,另外一本是《這才是行銷》。既然買到了,當然就馬上拜讀一下《成功的相反不是失敗,而是什麼都沒做》,讓自己更有行動力。後來,我在電子書平台也找到很多賽斯 高汀的書,雖然只有英文版,就買了吧,實際上真的蠻多不錯的概念!

 

經理人之道 - 技術領袖航向成長與改變的參考指南

        這本書是在天瓏書局閒晃的時候不小心撿到的書籍,一開始就是大略的翻一下,覺得書中內容不錯,適合一個技術人員職涯發展的參考手冊,與一些從小工到專家系列的書籍有些類似。

        後來,因為公司以這本書作為讀書會分享的書籍,所以就拿起來在看了一次,透過書中的一些概念在日常與一起工作的夥伴們分享,希望我們除了概念外,還可以身體力行。

 

一人公司:為什麼小而美是未來發展的趨勢與起步的思維與挑戰

        這是 Paul Jarvis 的所撰寫的兩本書,就不知道為什麼 Facebook 一直推薦這兩本書。後來,偶然在書局也看到了,就買回來看看。後來,我大概猜可能是有在搜尋賽斯 高汀的《小就是大》。書中提到,一人公司並非一個人的公司,而是應該思考我們如何透過把事情做得更好,以自動化或系統化的方式來獲取更好的收益,而不是只是一昧地擴大經營規模。透過人力的擴張,來擴張營運規模是最簡單的手段,但應該不是最好的方法。

 

思考致富聖經

        「凡是人心所能想像,並且相信的,終必能夠實現」,這句話我不知道去哪裡抄來的,很久以前放在 MSN 的暱稱列上的一段話。因為放很久,所以我自己大概記得這句話。

        後來,無意間翻到「思考致富聖經」裡面有段話,就把它買下來,後來發現跟《秘密》一書好像有點關係,主要就是從心靈開始培養自己,改變思想,付諸行動。這是一本讀了之後讓你自己心志更加堅定的書籍,讓自己不斷地付諸行動去嘗試。

        不過,我記得在其他書籍有參考到這本書,裡面似乎有一段與這本書不同。適時的承認失敗再另起爐灶,也不失為一種方式。

 

差異

        這是一本比較薄的書,買來放在那邊已經好一陣子,之前幾次都看前面兩章就放著了。後來,就有一次耐著性子慢慢的往下讀下去。書中以坦率、體貼、承擔責任與決心等不同主題,搭配著作者的故事來說明如何透過這幾個核心價值,製造自己與他人的差異。還好並不夠好,要追求卓越,就應該讓每個人都注重品質。

        書中以一根牙籤,一杯水等微小的故事,引發讀者去省思,如何讓每個人都注重品質,唯有這樣團隊才能製造出差異。就如書上的副標題,為什麼別人賺得比你多 100 倍。

 


【新年的目標】

 

整理兩門內部教材,幫助同伴提升軟實力與硬實力

 

整理兩份外部教材,作為公司搭售相關解決方案之加值服務

 

參與社群之活動,並進行兩次主題分享

星期五, 10月 22, 2021

解決 Cordova Plugin add 時發生 EACCES 權限問題

 


【問題描述】

近期遇到一個 Cordova Plugin 的問題,就是在建立 Plugin 元件時,會發生 EACCES 的權限問題。導致 Plugin 安裝失敗,失敗訊息如下:

Error: command failed with exit code EACCES

到網路上找一下解決方案,通常是提到可以執行下列指令,修改相關權限

chmod +x platforms/android/gradlew

此方法雖然可以解決 Cordova plugin 安裝的問題,但是每次要調整 Plugin 時都會需要手動調整。

【解決方案】

基本上,gradlew 是從 Android SDK 中 copy 到 cordova platforms 底下,在此過程會將相關權限資料也寫到 Android 的專案中。在 MAC 中,路徑範例如下:

/Users/{YOUR ACCOUNT}/Library/Android/sdk/tools/templates/gradle/wrapper/gradlew

cordova plugin add 指令執行時,會將該檔案複製到 Android 專案之中,所以直接調整此檔案之權限,可以避免每次都要手動調整之問題。


【參考資料】

1. Error: spawn EACCES cordova plugin add 解決辦法

星期五, 10月 15, 2021

Cordova Plugin Install Failed - cordova-plugin-mfp




最近被問到一個問題,就是在安裝 IBM Mobile Foundation Platform Plugin 時,發生了安裝失敗的錯誤。


錯誤訊息大概長得像下列這樣:


Failed to install 'cordova-plugin-mfp':undefined
Error: Failed to install plug-in for android :
Failed to install plug-in for android :
ReferenceError: hooksConsts is not defined

 

經過判斷,主要是在 cordova plugin 中,有 hooksConsts 的變數,但不知道為什麼卻是未定義的狀態。

因此,可能的原因有兩個:

(1) 目前專案中的 cordova-plugin-mfp 安裝不完整或是檔案有缺漏

(2) 要安裝的 cordova-plugin-mfp 檔案不完整或有缺漏

其中,第 (2) 項如果是透過指令以 npm 自己到網路上下載的,應該是不會發生。

第 (1) 項,則可能因為先前安裝失敗或是任何原因導致自己專案中的 Plugin 檔案有問題所致。


【解決方案】:

移除本地端的 cordova-plugin-mfp

(1) 透過 cordova plugin rm cordova-plugin-mfp 指令,進行移除

(2) 手動移除

  • 到專案中 plugins 資料夾
  • 刪除 cordova-plugin-mfp 資料夾
  • 修改 fetch.json、ios.json 及 android.json 移除 cordova-plugin-mfp 資訊 


再進行安裝,建議採用 cordova plugin add 指令進行線上安裝,如果要使用離線安裝,需要確認安裝檔案無缺漏。 


星期三, 3月 13, 2019

取得 IBM HTTP Server KDB 密碼





前一陣子,有個客戶的 SSL 憑證到期了,想要更新憑證,卻忘了當時建立的密碼。這時候可能需要重新使用 IBM 的 iKeyMan 工具再建立一次 KDB 檔案。後來,我回顧一下 KDB 建立的過程似乎有建立一個 stash 檔案,這個檔案似乎就存著密碼。

在 IBM HTTP Server 的 Config 檔案中,針對這個 KDB 的存取並沒有再特別設定密碼。所以,可以假設 stash 內就存著密碼,而且 IBM HTTP Server 可以解開這組密碼。

於是,上網找了一下是否有還原的機制,後來果然發現了相關的文章,並且實際驗證一下。

1. 我在 CentOS 的環境下建立一個 stash_decrypt.pl 檔案,內容如下:

#!/usr/bin/perl
use strict;
die "Usage: $0 <stash file>n" if $#ARGV != 0;
my $file=$ARGV[0];
open(F,$file) || die "Can't open $file: $!";
my $stash;
read F,$stash,1024;
my @unstash=map { $_^0xf5 } unpack("C*",$stash);
foreach my $c (@unstash) {
 last if $c eq 0;
 printf "%c",$c;
}
printf "\n";
2. 將 KDB 的 key.sth 檔案複製到與 stash_decrypt.pl 目錄中
3. 修改 stash_decrypt.pl 的權限為可執行
4. 執行 ./stash_decrypt.pl key.sth



最後可以看到 key.sth 檔案的密碼內容。

[參考資料]
1. https://websphereapplicationservernotes.files.wordpress.com/2012/04/websphere-doctor-7-recover-kdb-password.pdf

星期六, 12月 22, 2018

IBM MobileFirst web resources encryption

使用 IBM MobileFirst 開發行動應用程式時可以利用 MobileFirst Platform CLI 工具針對撰寫的 HTML、CSS及JavaScript 進行加密的動作。

因為 IBM MobileFirst 的專案是基於 Cordova 的專案,所以如果將 Web Resources 進行加密代表著要利用 ipa 或是 apk 進行反組譯檢視內部程式碼的困難度就增加了。

依據 IBM 官方的建議,要針對 Web Resources 進行加密動作最佳的時機點是在於應用程式開發完畢準備部署時,因為如果我們在進行 Web Resources 加密工作後執行下列指令,Web Resources 就會被解除:

  • cordova prepare
  • cordova build
  • cordova run
  • cordova emulate
  • mfpdev app webupdate
  • mfpdev app preview
所以,如果在進行上述指令後,就必須重新進行一次 Web Resources 加密的工作。

進行 mfpdev app webencrypt 程序

1. 在進行 Web Resources 加密前,先執行下列指令
  • corodva prepare
  • mfpdev app webupdate
    以便將專案程式碼同步到最新的版本。
2. 執行 mfpdev app webencrypt 指令
3. 檢視 web resources 加密後的結果


如上圖所示,在 WWW 目錄中出現 resources.zip.001 是 web resources 加密後的結果。

[參考資料]


星期三, 4月 18, 2018

Apache Cordova - Introduction


在工作上碰 Cordova 已經有蠻長的一段時間,從他還叫做 PhoneGap 的時代就已經開始接觸,目前已經有許多的客戶使用這樣的方式進行 App 開發作業。當然,在很多部分這樣的開發模型是比不上原生 (Native) 的開發,再者會用這樣開發方式的業主大多是從做 Web 開始,想要有進一步延伸出來的管道。很多時候,開發人員除了要關注 App 端之外,也需要關注 Server 的狀況,時間久了就慢慢變成要同時處理 App 與 Backend Server 的人。

雖然,看似有蠻多的需求,而且很多專案其實都找不到人可以執行。再到天瓏找找有沒有這類相關的書籍,看起來也不多。網路上的社群也沒有非常熱絡,也有可能是需求太多了大家沒空討論吧!剛好,最近有一連串的需求要進行教育訓練教材的準備,就將這些內容在網路上註記下來。

Apache Cordova 是一個行動應用開發框架的開放原始碼專案,它讓程式開發人員可以使用 Web 技術 (HTML5 + CSS3 + JavaScript) 來進行跨平台行動應用程式的開發。透過 Apache Cordova 開發出來的應用程式,可打包至各個不同的應用平台 (iOS and Android)。Cordova 應用程式會使用各平台標準的 API 來存取設備相關資訊。



什麼時候適合使用 Cordova 來進行 App 開發?
  • 假如你想要將你的應用程式拓展到不同的行動應用平台 (例如,iOS and Android),但你又不想各自開發一次,那麼使用這樣的技術會是一個好的選項。
  • 假如你是個 Web 應用工程師想要將 Web 應用程式打包並部署到不同的行動應用平台,以發布行動應用程式。
  • 假如你是一個行動應用開發工程師,對於混合式開發 (Web + Native) 感興趣,並想要開發 Web 與 Native 的溝通介面的話,可以嘗試 Cordova Plugin 的開發

下圖是 Apache Cordova 的架構圖:


Web App
在上圖中的 Web App 是我們所撰寫的程式碼,使用 HTML、JavaScript、CSS 等構成,預設的首頁是 index.html 在 HTML 內會定義參考的 CSS、JavaScript 及圖片等資源。


HTML Rendering Engine (WebView)
Cordova 應用程式透過 WebView (HTML Rendering Engine) 載入專案內的HTML 畫面作為 App 的使用者操作介面。

Cordova Plugin
Plugin 是 Cordova 裡非常重要的一部分,是 Web 與 Native 溝通的主要介面。我們可以透過 JavaScript 使用 Cordova Plugin 來存取底層的 Device API。
Apache Cordova 專案維護許多的 Plugin  可以在 Core Plugins 取得相關資訊,這些 Plugin 可以協助我們存取 Device 相關特性,例如電池、相機及通續錄等。除了這些官方的 Plugin 之外,我們也可以從 plugin search 或 npm 找到第三方的 Plugin 。

[參考資料]

星期五, 4月 13, 2018

Angular 5 Router Parameter

頁面的轉導以及相關參數的傳遞一直是 Web 應用程式發展的基礎,在 AngularJS 中,我們可以透過 Router 模組來定義各個頁面 (Component) 的繞送規則。然而,很多時候我們還需要將目前頁面上的參數往下一個頁面(Component)帶,才可以完成我們要做的工作。下列,說明如何在 AngularJS 裡進行參數傳遞的範例:

const routes: Routes = [
 { path: 'cmpa/:id', component: ComponentA },
 { path: 'cmpb/edit', component: ComponentB },
];
例如上述的 path/:id 即定義了一個 id 的變數,以變傳到 ComponentA 中。

2. 如何在 ComponentA 中接收 :id 參數?

import {ActivatedRoute} from "@angular/router";
.
.
.
constructor(private route: ActivatedRoute) {
    this.route.params.subscribe( params => console.log(params) );
}
使用 ActivateRoute 以取得相關參數資訊。在上述程式中,params 即為傳入的參數內容。


[參考資料]
1. https://codecraft.tv/courses/angular/routing/parameterised-routes/

星期三, 4月 11, 2018

IBM Application Center Push Notification of Application Update for Android and iOS


IBM Application Center Client 可以在應用程式更新時進行推播服務,告訴使用者已經有新版的應用程式上架,引導使用者進行下載新版的工作。

要完成這樣的功能,必須針對產品進行些許的設定,進一步說明如下:

1. Server 的設定
   IBM Application Center 可以安裝在 WebSphere Application Server、WebSphere Liberty Profile 以及 Tomcat 上。

   本文以 WebSphere Liberty 為例,需要在 server.xml 裡進行下列 JNDI 的設定:

Android:
<jndiEntry jndiName="ibm.appcenter.push.schedule.period.unit" value="hours" />
<jndiEntry jndiName="ibm.appcenter.push.schedule.period.amount value="2" />
<jndiEntry jndiName="ibm.appcenter.gcm.signature.googleapikey" value="AAAAX_7jiec:........" />
     其中 「ibm.appcenter.push.schedule.period.unit」的值建議使用 「hours」,避免伺服器過於頻繁檢查是否要進行推播,影響效能。(在測試的時候可以設定 seconds 以增進測試的效率)「ibm.appcenter.gcm.signature.googleapikey」可以使用 Firebase Cloud Message 上的 Server Key 來進行設定作業。

iOS 設定:
<jndiEntry jndiName="ibm.appcenter.apns.p12.certificate.location"  
     value='"D:/IBM/WebSphere/Liberty/usr/servers/MFPSrv2/PushNotification.p12"'/>

<jndiEntry jndiName="ibm.appcenter.apns.p12.certificate.password"  
     value='"yourpassword"'/>

<jndiEntry jndiName="ibm.appcenter.apns.p12.certificate.isDevelopmentCertificate"  
     value='"false"'/>
PushNotification.p12 憑證可以從 Apple Developer Account 針對包版的憑證進行 Push Notification 相關設定,設定完成後可以產生一個 .cer 檔案。將該 .cer 檔案匯入 MAC 上的「鑰匙圈存取」,再將其匯出成 p12 檔案,並設定密碼。

2. IBM App Center Client
   修改 CordovaAppCenterClient 內的 config.json 檔案內的「gcmProjectId」值。
   請建立一個 Firebase 專案,並且在專案設定頁面中進入 Cloud Messaging 的設定畫面,將「寄件者 id」抄出,並修改 gcmProjectId 值。

3. 進行測試
   接著我們可以上傳一個新的 ipa 或 apk 檔案,在上傳的時候記得將 Recommended 的 checkbox 打勾。接著,在一定時間內應該可以收到應用程式上版的推播通知。

4. 問題排解
   以上動作最好是在 App Center 上線前就完成,如果有人已經下載了 App 因相關推播內容設定值是錯誤的,例如:gcmProjectId 的值,那麼這時候可能就需要重置一下 App Center 的資料了。
 

參考資料:
[1] https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/appcenter/push-notifications/
[2] https://www.ibm.com/support/knowledgecenter/en/SSHS8R_8.0.0/com.ibm.worklight.appcenter.doc/appcenter/t_ac_gcm_connect.html

星期一, 11月 20, 2017

Odd-e Certified ScrumMaster 心得分享 3 - 快速交付,小步快跑

快速交付,小步快跑


雖然,認識 Agile 或是 Scrum 已經有一段時間,自認對於快速交付及小步快跑也有一定程度的理解。但是,卻沒有像這次在課堂上感受這麼深刻。

在課堂上,我們進行了一個 workshop,規範了一個明確的產出物作為目標,然後我們有 30 分鐘作為一個 Sprint 來完成一個可交付的產出。時間相當的緊湊,事後想想,如果採用 Scrum 的模型來執行,我們應該每 3 分鐘或 6 分鐘應該進行一次進度的同步工作。然後,在每 3 分鐘到 6 分鐘的時間,為最後的產出做努力。

但是,相場實際的狀況卻是,大家開始討論起該怎麼完成這個產品。整個過程中,我們大約有一半的時間在討論與規劃,就是還沒針對最終產出物捲起袖子開幹。等到,大家討論出一個方針後,我們開始進行製作產品的相關工作。這個 workshop 最有趣的地方,就在於他還必須完成一個 Deployed 的動作。

我們必須讓產品上線,這個 Sprint 才能夠算成功。在製作產品完成後,我們還有五分鐘左右。於是,我們嘗試進行部署。卻發現部署的時間比我們想像的還要久很多。最終,這個 Sprint 我們宣告失敗。

這裡面,其實有很多隱含許多的觀念,底下是自己回顧的心得:

1. 以終為始:我們應該快速地,發布一版到正式環境,以確認團隊了解整個發布程序,並且排除發佈時的風險。對應到實際的案例上,軟體工程師應該都很常遇到,這東西在我們本地端執行都沒問題,但是一移轉到正式環境問題就一大堆。透過這樣的思維邏輯,我們可以更早地面對正式環境的狀況,不會在做了很久之後,才發現有東西需要調整。

2. 用最短的時間產出 End to End 的價值,頻繁地發佈。快速地取得回饋,要比周詳的計畫,但是做了很久專案延宕,無法上線取得價值來說,更有意義。

3. 在之前協同合作時有提到,以拔河為例。當只有一個人的時候,你肯定會用上 100% 的力量。但是,當人一多的時候,大家可能就有所保留。在整個 workshop 中,我們應該沒有發揮整體團隊 100% 的戰力。

4. 快速交付,小步快跑的開發習慣是必須要一段時間練習,讓自己逐漸熟悉這種模式的思維,以任務下來時大家的反應來看。我們都需要一些時間來精熟這樣的模式。

星期五, 11月 17, 2017

Odd-e Certified ScrumMaster 心得分享 2 - 順暢的溝通




順暢的溝通

在二戰之前,法國的陸軍部隊擁有實力堅強的裝甲車設備。但是,在二戰的時候,卻被德國的陸軍打敗。據說,這中間的關鍵就是「溝通」。當時,法國的裝甲車部隊使用旗語在不同的坦克車之間進行溝通,而德國的部隊則是使用「無線電」進行溝通的工作。

在旗語跟無線電之間,我們可以清楚的知道這兩個工具產生的溝通效率不同。使用旗語時,溝通的效果有限,除了距離的限制之外。在作戰期間,坦克車的操作人員也很難時時刻刻探出頭來檢視其他坦克之間的狀況。這使得法國的坦克車部隊,像是一盤散沙,雖然裝備強大但是沒有辦法集中戰力,發揮團隊的力量。

反觀,德國的部隊,因為可以很快的進行有效的溝通工作。當其中一部坦克,打通了某個關卡之後,可以快速地通知其他的夥伴集結,快速地針對現況做出應對與改變,近一步達到戰略上的效果,而獲得最後的勝利。

對比軟體的工作模式,我們可以看到一個團隊雖然共同在打造一個產品,或是執行一個專案。團隊成員之間也有透過會議來進行資訊的同步。但,感覺很多時候,成員跟成員之間還是彼此不知道對方在做什麼,進行怎樣的工作,如何進行。

這使得專案團隊之間,對於產生的問題,或是良好的工法無法有效地快速傳播。所以,我們現在是用「旗語」還是「無線電」?

星期一, 11月 13, 2017

Odd-e Certified ScrumMaster 心得分享 1 - 協同合作



大約在兩年前吧,有一次到趨勢科技參加一個 Scrum 的分享會議,那時候第一次遇到 Daniel 老師。那次會議中分享了如何組成一個 Scrum 團隊,說明了 Cross Function Team 如何組建。

之後,也經常在社群裡,聽聞許多人對於 Daniel 老師的課程讚譽有加,所以當社群內出現了報名資訊後,我就立馬用手機完成了報名程序。接著,過著一段非常忙碌的專案執行生活。一直到上課前一天,都還有著許多工作上煩人的事。

但是,既然都已經報名了這個課程,就必須讓自己放空好好的沈浸在課程之中,以發揮學習最大的效益。

在課程中,我記下了大量的資訊,每一個 Key Word 都有一些啟發,基於養成習慣持續性的交付這項學習心得來看,只好把心得的部分切成許多小的 story 來 release 了!

協同合作

   Scrum 本來就是延伸自橄欖球運動中的爭球,所以一直以來我認為一個良好的 Scrum Team 就是要像一個合作無間的球隊,成員間彼此有默契,能夠互相合作。但是,一個團隊的協同合作就像拔河一樣,當只有一個人的時候,你可能會發揮 100% 的力量。如果,現在我們有一個團隊一起進行,每個人的力量貢獻度就不一定是 100%。

   「協同合作」是我在第一天筆記時,寫下的第一個關鍵字。在第三天,我們在討論什麼是一個好的 Product Backlog 時,卻突然有了體會。在哪份 Product Backlog Item 上,已分配好的工作都有指定一個負責人。

   假設,今天我們在談的是協同合作。一個 Product Backlog Item 為何是指定給特定人士來完成? Product Backlog Item 是一個 User Story,是一個對於客戶來說有價值的 End to End 功能特性的交付。這其中涵蓋許多的細節,包含分析、設計、開發、測試等一切我們必須進行的工作,也是一個交付的目標。

  既然,這是一個目標性的交付,應該是由團隊一起協同合作,完成一個 Product Backlog Item 的交付,否則團隊會在什麼時間點進行合作?

  大家只是各自處理各自的任務,是一個不協同合作的偽團隊罷了!仔細想想,這也是最常看到的分工模式。雖然,大家一起在為一個產品或專案努力,但是彼此之間卻互不相干,不互相幫助。

  一個良好的團隊,應該是共同為一個目標努力。中間有什麼問題需要協助,需要補位,喊一聲就會有人接替。我想,在這樣一個團隊下工作,應該是相當愉快的一件事。所以,也要好好跟團隊同仁分享一下這樣的概念,促進團隊在協同合作上的成長。



星期四, 6月 22, 2017

IBM MobileFirst 7.1 拒絕存取


延續之前 MobileFirst 7.1 的 Server Farm 機制無法正常啟用,經過好一陣子與 IBM Lab 之間的往返,還是沒有一個好的解決方案。


所以,只好考慮直接裝一套新的 Server,並且把專案移轉到新的伺服器上來。
但是,在移轉之後卻出現如上圖所示的錯誤。

因為,通常我們會在 App 啟動時,使用 WL.Client.connect 與 MobileFirst 伺服器連線,以確認 Client 與 Server 之間的版本,並檢查管理者有沒有設定任何通知訊息。

但是,在移轉後,App 端會出現「Access Denied」的錯誤,無法正常啟動 App。

伺服器端,也可以觀察到下列的錯誤訊息:
FWLSE0335E: Authorization failed: 
ClientId f5ac9a8cda443cfca33d1e7f926a71f90f8c67a1 was not found 
on the server.
這個情況,可以透過移除該 App 並且重新安裝,來解除此問題。

所以,我們大概可以推測,MobileFirst 的 Client 端在跟 Server 連結之後,會在手機端留下一些資訊。這些資訊,應該是 MobileFirst 用來確保安全的機制。

1. 可以避免,我們連接到的 Server 與之前的不同
2. 從伺服器端的角度來看,如果先前該手機已經跟伺服器註冊過。但是,現在我們卻無法在伺服器上找到該 ClientId 的話。這個裝置是不是該被視為有問題的裝置。

當然,這種安全機制,有時候還是會造成我們的困擾。

所以,為了避免要求大量使用者重新安裝 App,我們可以採取下列兩種方案,來解決此問題。

1. 在 MobileFirst 7.1 之後,與先前開始有所不同,採用 Session Independent 作為伺服器運作的預設機制。當採用 Session Independent 時,MobileFirst 的相關資訊就會被存於資料庫中。所以,必須調整 MobileFirst 處理 Session 的機制,讓資訊是存於記憶體之中。這樣,就可以解決上述遇到的問題。但是,當採用這樣的機制,勢必會影響到後續 Server 做平行的擴充。所以,除非是以單一機器提供服務,不然不建議採用這個解決方案。

2. 既然,App 移除重裝之後就可以解決此問題。那麼,就是需要在程式中加上一段清除手機上暫存的這些資訊,如此就可以使 App 恢復正常運作。經測試,先前假設沒錯,就是有一段資料被存在手機上。移除之後,就可以正常與伺服器連線。

「參考資料」
1. MobileFirst 7.1 Server Access Denied when using WL.Client.connect API

星期一, 3月 27, 2017

IBM MobileFirst 7.1 WebSphere Liberty Server Farm Unresponsive

前一陣子有客戶反應,他們公司的 MobileFirst Server 無法正常啟動。

於是,開始這段伺服器搶救的過程。

1. 因為 console.log 及 message.log 中都沒有紀錄錯誤訊息,所以為了看更多的資訊,必須打開 trace.log

需要再 server.xml 中加上下列資訊,就可以產生 trace.log 了!
<logging maxfiles="10" maxfilesize="20" 
         tracefilename="trace.log" 
         traceformat="BASIC" 
  tracespecification="com.worklight.*=all:com.worklight.*=all:*=info">
</logging>
中間經歷了很多次重開的過程,Server 就是無法順利啟動。

在沒辦法之下,我只好使用 MobileFirst 的 Configuration-Tool 試著用 update 的方式,中置一下 worklight admin 服務及 runtime environment 的三個 war 檔案。

突然,其中一部 Server 正常啟動了。

心想,應該修好了!

結果在啟動另一個 Server 時,卻卡住了!

這時候剛剛啟動的 Server 也無法正常運作。

觀察一下 tracelog,後來我發現每 30 秒會出現一次下列紀錄

com.worklight.core.clustering.ClusterSynchronizationTask
解到這邊,我一直觀察資料庫內的資料跟伺服器運作的模式。
感覺,就是同步作業失敗,然後一直重做。

上網找了一下資料,看起來跟這個問題比較像的是:
IBM MobileFirst 7.1.0 Liberty Server Farm Unresponsive

但是,內文也是說重建 Server Instance 跟重新設定 Server Farm 就好了!

目前,重建後只能讓單一伺服器恢復運作。
只要想同時啟動 Server Farm 中的兩個伺服器,就會陷入同步失敗的問題。

現在還在等 IBM 原廠回覆此問題的正確解法。

星期二, 8月 09, 2016

Kendo Grid 教學 4 - 解決 REST Service 回應 HTTP 403

在先前「RestTemplate 無法呼叫 Rest Service」的文章中有提到,有些後台被 Spring Security 保護著,並啟用 Cross-site request forgery (CSRF) 的保護機制,並免他人因為知道服務的端點,就可以直接呼叫相關的服務。

Kendo UI 可以透過 Datasource 中 transport 的屬性設定,可以完成資料的讀取及寫入工作。針對新增、修改、刪除及查詢的部分,分別提供 create、update、destory 及 read 的 function 來進行相關作業的處理。
    transport:{
        create:{...},
        update:{...},
        destroy{...},
        read{...}
    }
開發人員可透過上述設定,完成 kendo grid 上 CRUD 的相關動作。

但是,當我們碰上後端具有 CSRF 保護的服務時,可能會出現 「HTTP 403 : Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'」的錯誤訊息。

這代表,我們正常地呼叫後端的服務。以整合 Spring Security 來說,當我們完成登入後,可以從 Request Header 中觀察到,HTTP Request 都會帶著兩個 Cookies 的資訊,分別是 JSESSIONID 及 XSRF-TOKEN 資訊。

然後,我們再看一下錯誤的訊息「HTTP 403 : Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'」。看起來,後端要的服務需要我們的 Header 送一個 X-CSRF-TOKEN 的資訊過去。上網找一下參考資料「Invalid CSRF Token 'null' 解決方案」看起來也是這樣說明沒錯。而且,X-CSRF-TOKEN 的內容跟 XSRF-TOKEN 一樣 (一樣的東西,底層竟然沒有自己處理掉 .... 看來還要找時間看看到底為什麼有這樣的限制)。 

所以,接著要思考的是如何在 Kendo Grid 呼叫後端服務時,將  X-CSRF-TOKEN 動態的塞入。後來,我在 「Transport and basic authentication」找到了解答。我們可以在 create、update、destroy 跟 read 等方法上加上 「beforeSend」的方法來加入 X-CSRF-TOKEN。

beforeSend: function(req){
    req.setRequestHeader('X-XSRF-TOKEN', $cookies.get('XSRF-TOKEN'));
}
如此一來,就可以正常使用後端服務了!

[參考資料]
1. 跨網站請求偽造
2. Invalid CSRF Token 'null' 解決方案
3. Transport and basic authentication

星期一, 8月 08, 2016

RestTemplate 無法呼叫 Rest Service

最近有人問我一個問題,現象是他的應用程式呼叫被 Spring Security 保護的服務時,如果未將 csrf disable,系統就無法正常運作。

Spring Security 啟用 CSRF 後可保護 Server Side 的 Resource,避免跨網域攻擊 (從別的機器發出 Request 以取得後端的資訊)。所以,當 Spring Security 啟用 CSRF 後,我們會在前端的頁面加上

   <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

以便,證明我們是從同一個網域發送的請求。

然而,這個問題卻不是上述原因造成!第一時間的猜想錯誤,所以我就開始檢視程式碼內容,來看看到底那邊出了問題。

後來,發現在後端的程式中有一段使用 RestTemplate 去呼叫 REST 服務。基本上,如果在內部應該可以直接呼叫相關的物件,而不需要透過 RestTemplate 來進行呼叫 (多繞了一圈)。不過,依照範例來看是個教學程式,所以就先不討論合理性的問題。

RestTemplate 其實是一個增強化的 HTTP Client ,所以在使用 RestTemplate 時我們可以想像自己開了一個新的瀏覽器,然後存取該服務。此時,RestTemplate 中根本就沒有儲存相關的 Session。因為他的 Request 中沒有帶任何經過驗證的資訊。所以,會被 Spring Security 視為不合法的存取。

我們必須在 RestTemplate 中加入一些資訊,才可讓這個呼叫合法。相關資訊,可參考下列參考資訊的網址。

HttpHeaders headers = new HttpHeaders();
headers.add("cookie", req.getHeader("cookie"));
HttpEntity requestEntity = new HttpEntity(null, headers);
ResponseEntity rssResponse =
restTemplate.exchange( your_service_url,
HttpMethod.GET,
requestEntity, List.class);
1. 建立 HttpHeader 物件,並將 request header 中的 cookie 值取出,設定到自己建立的 HttpHeader 中。(因為 Session 就存在這裡)

2. 建立 HttpEntity 物件,並利用先前建立的 HttpHeader 進行初始化。

3. 使用 restTemplate 呼叫後端服務,取得 ResponseEntity 以進行後續邏輯運算


[參考資料]

星期三, 8月 03, 2016

Kendo Grid 教學 3 - 建立新增功能

在 「Kendo Grid 教學 2 - Inline Edit」的文章中提到怎麼樣進行 inline edit 的工作。但是,以先前提供的範例來看,並未交代如何進行新增的作業。

但是,如果有依據參考資料進入 「Kendo Grid Grid Inline Edit Demo」檢視範官方的範例程式的話,應該已經發現如何把「Add New Record」的按鈕加上去。

$scope.mainGridOptions = {
    dataSource: $scope.datasource,
    pageable: true,
         height: 300,
toolbar: ["create"],
    columns: [
     { field: "id",  title: "商品編號", width: "120px"},
     { field: "name", title: "商品名稱", width: "120px" },
      { field: "price", title: "商品價格", width: "120px"},
{ command: ["edit", "destroy"], title: "&nbsp;", width: "250px" }
          ],
editable: 'inline'
};
};
在原本 mainGridOptions 中,加入 toolbar 的元素,並指定要使用 create 功能,就可以像官方的範例,有一個 「Add New Record」的按鈕。

當這個按鈕按下去之後,以 inline 編輯模式來看,Kendo Grid 的第一行會進入編輯模式,讓我們輸入資料後進行新增作業。

[參考資料]
1. Kendo Grid Grid Inline Edit Demo

星期三, 7月 27, 2016

Kendo Grid 教學 2 - Inline Edit

在 「Kendo Grid 教學 1 - 建立列表」的文章中,有兩個主要的變數要設定,以便讓 Kendo Grid 可以運作起來,並透過 Rest Service 拿到列表資訊。分別是 datasource 與 mainGridOptions。

Datasource

其中,datasource 可以看作是 kendo grid 的資料來源。在先前的文章中,設定了 transport 與 schema  兩個主要屬性。

transport


透過 transport 的屬性設定,可以完成資料的讀取及寫入工作。針對新增、修改、刪除及查詢的部分,分別提供 create、update、destory 及 read 的 function 來進行相關作業的處理。
    transport:{
        create:{...},
        update:{...},
        destroy{...},
        read{...}
    }
開發人員可透過上述設定,完成 kendo grid 上 CRUD 的相關動作。

schema

Schema 在 Datasource 中扮演兩個重要的角色:

  1. 透過 schema.model.fields 定義 kendo grid 的資料模型,設定排序 (sorting)、篩選 (filtering),並確保使用對應的編輯元件,例如: 數字輸入框對應到數字型別的資料。
  2. 透過 schema.model.id 定義 kendo grid 中的 id 欄位,以確保新增、修改、刪除等工作可以正確執行。

schema: {
      model: {
           id: "id", 
           fields: {
                 id: { editable: false, nullable: true, defaultValue: null},
                 name: {validation: { required: true }},
                 price: { type: 'number', defaultValue: 0, validation: { required: true, min: 0}}
           }
       }
}



parameterMap

在 Kendo Grid 與後端服務整合的部分,透過設定可以採用 json, jsonp, odata 等不同資料模式。所以,在請求資料 (request) 真的往後送之前,我們需要透過 parameterMap function 幫我們處理資料的轉置問題。

下列為,parameterMap 中的範例程式。因為 read 方法不需要傳參數即可拿到資料,所以在範例程式中,我們把 read 方法過濾掉。然而,在 create, update 及 destory 的部分,我們將前端 Form 內的第一個元素取出 (因為 options.models 預設是 array),並將其當作參數往後面的服務拋送。

parameterMap: function(options, operation) {
if (operation !== "read" && options.models) {
        return JSON.stringify(options.models[0]);
     }
 }


mainGridOptions


在前一篇文章中,我們有看到下列 mainGridOptions 之設定。設定的內容可以進一步分成幾個區塊。


  1. 設定 datasource,作為 kendo grid 的資料來源
  2. 利用 pageable 設定是否分頁
  3. 透過 height 設定 kendo grid 的高度
  4. 透過 columns 設定 kendo grid 的表頭應該呈現什麼
    4.1. filed 的設定會與 datasource 底下 schema 內的 fields 做呼應,相同名稱的會對在一起,是一種透過設定抓相對應資料的概念。
  5. columns 中還有一個設定為 command,在每一列上會顯示編輯 (edit) 與刪除 (destory) 的按鈕
  6. editable 設定為 inline 代表該 grid 會使用 inline 的方式進行編輯作業
      其中,標紅色字樣的部分是本次要做 inline edit 新加的部分


$scope.mainGridOptions = {
    dataSource: $scope.datasource,
    pageable: true,
         height: 300,
    columns: [
     { field: "id",  title: "商品編號", width: "120px"},
     { field: "name", title: "商品名稱", width: "120px" },
      { field: "price", title: "商品價格", width: "120px"},
{ command: ["edit", "destroy"], title: "&nbsp;", width: "250px" }
          ],
editable: 'inline'
};
};

建立對應新增、修改、刪除、查詢的方法

在本文前面有提到 datasource 中的 transport 就是讓我們進行 create、update、destory 及 read 的 function 撰寫。

在本文中,以 update 為例:

1. url : 記錄遠端服務的端點
2. type:  使用 HTTP  通訊協定的方法 (例如:GET, PUT, POST, DELETE 等)
3. contentType 傳輸內容的類型
4. complete function: 服務呼叫成功後,要做的相關動作可以寫在此處
5. error function: 服務呼叫失敗後,要做的相關動作可以寫在此處

update: {
     url: "your service endpoint",
     type: "PUT",
     dataType: "json",
     contentType: 'application/json',
     complete: function (data) {
// 呼叫服務成功後,要做什麼事
     },
     error: function (xhr, error) {
         // 呼叫服務失敗後,要做什麼事
     }
}

其他,關於 destory 及 create 也是採用相同的方式進行撰寫。雖然,在這裡並沒有說明如何建立一筆新的資料。但,後面還會有其他文章提到。

備註:
我們做 Rest Service 的時候,可能經常將 create、update 及 delete 的 method 預設為不回傳值。以 Java 來說,就是宣告回傳的是 void。

但是,這樣可能會導致 kendo grid 不 work。所以,我們必須回傳一個 JSON 字串回來。針對,create 及 update 的方法,需要回傳新增或是更新的那個物件回來。避免 kendo grid 呈現一個空白列在那邊。

有關 inline edit 的實際 demo,可以進一步參考官網上 Inline Edit 的範例。

「參考資料」
1. Kendo Grid CRUD Data Operation
2. Kendo Grid Grid Inline Edit Demo

Kendo Grid 教學 1 - 建立列表

近年來,前端 javascript 的技術突飛猛進,有許多的 framework 出現,學都學不完。而在,公司的專案需求上,我們需要開始研究 Kendo UI 這套框架。

Grid View 是我們建置 Web 應用程式中相當常用的 UI 元件。記得十多年前,同時接觸 .NET 與 Java 時,總覺得為什麼 .NET 上做一個 Grid View 相當容易,而在 Java 上卻需要自己寫那麼多程式。一個 Page 一個 Page  一直寫著重覆類似的程式碼。

雖然知道,這裡應該要被元件化,但始終沒有下手去做這類整理的事。那時候,還是以 Server Page 為主的時代。AJAX 的興起是在那之後兩三年的事情。

而到了現在,檯面上已經有非常多這種前端的元件,而且透過 javascript 技術的發展。現在,前端的頁面已經鮮少使用 Server Page 相關的 Tag 。而改由 HTML5 + javascript + css 來進行所有的事情。至於後端採用什麼語言 (C#, Java or PHP) 似乎已經沒那麼重要,也徹底實現 Web 端的 MVC 概念。

底下,我們就建立一系列的文章,來探討使用 Kendo UI 的心路歷程:

1. 下載 kendo ui 的相關套件 Kendo UI Download Free Trial
 
解壓縮後,將套件內的 js 與  styles 資料夾放到專案目錄中。以我自己的範例來看,這兩個資料夾放在 [your project]/webapp/resources/lib/ui/ 底下。

2. 下載 kendo.all.min.js

我是認為 kendo.all.min.js 應該涵蓋在第一步驟中所下載的內容裡。但是,不知道為什麼沒有。可能這樣可以收一點顧問費,畢竟它是需要付費的!所以,只好從官網的範例偷偷把 js 檔載回來。一樣放在 [your project]/webapp/resources/lib/ui/ 底下。

此使,該目錄下有 js 及 styles 兩個資料夾再加上 kendo.all.min.js 這個檔案。

3. 建立後端 RESTFUL Services,讓 Service 回傳下列這串 JSON 訊息回來

[
  {"id":4,"name":"Starbucks","price":300},
  {"id":5,"name":"BrownCafe","price":200},
  {"id":6,"name":"CityCafe","price":100}
]
4. 撰寫前端頁面

4.1. CSS 與 JS 引用之宣告

<link rel="stylesheet" href="./resources/scripts/lib/ui/styles/kendo.common.min.css" />
<link rel="stylesheet" href="./resources/scripts/lib/ui/styles/kendo.default.min.css" />
<link rel="stylesheet" href="./resources/scripts/lib/ui/styles/kendo.default.mobile.min.css" />
<script src="./resources/scripts/lib/ui/js/jquery.min.js"></script>
<script src="./resources/scripts/lib/ui/js/angular.min.js"></script>
<script src="./resources/scripts/lib/ui/kendo.all.min.js"></script>
4.2. 在 HTML 頁面上,宣告要使用 Kendo Grid (以 AngularJS 為範例,官網上還有許多 JQuery 的範例)

<div id="example" >
    <div ng-controller="MyCtrl">
        <kendo-grid options="mainGridOptions">
        </kendo-grid>
    </div>
</div>
4.3. AngularJS

4.3.1. kendo UI 元件在 AngularJS 中被實作成 directives 所以當我們要使用 kendo ui 時需要注入 kendo.directives
var app = angular.module('myApp', ['kendo.directives']);
4.3.2. Controller

app.controller('MyCtrl', function($scope){
$scope.datasource = {
transport: {
read: {
url: [your service address]
dataType: "json"
}
},
schema: {  
model: {
                 fields: {
                    id: { editable: false},
                    name: {validation: { required: true }},
                        price: { type: 'number', defaultValue: 0, validation: { required: true, min: 0}}
                    }
                }
            }
};
$scope.mainGridOptions = {
    dataSource: $scope.datasource,
    pageable: true,
         height: 300,
    columns: [
     { field: "id",  title: "商品編號", width: "120px"},
     { field: "name", title: "商品名稱", width: "120px" },
      { field: "price", title: "商品價格", width: "120px"},
          ]
};
};
依據此方式,即可完成下列表格之設計。雖然,做了很多事才弄出這張表。但是,使用這個元件可以讓後續新增、修改跟刪除的 UI 操作快很多,只需要再加上一些設定。




[參考資料]
1. Kendo UI - Grid Example

星期一, 7月 25, 2016

IBM MobileFirst 7.1 DirectUpdate 失效


最近,有客戶反應他們的 MobileFirst Server 升級到 7.1 後,Direct Update 僅能更新一次,之後就無法再進行更新。

因為客戶說,他們當天要準備上線作業,這個功能必須能正常運作。所以,我跟同事就開始研究問題可能發生的原因。

根據客戶描述,一開始的時候是部署 wlapp 到 MobileFirst Console 時會出現警告訊息如下:


FWLSE3210W: Environment: android of application [YOUR Application] 
version 1.1 has been deployed with a different version of the native 
MobileFirst SDK. 

Direct updates will no longer be available for existing clients with 
other versions of the MobileFirst SDK. 

To Continue to use direct updates, increment the app version, publish it 
to the public app store, deploy to the server, and (optionally) block/notify 
older versions of the app to enforce customers to upgrade to the new version 
from the app store.

針對上述部分,需要修改 wlapp 的版本。因為 version 1.1 的時候是使用 MobileFirst 先前的版本進行打包。依據 IBM 對於 Direct Update 的定義來看,如果有 Native SDK 更新的話,是必須整個 App 重新下載安裝,而非僅更新 Web Content 就可以。

而升級的時候,IBM MobileFirst 底層的 SDK 有可能被更換掉,所以會出現上述訊息。故,我們將 version 1.1 換成 1.2。如此,在部署 wlapp 時,就不會有 FWLSE3210W 的警告訊息。

但是,上述問題解決後。客戶驗證 Direct Update 的系統發現還是只能更新一次。所以,問題實際上還沒有被解決。

後來,我們又發現 worklight.properties 檔案中,有一個參數是 wl.realm.expiration.directUpdate 的值預設為 3600 (一小時內,Direct Update 不會再生效)。在舊版的值似乎是 -1。但是,目前設定 -1  MobileFirst Server 又無法正常啟動。所以,只好設定個 60 秒 (反正改程式應該都會超過一分鐘吧!)。

修改後,重新更新 MobileFirst Server 的 Runtime WAR 檔之後,Direct Update 的更新頻率就換成1分鐘後可重覆更新的模式。

[參考資料]
1. The direct update doesn't work in MobileFirst Studio v7.1


星期四, 8月 13, 2015

Certificate Scrum Developer 認證課程心得




最近剛上完 Certificate Scrum Developer 課程,授課老師是 Jacky Shen。在這門課程當中討論「持續整合」,「TDD」,「重構」,「Simple Design」,「Git version control」,「Pair Programming」等相關議題。

在最近一年的時間裡,我陸續取得 PMI-ACP,CSPO 及CSM等證照。有了這些知識,卻感覺還少那麼一點東西。Scrum 團隊有 Product Owner,Scrum  Master 及 Development Team 這三個角色。其中,Team 的人數最多,卻很少有人坐下來好好地把什麼是一個好的 Development Team,以及我們該如何成為這樣的團隊。

所以,有 Product Owner 的認證,有 Scrum Master 的認證,當然我們也需要知道如何培養自己或是團隊成為一個敏捷開發團隊成員之一。所以,基於一個這樣的念頭,讓我在颱風隔天連續上了兩天 12 小時的馬拉松課程。


從整個課程的內容來看,初步可以將課程內容分成兩個主要觀念。

          (1) 專注品質

1.1. 在課程中有提到許多好的程式概念,例如:程式碼要讓其他人一目了然,快速地了解。程式碼要可被信賴。程式碼必須是可維護的。

1.2. Test Driven Development: 確保每一段程式碼都有其對應可執行的測試案例。

1.3. 頻繁且持續地測試,保持程式碼永遠是可動的,並且合於需求。

1.4. 透過重構,不斷地改善程式碼的品質,降低程式的壞味道。

          (2) 減少浪費

2.1. 不做過度的設計,減少浪費。

2.2. 花時間進行重構,可以降低日後一次性大規模的調整。(這讓我想起「不要惹公司的程式設計師啊」。)

2.3. 建立自動化的測試案例,可以降低人為測試不斷重工的浪費。


但是,我認為上述的內容還不是最重要的。在 Scrum Alliance 的網站上,說明怎樣是一個成功的 CSD?

A successful Scrum Developer is committed to continuous improvement.

課程最重要的內容是

讀書、練習、分享

努力不懈地提升自己,透過練習不斷地提升自己實務的能力,並且將這些知識分享出去,發揮影響力,讓團隊可以更精進。

最後,感謝長宏的團隊促成以及一起上完這兩天馬拉松式課程的同學們,讓這次Certificate Scrum Developer 課程能在百般的艱難下開課成功。感謝 Jacky  老師充實的課程使大家獲益良多。