2020/03/02

在 Windows 上用 Visual Studio 2019 開發 Linux C++ 程式

情境是這樣的

我已經存在一個 repository 寫好了 Makefile
可以在 Linux 上透過 make 編譯出執行檔
想用 Visual Studio 開發並 debug 這樣一個程式

手上有的環境跟 GitHub repository

其實 Microsoft 官方文件介紹得非常清楚
跟著文件做就可以很簡單的建立一套開發環境

首先在 Visual Studio 上必須先安裝 Linux development with C++ 的 workload

安裝 Linux development with C++ in vs2019

接著在你的 Linux 系統上確認有安裝需要的套件
g++, gdb, rsync, zip, make, openssh-server 等

然後啟動 Visual Studio 後進入 Tools > Options 選單
在 Cross Platform > Connection Manager 頁面按下 Add 按鈕
並輸入連線的資訊
當然可以使用 SSH Private Key 的方式做認證

設定與 Linux 的連線

輸入與 Linux 連線的資訊

接著就可以建立新的專案
選擇 Makefile Project (for Linux) template
路徑設定在我們已經有的 repository 資料夾內
因為後續路徑關係
我們把 .sln 跟 .vcxproj 兩個檔案放到跟 Makefile 同一層

建立 Makefile Project

選擇在原本 Linux 程式的 repository 資料夾下建立

把 .sln 與 .vcxproj 移動到 Makefile 同目錄

再來把所有相關的 sources 跟 Makefile 都加入專案內
接著進入 Project > Properties 選單
在 Remote Build 頁面的 Build Command Line 設定填入 make all
最後按下 Build Solution (Ctrl + Shift + B)

加入已存在的檔案

設定 Remote Build

可以看到執行建置時, 複製到遠端 Linux 並執行 make all

這時候可以在 Linux 裡面發現被複製過去的檔案
default 會在使用者的 home 路徑下的 projects 資料夾
這個路徑也能在 Project Properties 裡修改

設定複製到遠端 Linux 的路徑

檔案被複製到 Linux 上的樣子

最後設定 debugging 的資訊
跟以往在 Windows 上的設定類似
不過路徑改為遠端 Linux 上的
執行沒問題後就可以加上一些 breakpoints 來試試看吧

設定 debugging 啟動資訊

用 Visual Studio 2019 debug Linux C++ 程式的過程

我沒有使用更多深入的功能
但就目前有接觸到的基本功能來說
體驗算是與原本開發 Windows C++ 程式非常一致
很快就可以上手

2020/02/17

[自己的 Hackathon] L10 盃黑客松之即時開票系統 - 回顧

簡單回顧一下這次自己的黑客松

Azure Cost

Google API Dashboard
最後因為 Azure Functions 沒有真的跑在雲端上
所以只有 Storage 被收了點錢
Google Sheets API 打了四千多次

What went well?


能快速從文件
以及可搜尋到的教學材料中學習
只有在最後上了雲端後
不知道為什麼 Azure Functions 會一直取得同樣的值
但運氣很好的有發現可以用本機執行替代

再者是有先簡單規劃要完成的小項目
這樣可以在短時間內聚焦目標
做比較快的衝刺

What needs improvement?


這次我建立一個 HTTP 觸發的 Azure Functions 當作測試使用
但是如果使用單元測試
我相信在開發核心邏輯上應該可以做得更快
畢竟每次測試都必須在本機啟動 Azure Functions
雖然沒有特別慢
但我假設單元測試應該可以執行得更快
對於除錯或是快速迭代很有幫助
運氣不錯這次重構並沒有改出問題
(是的, 我有花時間重構)

用 Visual Studio Code 寫 python
不能說非常好用
只有一些很基本的重構功能
我還遇到 extract method 把 code 搞亂的情形
也許下次寫的時候可以改用 PyCharm 試試看

非常不熟系上線到雲端後的各種觀測系統
下次也許要多花點時間理解怎麼使用那些工具

Something learn


  • 學會怎麼用 pandas 取得網頁的資料
  • 學會用 python 呼叫 Google Sheet API
  • 學了幾個 Google Sheet functions
  • 學會怎麼開發/測試/佈署 Azure Functions

Future works


這次的系統就是給朋友們自己使用
大約十人左右的流量
而且是利用 Google Spreadsheet 來做 renderer
蒐集了大家使用上的意見
也許下一次大選的時候可以考慮用更有趣的前端來作呈現
這次天下雜誌有做了一個很不錯的系統
希望下次自己可以玩出一些有趣的東西

最後附上這次 hackathon 的 github repo - https://github.com/LaurenceCheng/2020Election

2020/02/14

等寬字型比一比 - JetBrains Mono、Fira Code、Cascadia Code、Consolas 在 Visual Studio Code 的樣貌


上個月在 facebook 上分享了 JetBrains 出了一款等寬字型叫 JetBrains Mono
昨天免費資源網路社群剛好也寫了一篇
"JetBrains Mono 更適合閱讀程式碼的等寬字型,內建四種字重斜體可商用"
在介紹這個字型

之前也有看過 Fira Code 以及微軟出的 Cascadia Code
趁這機會測試比較一下這幾種等寬字型
我是使用 Visual Studio Code 當作測試用的 IDE
以下是各種字型的截圖

Consolas

Cascadia Mono PL

Cascadia Code PL

Fira Code

JetBrains Mono
我原本都是使用 Consolas
未來會試著改用 Fira Code
主要是幾個原因

1. 我想試試 ligatures font
2. Fira Code 相較 JetBrains Mono 更細長點

大家可以嘗試看看自己喜歡哪一種字型

References:
1. Cascadia Code
2. Fira Code
3. JetBrains Mono
4. Font Switcher (VSCode extension)

2020/01/29

[自己的 Hackathon] L10 盃黑客松之即時開票系統 - 技術分享 (二) - 學習 Google Sheet API 與 Crawler

在上一篇依著微軟官方教學文件
學會了利用 Visual Studio Code 建立以及發佈 Azure Functions
接著就是要寫出我想要的 Crawler 以及即時更新 Google spreadsheet 的功能

流程簡圖

建立測試 Endpoint 來做 POC


因為每個部份我都沒有實際自己寫過
所以方便起見我建立了一個 HTTP trigger 的 Azure Function
在裡面寫一些 POC 的小片段
再把可行的部分搬移到對應的 Crawler 或是 Update Handler 中
我簡單盤點了一下我需要完成的幾項工作

T1. 從中選會網頁上爬到票數
T2. 將票數轉換成我定義好的 JSON 後,塞入 Azure Queue Storage 中
T3. 從 Azure Queue Storage 取出 JSON
T4. 依 JSON 中的對應票數,使用 Google Sheet API 填入 Google spreadsheet 對應的格子中

首先很快的利用 Azure Functions extension 建立好三個 Azure Functions
分別為

1. Timer trigger 的 Crawler
2. Azure Queue Storage trigger 的 Update Handler
3. HTTP trigger 的測試 Azure Function

最先完成的就是最簡單的 T2 與 T3
因為在教學文件中都有介紹到
唯一不同的就是要設計自己的 JSON 樣子而已
{
  "time": "1580121166",
  "votes" : {
    "president" : { "blue" : 1, "green" : 1 },
    "taipei3" : { "blue" : 1, "green" : 1 },
    "taipei4" : { "blue" : 1, "green" : 1 },
    "taipei5" : { "blue" : 1, "green" : 1 },
    "taichung3" : { "blue" : 1, "green" : 1 },
    "hualien" : { "blue" : 1, "green" : 1 }
  }
}


使用 Google Sheet API 填入對應票數


將 Crawler 與 Update Handler 串起後
下一件事情是學習怎麼在 Update Handler 中
用 Google Sheet API 去更新 spreadsheet
我是使用 pygsheets 這個 package
說明文件也算清楚
可以在 requirements.txt 中填入要使用的其他套件
在執行 debugger 的時候會自動用 pip install 幫你安裝

使用 pygsheets 套件前得先取得 Google API 的授權
我是使用 Service Account 的方法
要注意的就是 credentials.json 的檔案位置
一開始一直傳不對的路徑進去
導致卡關了一小段時間

學習怎麼寫 Crawler


我主要是看這個影片
[爬蟲實戰] 如何透過 Python 網路爬蟲 抓取並整理 2018 公投選舉資料?
非常仔細也非常詳盡
裡面介紹了兩個 packages, BeautifulSoup 與 pandas
我只需要用到 pandas 就好
就先用候選人簡歷的頁面練習
原則上是沒有遇到太大的問題
有錯誤的時候稍微再到 pandas 的官網查一下文件
或是利用 Google 都可以找到解答

利用條件式格式設定 highlight 第一名


我本來就會使用 RANK() 這個函式來排名
這次有兩個題目的排序需要預先處理,再餵入 RANK()
又很自以為的不想使用輔助欄 (就是先在其他格子內算出結果)
沒想到也搞了很久

ARRAYFORMULA() 應用


第一個是我要依 "絕對值" 由小到大排名
在這裡學到的一個公式是 ARRAYFORMULA()
ARRAYFORMULA() 可以想成本來 ABS() 這個函式只能計算一個格子的絕對值
套用 ARRAYFORMULA() 後,我們可以計算一個範圍內所有格子個別的絕對值
因此我們可以使用 ARRAYFORMULA() 的結果
再傳入 RANK() 的第二參數裡面使用
這樣我就不必使用一個輔助欄來先行計算絕對值再套用 RANK() 函式了

ARRAYFORMULA() 的結果


第二個是我要依 Max( |∆KMT|, |∆DPP| ) 由小到大排名
上圖中可以看到我用 ARRAYFORMULA() 先取得了一個二維的絕對值結果
下一步我需要把結果套入一個公式來取得兩欄中的最大值
這裡學到的是 QUERY() 這個公式
利用 QUERY() 我可以選出兩欄中最大的那一欄
不過 QUERY() 第二參數是類似 SQL 的語法
因此必須先做一次 TRANSPOSE() 把列與行對換
才能用 MAX() 語法取得最大值 (非常自找麻煩)

QUERY() 應用

最後就是再把結果 TRANSPOSE() 一次然後選出數字的那欄
就能餵到 RANK() 的第二參數中
非常囉嗦的方法,但是這樣就不必有輔助欄了

2020/01/18

[自己的 Hackathon] L10 盃黑客松之即時開票系統 - 技術分享 (一) - 學習 IDE 與 Azure Functions 基礎

這篇文章主要是我依著微軟官方文件
"使用 Visual Studio Code 在 Python 中建立和部署無伺服器 Azure Functions"
學習一些 Azure Functions 基礎的過程
分享我遇到的一些問題
如果你跟我一樣習慣英文介面的 Visual Studio Code
同樣的教學文件也有英文版 (較容易找到對應的 IDE 功能)

必要條件申請與安裝


文件中有三個前置要先準備好的東西
1. Azure 訂用帳戶 (Azure Subscription)
2. Azure Functions Core Tools
3. Visual Studio Code 以及對應的 extensions

首先最重要的當然是申請 Azure 帳號
新帳號在期限內能享有蠻多福利的
像是前三十天有 NTD 6,100 的額度可以使用
我多年前已經申請過了所以直接跳過這一步

新帳號可享的一些福利

再來就是安裝 Azure Functions Core Tools
先到 Node.js 下載頁面取得 v12.14.1 x64 的 Windows Installer 並安裝
接著依文件再輸入
npm install -g azure-functions-core-tools@3
文件中有提醒 "安裝 Node.js 時,請使用預設選項,「不要」 選取自動安裝必要工具的選項。"

最後就是安裝 Visual Studio Code
以及兩個對應的 extensions - Python extension 跟 Azure Functions extension
我是使用 python 作為實作這次系統的程式語言
所以要記得安裝 python 3.7.5 64bit

執行 Azure Functions Core Tools 的錯誤

以上三個前置都準備好後
依著文件說明在 vscode 中登入你的 Azure 帳戶
然後在 vscode 裡的 Terminal 執行 func
這時候我遇到了一個問題

"因為這個系統上已停用指令碼執行,所以無法載入 XXXX\funcc.ps1 檔案。
  如需詳細資訊,請參閱 about_Execution_Policies,網址為 https:/go.microsoft.com/fwlink/?LinkID=135170。
"

幸好隨便 Google 就找到了解答
(錯誤訊息中的官方連結也是有解答, 但是找到的這篇比較直接)
用 administrator 權限執行 PowerShell 並執行
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
然後再執行一次 func 應該就可以看到 Azure Functions Core Tools 的執行畫面了

看到斗大的 Azure Functions Icon 就是成功啦

建立第一個使用 HTTP trigger 的 Azure Function


終於開始要寫程式啦
再次稱讚文件介紹的非常清楚
工具也是相當的好用
點幾下選一選就建立好了一個 HTTP trigger 的 Azure Function
啟用 debugger 也沒甚麼問題
第一個範例是你可以透過 GET 在 URL 裡傳一個 name 參數
Azure Function 則是把你傳入的名字字串回傳
文件也有附上用 curl 執行 POST 的指令
但是我使用 PowerShell 指令又遇到了問題
最後在多方搜尋嘗試下
修改成下面這段
$body = @{"name"="Visual Studio Code2"} | convertto-json
curl http://localhost:7071/api/HttpExample `
 -Headers @{"Content-Type"="application/json"} `
 -Method Post -Body $body
這樣就測試到 GET 與 POST 兩種方法了

但是在執行 debugger 練習測試的時候
一直有一個很惱人的問題
就是每當要停止 debug 的時候
整個 vscode 就會 hang 在那邊, 只能重開
幸好也有人反應這個問題
解決方式就是在 vscode 裡面把 azureFunctions.stopFuncTaskPostDebug 關掉
但是這會造成離開 debugger 後
本機上的 Azure Functions 仍會繼續執行 (等於是你只是 detach 該 process 而以)

發佈你的第一個 Azure Functions


也還是跟著文件做就好
唯一不同的是, 我會建議選擇 "Create New Function App in Azure... Advanced"
因為這個選項才能選擇 hosting plan 為 consumption plan
發佈好了就能直接用公開的 URL 來觸發你的 Azure Function

有三種計價方式

文件後面還有教怎麼使用 queue 來觸發 Azure Functions
基本上照著做都沒甚麼問題
做完這些就等於學會了怎麼用 vscode 來開發並佈署簡單的 Azure Functions 了

2020/01/13

[自己的 Hackathon] L10 盃黑客松之即時開票系統 - 過程 (不含技術介紹)

決定好了題目後
接下來就是要決定實作的系統樣貌跟需要用到的技術
好幾年前 (大約是林傑學長還在做微軟技術傳教士時)
我有用過 Azure Functions 做過一個整合 slack 與 trello 的 bot
當時是直接在 Azure 提供的網頁上寫 python 來達成
這次也是想利用 serverless 的技術試試看
所以設計了一個簡單的架構


流程簡圖

Crawler 跟 Update Handler 就用兩個 Azure Functions 實作
Queue 的部分使用 Azure Queue Storage

先來重新學習現代化的開發方式


這次想順便試試看目前使用 IDE 開發 Azure Functions 能做到多方便
所以先以 "使用 Visual Studio Code 在 Python 中建立和部署無伺服器 Azure Functions"
這篇微軟官方的教學文件開始
星期五晚上把小鬼們都弄去睡覺之後
就開始依著這篇文件一步步的學習
文件還算詳細
雖然還是有遇到一點點小問題
不過都能透過 Google 大神找到解決方法
走過整篇文件後
就可以學會幾件事情

1. 如何在本機上開發 Azure Functions 且啟動 local debugger
2. 如何建立 HTTP 觸發的 Azure Functions 並測試
3. 如何把資料用 Azure Functions 送到 Azure Queue Storage 中
4. 如何部屬本機開發好的 Azure Functions 到雲端上

我做完整個教學後就去睡覺了
準備明天早上起床後再新建立一個專案來做真正的系統

把系統雛型產生出來


一早八點起床
老婆出門上班而小鬼們還在睡
趁機加緊腳步把 Crawler, Update Handler 以及 Azure Queue Storage 都先建好
定義好要塞進 queue 的 JSON 樣子後
先把組合出 JSON 後塞入 queue
以及被 queue 觸發後取得 JSON 的部分做好

當然中間少不了排解小鬼們的紛爭
還有被女兒甩了門後進行諄諄教誨的時間
接著開始準備兩位少爺小姐的午餐
等到老婆回家後我趁隙出門投票
直到他們開始午睡
我再繼續推進我的進度

最後在投票截止前約半小時把基本的功能完成
Update Handler 可以依 JSON 的內容, 把票數填寫到對應的儲存格中
因為尚未開票所以沒有票數頁面可以爬
於是我用中選會網站的 "候選人簡歷" 確認我會使用 package 寫出可行的 Crawler
接著就是守在電腦前等待得票數頁面出現

有人投票日一早開 vscode 的嗎?

最刺激的時刻總會出現問題


我重新整理中選會網站到約下午四點十七分
開始出現得票數頁面了
馬上著手修改 Crawler 的部分
結果竟然遇到無法印出爬到的內容 (因為我想先用 print 看看爬到的內容是否正確)
搜尋了半天還是沒找到解法
靈機一動想說先印出爬到表格的欄數與行數
這樣我可以知道哪一張才是得票數表格
果然有用, 馬上針對我想知道的候選人票數做處理 (對不起宋杯杯)
確定爬到總統得票數且能透過 Azure Queue Storage 觸發 Update Handler
也寫了正確數字到 spreadsheet 後信心大增
就開始把剩下的區域立委做完
同時使用本機的方式先確定可以一直爬到最新票數
終於在五點半時按下 Deploy 按鈕送上雲端

一開始先以每一分鐘觸發一次的頻率觀察一下
前幾分鐘好像一切正常
結果出現了票數回朔的現象
只好馬上來 debug
用著不熟悉的 Azure 介面看 Application Insights
赫然發現我的本機仍在執行 Azure Functions
所以才會有被修改兩次的現象
但是關掉本機之後又發現不會取得最新的票數
Azure 雲端上的 Crawler 似乎會一直拿到一樣的內容
查了半天查不出結果
幸好透過 Application Insights 了解到原來在本機執行也可以
只好在出門前把雲端上的都關掉
開啟本機上的開發環境讓他自己跑了
萬幸的是在外面用手機看 spreadsheet
有一直在更新票數
才鬆了一口氣

最後收尾的 spreadsheet 排名


回到家後幫孩子們沐浴更衣完後
把最後 spreadsheet 上的結果表格
依照之前討論的勝利方式
利用條件式格式設定功能
將猜測最準的人 highlight 出來
這裡也學到了幾個 spreadsheet 公式
整個只有自己的 hackathon 就這樣告一段落
收穫真的很多

複雜的 spreadsheet 公式

2020/01/12

[自己的 Hackathon] L10 盃黑客松之即時開票系統 - 前言

這次 2020 總統立委選舉很激烈
我的某個朋友群中也開啟了一些對於選舉結果的猜測
起初是我很雞婆的幫忙整理了每個人的預測
一直到星期五的時候突發奇想
如果用 Google Sheet 來顯示結果以及大家預測的準不準
好像蠻有意思的
所以我花了點時間做了一個 spreadsheet
(已經去識別化, 請相關人士不要擔心)

spreadsheet 的樣子

簡單說明一下表格上的資訊
朋友們討論後決定一起來預測三個題目
1. 關注的區域立委當選與否
2. 兩大黨不分區的席次
3. 兩大黨總統的票數差
可以看到這些人關注的選區有五個

表的左邊我是安排放票數跟席次的資訊
右邊的上半部是放個別的預測
下面做了一個結果的表格
計算出各題大家的預測結果
1. 猜中的選區數 (多者得勝)
2. 猜測席次與實際席次的差, 少一席跟多一席為一樣的計分
    (這題相對複雜, 最後大家的共識是 Max( |∆KMT|, |∆DPP| ) 最小者勝
    請原諒我用類似數學的式子表示, 中文太差了 Orz)
3. 猜測票數差與實際票數差的落差 (絕對值小者得勝)

做好了後分享給朋友們
大家覺得蠻不錯的很好懂

一開始是跟大家說 "你們就自己更新票數吧"
後來下班開車回家的路上就在想

如果能夠爬中選會的開票結果網站
然後即時的填入票數到 spreadsheet 中
好像更有臨場感了

於是這小小個人黑克松就在我的內心裡慢慢萌芽

2019/08/19

如何在 AppVeyor 建置 golang 的 repository

最近因為工作關係開始學習 golang
同時也要練習寫 golang 的 unit test
所以想起了之前寫過兩篇文章
這篇文章就記錄一下怎麼用 AppVeyor 建置 golang 的 repository 吧

其實比想像中的簡單
一開始也是從 NEW PROJECT 的按鈕
把你用 golang 寫的 repository 加進來

AppVeyor 主畫面 [截圖自www.appveyor.com]

然後 AppVeyor 的官網文件有教你怎麼寫 yaml 來 build golang repository
照抄就可以了

# appveyor.yml
build: off

clone_folder: c:\gopath\src\github.com\$username\$project

environment:
  GOPATH: c:\gopath

stack: go 1.10

before_test:
  - go vet ./...

test_script:
  - go test ./...

這次也是第一次用 AppVeyor 的 yaml 檔
其實比想像中容易很多
而且網頁上的 Settings 裡面
也有 Export YAML 的功能
你可以利用網頁 UI 設定好一些內容後
透過 Export YAML 輸出 appveyor.yml
再放入你自己的 repository 內

Export YAML 畫面 [截圖自www.appveyor.com]

接下來就是測試看看 build 的結果啦

成功的 build 好與執行 unit tests [截圖自www.appveyor.com]

不過 golang 的 unit tests 輸出並非是 AppVeyor 支援的格式
所以我們得透過一個工具 go-junit-report 來做轉換
我查了一下
最後是在我的 appveyor.yml 檔加了兩個部分
一個是 install 的地方先抓下 go-junit-report
接著在執行 unit tests 的地方透過參數把輸出開成 verbose
然後利用 pipe 傳給 go-junit-report
當然最後要用到之前文章學到的
把 report 透過 API 傳到 AppVeyor 上

build: off

clone_folder: c:\gopath\src\github.com\LaurenceCheng\testutils

environment:
  GOPATH: c:\gopath

stack: go 1.12

install:
  - go get -u -v github.com/jstemmer/go-junit-report

before_test:
  - go vet ./...

test_script:
  - go test -v ./... 2>&1 | c:\gopath\bin\go-junit-report > tests_report.xml

on_finish:
- ps: (new-object net.webclient).UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\tests_report.xml))

之後就能成功在 Tests 頁面看到失敗與成功的案例了

unit test 成功與失敗的 report [截圖自www.appveyor.com]


2019/07/17

眼前的黑不是黑,你說的 I 是哪個 i

[蕭煌奇的經典歌曲]

基於這個案例實在太經典了
除了前公司,現在的公司也有遇到過
本來想請前公司的同事幫忙
把我在內部分享的文章轉寄給我,然後重貼在這裡
但是據說該 forum 已經暫停服務
所以乾脆重新再寫一次吧

一個土耳其客戶回報某個功能失效


記得從 log 檔分析
是類似找不到某個 database table 的錯誤
研究了半天發現是大小寫不一致造成的
假設有一張 table 名字叫作 CustomerInfo
在建立 database 時寫成全小寫的 customerinfo
但是在程式裡面使用 SQL statement 時是寫成 CustomerInfo
在英文語系的時候很正常
可是在土耳其語系的時候就不行了
原因是土耳其語有兩個意料之外的字母

大寫字母 小寫字母
Iı
İi

所以 CustomerInfo 與 customerinfo 是不一樣的字母組成

其實字母數都不一樣的匈牙利語


又有一次遇到了類似的問題
也是找不到某個 database table 的錯誤
這次大腦的迴路就響起了警鈴
難道又是跟大小寫有關
假設有個 table 叫做 BasicSet
一樣建立的時候用全小寫
使用的時候寫成了 camel case
原因是匈牙利語中有特殊的字母

大寫字母 小寫字母
Cscs
Dzdz

所以 B-a-s-i-c-S-e-t 跟 b-a-s-i-cs-e-t 根本連字母數都不一樣

結論


就是大小寫使用的時候一定要一致
Windows 不是 case sensitive 的環境
所以導致測試的時候可能會忽略了這一點
這次公司遇到的就與 database 無關
而是在執行指令的時候踩到了這個雷

參考
土耳其语 - Wikipedia
匈牙利语 - Wikipedia

2019/03/19

Scrum Drawing Game by Juggernaut



前言


今天在公司內部上到了 Diro 哥非常推薦的一門課
Scrum Drawing Game [參考: Scrum Drawing Game 1.2 四小時豪華版]
講課的人是發想出這個遊戲的作者 Juggernaut
第一次與賈格的一面之緣是在新竹的敏捷活動
當天也是第一次參與 91 哥的 workshop
非常感謝我待的 Group 特地安排一個專班
請賈格來帶這一個 workshop
即使過去在前公司 VIVOTEK 跑了三年多的 scrum
還是可以從這樣的 workshop 學習到很多東西

客戶想的跟說的跟你認為的永遠不一樣 [圖片來源 : knowyourmeme.com]


產品探索的重要性


因為 Scrum 的精神與流程還算有點經驗
所以敏捷開發與 Scrum 的部分只是再次透過賈格的說明
重新驗證自己的理解有沒有問題
不過倒是對於產品探索本身有了一些新的學習
今天我們不是得分最高的組別
我後來覺得在唯一一次 stakeholder 到團隊來說明需求的時候
有一些地方做得不好以及應該可以做得更好

  1. 團隊說了太多話
  2. 大家可能急著把想做的事情列出來,卻不知不覺說了太多假設的事情。
    例如:客戶列了很多跟隱私有關的需求,我們就以為他一定很重視隱私。
    結果我們先把整個房子對外窗都做單面玻璃,還在大門做了指紋跟虹膜辨識。
    客戶驗收了,但是這項需求的 value 卻是 0... Orz

  3. 團隊應該要只問問題
  4. 回家的路上跟洗澡的時候,我想想,團隊應該只能問問題。
    因為很難得可以直接接觸客戶,應該要放下所有腦補,直接以很多的問題來確認客戶到底在想甚麼。
    甚至應該問客戶最重要最在乎的是甚麼,因為那通常是對方認為對他價值最高的事情。
    所以「聽」跟「問」是很重要的。
    這點也呼應了 91 哥說的,需求是問出來的,以前我們會抓著 PO 把事情問清楚。
    很有趣的,離開了那樣的情境,反而卻忘了要做到一樣的事情。
    看來是還不夠融入自己的靈魂啊 XD

2019/02/01

三六.一十八.回不去的十八歲

好久沒有寫生日感言了
上一篇已經是三年前三十三歲的時候
轉眼間已經到了四捨五入就不惑之年的年紀
不禁令人感嘆時光飛逝

2018 年最大的改變就是換工作



去年離開了從畢業服國防役
一路待了十年的公司晶睿通訊
這大概是目前人生中最大一次的轉變吧
依現況看來離換工作想達成的目的仍有一些落差
但是也因此學習到了很多事情
只能說離開舒適圈還是有其必要性
以前在晶睿學習到的軟實力跟軟體開發的技能
也對我在新公司重新建立 credits 上很有幫助
再次感謝讓我待了十年的這間公司

兩個十八歲的分水嶺



2018 是建中第一百二十周年校慶
當天我還有到學校去拜訪我的國中導師
為什麼不是高中老師?
因為依據現任台大資工系助理教授高中同學大屁股說
現在只剩下英文老師 SM 莎還在教
其他的各科老師都已經退休了
在建中的三年
是第一個十八歲最重要的那段期間
試著在一堆優秀的人中尋找自己的定位
經歷了一場失戀
還有最青春最自由最無拘無束的時光
記得在高中同學維揚的婚禮上
深深感受到曾經有過這群人一起度過高中三年
然後在十八年後仍然能聚在一起是多麼珍貴的情誼
Some things change, but some things never do.

第二個十八年
經歷了大學,出社會工作,成家到生小孩
大概是每四到五年會發現自己有不一樣的轉變
第一階段是學會怎麼跟自己相處
第二階段是學會怎麼發揮自己的社交能力
第三階段是學習怎麼作一個還可以的伴侶跟家長
相信未來還會有更多轉變
希望自己能朝向越來越好的方向繼續努力

依然幼稚的射手座性格


每次我跟著家裡兩個小鬼頭一起幹些蠢事時
老婆總是用很受不了的表情翻著白眼說你三十幾歲了怎麼跟三歲一樣
我想,也許未來會有一個階段是跟內心裡幼稚的那個自己道別吧
在那個時間到來之前
還請我周圍的各位親朋好友多多忍受我這三十六歲的幼稚射手座

2018/11/13

用 Stylus 幫你的 GitHub 網頁換皮

原本 GitHub 的配色 [截圖至 github.com]
可能有人跟我一樣比較偏好暗一點的背景色
所以我試著找方法來改變 GitHub 網頁的配色

修改後 GitHub 的配色 [截圖至 github.com]

研究了一下發現 GitHub-Dark 這個 repo
裡面有教你透過安裝 Stylus 這個 browser extension
再加上套用設計好的 CSS
就可以將你的 GitHub 網頁套用你喜歡的配色
不過 Stylus 是透過 URL matching 來決定哪個網站要套用哪套 CSS
如果公司使用的是 GitHub Enterprise
你就需要修改 Stylus 的設定把 self-hosted 的 domain 加入
這裡以 Chrome 為範例示範流程

點下右上角 Stylus Icon 後點擊 Manage 按鈕
點擊 GitHub Dark (看起來不像可以點的樣子)
1. 點擊最右邊的加號
2. 在 URL matching the regexp 填入你想套用的 GitHub domain
3. 最後點左上角的 Save

2018/07/19

再見 VIVOTEK

本文開始,文長請見諒

初見晶睿通訊


其實當初國防役在面試的時候
VIVOTEK 並沒有在我投遞履歷的清單當中
因為金門王的建議
所以我才投了 VIVOTEK
當時第一關的面試官是 Bruce
我到現在還記得他問了甚麼問題 XD
也在面試的過程中
跟未來會合作多年的 Diro 哥打到照面
很幸運的我通過了第一關的面試
接著與當時的經理喬伊及藍總的面試也順利
於是我就這樣取得了 VIVOTEK 的 offer

國防役的四年


我在 2007 年 10 月提前先到公司上班
之後再到關西受國防役的軍事訓練
2008 年的 1 月 14 日是我的報到日
也是在 VIVOTEK 國防役正式啟動的日子
很幸運地加入了當時研發二部 (R2) 的 Server Team
組長是 Lloyd
我們組一開始含組長總共就三個人
R2 在那時候所有的人也才二十人不到
但是我覺得我們是小而美的單位
當年肩負了相當重要的自有品牌軟體的開發
印象非常非常深的是有一年跨年夜
離開公司的時候跟同組的 Jason 說
「你等下說不定會在福和橋上看到一零一煙火喔 XD」
結果連假結束 R2 的大家長 Perkins 說他元旦四日連假都有來公司 Orz

總之我覺得能在 VIVOTEK 服國防役是非常幸運的
因為從小道消息指出
在關西同班的某些同袍
報到了一周還一個月後就直接決定回役
有地方是到職一個月後
就讓人寧願回部隊當兵也不想待四年
可見那地方有多水深火熱 XD
非常感謝所有 VIVOTEK 的同事長官
讓我能在這學習到非常多的技能與經驗

管理工作帶來不同的職涯經歷


隨著 R2 人數漸增
運氣不錯的被晉升成初階管理人員
自己的組最少的時候有三個組員
最多的時候則有七個組員
一直到最後離職前
我都還是擔任組長的職務
能夠接觸管理工作是我職涯中最特別的經驗

Perkins 在我剛進公司的第一年
有次面談時跟我提到
在面對把工作當作 routine 卻缺乏動力提升自己的人時
你會怎麼做?
當時的我屬於
「每個人應該都有選擇自己生活方式的自由,我不應干涉對方」這一派
P 老大說他以前也是這樣想的
但是後來他改變了
他當時的說法大概是這樣
「如果你的幫助或建議,能夠讓他有一點點改變的契機,那對他來說會是很大的影響」

有趣的是 P 老大並沒有告訴我一定要這樣想
但我在擔任管理職的過程中竟慢慢變成他口中的那一派
我喜歡分享我會的給其他人
我也喜歡回答其他人的問題
我更喜歡聽聽成員對於目前的工作有甚麼看法
並試著討論及給予他我能提出的建議
這是剛開始工作的我不會做的事情
以前的我覺得何必去改變別人的想法跟價值觀
現在我覺得如果他可以從我這邊得到一絲絲資訊
使得他自己能變得更好
那我會比他還要高興

練習說話也是擔任管理職的重要學習
面試以及一對一的面談都很需要
還有最難的就是說你不想說的話
做你內心會抗拒但又不得不做的事情時
我常跟成員說
擔任管理職帶給我最大的影響是
它就像一面鏡子
會幫助我發現以往沒有看過的自己
也算是某種讓自己離開舒適圈的一種方式吧

有幸參與敏捷轉型


在 2015 年的 1 月
R2 在 Diro 哥的帶領下開始導入敏捷開發
在好幾年前我們似懂非懂的嘗試過一點點
當然最後是失敗了
這次 Diro 哥勢在必行地做了很多準備
很幸運地我們算是有轉型過去
這三年中開拓了我的眼界
原來我們還有很多的可能性
革命尚未成功,同志仍須努力

最後要幫忙拉票一下


在 VIVOTEK 待了十年半
從來沒想過第一份工作就做了這麼久
我在這裡成家立業
還請了一段時間的育嬰留停
VIVOTEK R2 的同事們都很好相處
主管們對於各種意見也是以很開放的態度傾聽
除了內部自由發起的讀書會外
公司對於人的培養也很願意投資
無論是請外部講師到公司內訓
還是讓你到外面參加訓練課程或研討會
我本人就參加過資策會開的侯捷的課
以及到北京參加 QConf
只要是對於提升自我能力有幫助的
主管們都願意利用公司資源給予支持
歡迎有志人士可以跟 Diro 哥了解一下

我是因為禁不住內心對於舒適圈的恐懼感
以及想嘗試追尋更不一樣的刺激
所以選擇離開
但必須說如果可以再來一次
我還是會選擇 VIVOTEK 作為第一份工作的

天下無不散的筵席

我的國中導師在畢業紀念冊留下了這樣的句子

泉涸,魚相與處於陸,相呴以溼,相濡以沫,不如相忘於江湖。

這一段話一直到我當組長
第一個成員跟我說要離職後
我在感到很失落的當下才忽然懂了
如果真心的希望對方能過的更好
那就是在對方做了決定時
替他高興並且為他加油
雖然彼此可能不能再一起合作
但看到離開的那些成員都能更有發揮
這樣就很好了

希望 VIVOTEK 的各位都能越來越好,業績蒸蒸日上

2018/02/13

如何在 AppVeyor 執行用 Google Test 寫的測試程式

不久前有介紹怎麼使用 AppVeyor 整合 GitHub
(詳見 如何把 GitHub 上的 repository 掛上 AppVeyor 一文)
假設你使用 Visual Studio 2017 內建的 Google Test 來撰寫測試程式
要怎麼讓 AppVeyor 幫你 build 好後順便執行測試
並把測試結果回報給你呢?

首先當然是要先到方案中加一個 Google Test Project

新增一個 Google Test Project

Visual Studio 2017 已經把加測試這段作的很方便
你可以選擇這個測試是為了測試哪個模組
接著 Wizard 就會幫你把參考設定好
你只要著手開始寫測試就好

設定要測試的目標專案

因為等下要在 AppVeyor 上看結果
所以我先故意寫了一個成功跟一個失敗的測試
方便對照 UI 上的效果

一個成功一個失敗的測試案例

接著就把這些新增全部 push 到 GitHub 上看看 AppVeyor 的執行結果
這時候會發現有錯誤
似乎跟 NuGet package 有關係

缺少某個不存在的 NuGet package [截圖自 www.appveyor.com]

幸好 AppVeyor 有提供這個問題的解答 [參考: About NuGet package restore]
我們就照著在 Before Build Script 中輸入 "nuget restore"

設定 nuget restore [截圖自 www.appveyor.com]

按下 Save 後再回到主頁按下 [RE-BUILD COMMIT]
應該就可以得到成功的綠燈
不過這時候還沒有看到我們的測試結果
因為還需要設定兩個步驟
首先要讓 AppVeyor build 完後
會自動執行我們的測試程式
所以先切換到 Settings 頁面
在側邊攔找到 Build 頁籤
設定好 Configuration 為 Debug
以及 Platforma 為 x86

設定 Configuration 與 Platform [截圖自 www.appveyor.com]

再到 Tests 頁籤設定 Test script 為 "%APPVEYOR_BUILD_FOLDER%\%CONFIGURATION%\MyProjectTest.exe --gtest_output=xml:tests.xml"

設定 Test script [截圖自 www.appveyor.com]

再執行一次 Rebuild
應該可以看到測試程式成功執行的畫面

成功執行測試程式 [截圖自 www.appveyor.com]

不過右上角的 Tests 並沒有把兩個 test cases 列出來
這是因為結果的 tests.xml 還要透過 AppVeyor 的 API 傳上去
它才可以幫忙剖析出報告
我們再次進入 Settings 中的 General 頁籤
往下滑到最後的 On build finish script 中
輸入 "(new-object net.webclient).UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\tests.xml))"
儲存後再重新 Rebuild
這樣我們就可以在 Tests 畫面看到報告了

設定 On build finish sciprt 上傳測試報告 [截圖自 www.appveyor.com]

最後的測試報告 [截圖自 www.appveyor.com]