[KATA] 最大公因數與最小公倍數

簡介

數學系畢業後,在學寫程式雖然偶爾會用到一些數學特性來解題,
不過到了工作確不是那麼一回事,大多在處理商業流程,資料流 ;
然後在商業流程與資料流中穿梭,找蟲然後補丁 ;

這是最近在練習 Kata 的題目所用到的兩個國中數學,
「最大公因數」與「最小公倍數」,還用程式實踐了「輾轉相除法」,
真的是有點懷念啊 。

這是題外話,Rx(Reactive Functional Programing)感覺很有趣
最近參與 functional programing 的讀書會,
裡面似乎有比現在開發模式更優雅的解決問題方式。
不過門檻有點高,需要具備的抽象思考能力,是種非常燒腦的開發方式。

實作

1
2
3
4
5
6
7
8
//// GCD
static Func<int, int, int> GCD = (numA, numB) => {
return numB == 0 ? numA : GCD(numB, numA % numB);
};
//// LCM
static Func<int, int,int> LCM = (numA,numB) => {
return numA * numB / GCD(numA, numB);
} ;

參考

(fin)

i18n 與 l10n

I18n 國際化

1
2
3
| I | n | t | e | r | n | a | t | i | o | n | a | l | i | z | a | t | i | o | n |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |16 |17 |18 | |

Internationalization 因為字首I到字尾N18個英文字

L10n 在地化

1
2
3
| L | o | c | a | l | i | z | a | t | i | o | n |
|---|---|---|---|---|---|---|---|---|---|---|---|
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 | |

Localization 因為字首L到字尾N共10個英文字

國際化/在地化常見問題

  • 語言
    • 語系-區碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  [
{"LangCultureName": "af-ZA", "DisplayName": "Afrikaans - South Africa"},
{"LangCultureName": "sq-AL", "DisplayName": "Albanian - Albania"},
{"LangCultureName": "ar-DZ", "DisplayName": "Arabic - Algeria"},
{"LangCultureName": "ar-BH", "DisplayName": "Arabic - Bahrain"},
{"LangCultureName": "ar-EG", "DisplayName": "Arabic - Egypt"},
{"LangCultureName": "ar-IQ", "DisplayName": "Arabic - Iraq"},
{"LangCultureName": "ar-JO", "DisplayName": "Arabic - Jordan"},
{"LangCultureName": "ar-KW", "DisplayName": "Arabic - Kuwait"},
{"LangCultureName": "ar-LB", "DisplayName": "Arabic - Lebanon"},
{"LangCultureName": "ar-LY", "DisplayName": "Arabic - Libya"},
{"LangCultureName": "ar-MA", "DisplayName": "Arabic - Morocco"},
{"LangCultureName": "ar-OM", "DisplayName": "Arabic - Oman"},
{"LangCultureName": "ar-QA", "DisplayName": "Arabic - Qatar"},
{"LangCultureName": "ar-SA", "DisplayName": "Arabic - Saudi Arabia"},
{"LangCultureName": "ar-SY", "DisplayName": "Arabic - Syria"},
{"LangCultureName": "ar-TN", "DisplayName": "Arabic - Tunisia"},
{"LangCultureName": "ar-AE", "DisplayName": "Arabic - United Arab Emirates"},
{"LangCultureName": "ar-YE", "DisplayName": "Arabic - Yemen"},
{"LangCultureName": "hy-AM", "DisplayName": "Armenian - Armenia"},
{"LangCultureName": "Cy-az-AZ", "DisplayName": "Azeri (Cyrillic) - Azerbaijan"},
{"LangCultureName": "Lt-az-AZ", "DisplayName": "Azeri (Latin) - Azerbaijan"},
{"LangCultureName": "eu-ES", "DisplayName": "Basque - Basque"},
{"LangCultureName": "be-BY", "DisplayName": "Belarusian - Belarus"},
{"LangCultureName": "bg-BG", "DisplayName": "Bulgarian - Bulgaria"},
{"LangCultureName": "ca-ES", "DisplayName": "Catalan - Catalan"},
{"LangCultureName": "zh-CN", "DisplayName": "Chinese - China"},
{"LangCultureName": "zh-HK", "DisplayName": "Chinese - Hong Kong SAR"},
{"LangCultureName": "zh-MO", "DisplayName": "Chinese - Macau SAR"},
{"LangCultureName": "zh-SG", "DisplayName": "Chinese - Singapore"},
{"LangCultureName": "zh-TW", "DisplayName": "Chinese - Taiwan"},
{"LangCultureName": "zh-CHS", "DisplayName": "Chinese (Simplified)"},
{"LangCultureName": "zh-CHT", "DisplayName": "Chinese (Traditional)"},
{"LangCultureName": "hr-HR", "DisplayName": "Croatian - Croatia"},
{"LangCultureName": "cs-CZ", "DisplayName": "Czech - Czech Republic"},
{"LangCultureName": "da-DK", "DisplayName": "Danish - Denmark"},
{"LangCultureName": "div-MV", "DisplayName": "Dhivehi - Maldives"},
{"LangCultureName": "nl-BE", "DisplayName": "Dutch - Belgium"},
{"LangCultureName": "nl-NL", "DisplayName": "Dutch - The Netherlands"},
{"LangCultureName": "en-AU", "DisplayName": "English - Australia"},
{"LangCultureName": "en-BZ", "DisplayName": "English - Belize"},
{"LangCultureName": "en-CA", "DisplayName": "English - Canada"},
{"LangCultureName": "en-CB", "DisplayName": "English - Caribbean"},
{"LangCultureName": "en-IE", "DisplayName": "English - Ireland"},
{"LangCultureName": "en-JM", "DisplayName": "English - Jamaica"},
{"LangCultureName": "en-NZ", "DisplayName": "English - New Zealand"},
{"LangCultureName": "en-PH", "DisplayName": "English - Philippines"},
{"LangCultureName": "en-ZA", "DisplayName": "English - South Africa"},
{"LangCultureName": "en-TT", "DisplayName": "English - Trinidad and Tobago"},
{"LangCultureName": "en-GB", "DisplayName": "English - United Kingdom"},
{"LangCultureName": "en-US", "DisplayName": "English - United States"},
{"LangCultureName": "en-ZW", "DisplayName": "English - Zimbabwe"},
{"LangCultureName": "et-EE", "DisplayName": "Estonian - Estonia"},
{"LangCultureName": "fo-FO", "DisplayName": "Faroese - Faroe Islands"},
{"LangCultureName": "fa-IR", "DisplayName": "Farsi - Iran"},
{"LangCultureName": "fi-FI", "DisplayName": "Finnish - Finland"},
{"LangCultureName": "fr-BE", "DisplayName": "French - Belgium"},
{"LangCultureName": "fr-CA", "DisplayName": "French - Canada"},
{"LangCultureName": "fr-FR", "DisplayName": "French - France"},
{"LangCultureName": "fr-LU", "DisplayName": "French - Luxembourg"},
{"LangCultureName": "fr-MC", "DisplayName": "French - Monaco"},
{"LangCultureName": "fr-CH", "DisplayName": "French - Switzerland"},
{"LangCultureName": "gl-ES", "DisplayName": "Galician - Galician"},
{"LangCultureName": "ka-GE", "DisplayName": "Georgian - Georgia"},
{"LangCultureName": "de-AT", "DisplayName": "German - Austria"},
{"LangCultureName": "de-DE", "DisplayName": "German - Germany"},
{"LangCultureName": "de-LI", "DisplayName": "German - Liechtenstein"},
{"LangCultureName": "de-LU", "DisplayName": "German - Luxembourg"},
{"LangCultureName": "de-CH", "DisplayName": "German - Switzerland"},
{"LangCultureName": "el-GR", "DisplayName": "Greek - Greece"},
{"LangCultureName": "gu-IN", "DisplayName": "Gujarati - India"},
{"LangCultureName": "he-IL", "DisplayName": "Hebrew - Israel"},
{"LangCultureName": "hi-IN", "DisplayName": "Hindi - India"},
{"LangCultureName": "hu-HU", "DisplayName": "Hungarian - Hungary"},
{"LangCultureName": "is-IS", "DisplayName": "Icelandic - Iceland"},
{"LangCultureName": "id-ID", "DisplayName": "Indonesian - Indonesia"},
{"LangCultureName": "it-IT", "DisplayName": "Italian - Italy"},
{"LangCultureName": "it-CH", "DisplayName": "Italian - Switzerland"},
{"LangCultureName": "ja-JP", "DisplayName": "Japanese - Japan"},
{"LangCultureName": "kn-IN", "DisplayName": "Kannada - India"},
{"LangCultureName": "kk-KZ", "DisplayName": "Kazakh - Kazakhstan"},
{"LangCultureName": "kok-IN", "DisplayName": "Konkani - India"},
{"LangCultureName": "ko-KR", "DisplayName": "Korean - Korea"},
{"LangCultureName": "ky-KZ", "DisplayName": "Kyrgyz - Kazakhstan"},
{"LangCultureName": "lv-LV", "DisplayName": "Latvian - Latvia"},
{"LangCultureName": "lt-LT", "DisplayName": "Lithuanian - Lithuania"},
{"LangCultureName": "mk-MK", "DisplayName": "Macedonian (FYROM)"},
{"LangCultureName": "ms-BN", "DisplayName": "Malay - Brunei"},
{"LangCultureName": "ms-MY", "DisplayName": "Malay - Malaysia"},
{"LangCultureName": "mr-IN", "DisplayName": "Marathi - India"},
{"LangCultureName": "mn-MN", "DisplayName": "Mongolian - Mongolia"},
{"LangCultureName": "nb-NO", "DisplayName": "Norwegian (Bokmål) - Norway"},
{"LangCultureName": "nn-NO", "DisplayName": "Norwegian (Nynorsk) - Norway"},
{"LangCultureName": "pl-PL", "DisplayName": "Polish - Poland"},
{"LangCultureName": "pt-BR", "DisplayName": "Portuguese - Brazil"},
{"LangCultureName": "pt-PT", "DisplayName": "Portuguese - Portugal"},
{"LangCultureName": "pa-IN", "DisplayName": "Punjabi - India"},
{"LangCultureName": "ro-RO", "DisplayName": "Romanian - Romania"},
{"LangCultureName": "ru-RU", "DisplayName": "Russian - Russia"},
{"LangCultureName": "sa-IN", "DisplayName": "Sanskrit - India"},
{"LangCultureName": "Cy-sr-SP", "DisplayName": "Serbian (Cyrillic) - Serbia"},
{"LangCultureName": "Lt-sr-SP", "DisplayName": "Serbian (Latin) - Serbia"},
{"LangCultureName": "sk-SK", "DisplayName": "Slovak - Slovakia"},
{"LangCultureName": "sl-SI", "DisplayName": "Slovenian - Slovenia"},
{"LangCultureName": "es-AR", "DisplayName": "Spanish - Argentina"},
{"LangCultureName": "es-BO", "DisplayName": "Spanish - Bolivia"},
{"LangCultureName": "es-CL", "DisplayName": "Spanish - Chile"},
{"LangCultureName": "es-CO", "DisplayName": "Spanish - Colombia"},
{"LangCultureName": "es-CR", "DisplayName": "Spanish - Costa Rica"},
{"LangCultureName": "es-DO", "DisplayName": "Spanish - Dominican Republic"},
{"LangCultureName": "es-EC", "DisplayName": "Spanish - Ecuador"},
{"LangCultureName": "es-SV", "DisplayName": "Spanish - El Salvador"},
{"LangCultureName": "es-GT", "DisplayName": "Spanish - Guatemala"},
{"LangCultureName": "es-HN", "DisplayName": "Spanish - Honduras"},
{"LangCultureName": "es-MX", "DisplayName": "Spanish - Mexico"},
{"LangCultureName": "es-NI", "DisplayName": "Spanish - Nicaragua"},
{"LangCultureName": "es-PA", "DisplayName": "Spanish - Panama"},
{"LangCultureName": "es-PY", "DisplayName": "Spanish - Paraguay"},
{"LangCultureName": "es-PE", "DisplayName": "Spanish - Peru"},
{"LangCultureName": "es-PR", "DisplayName": "Spanish - Puerto Rico"},
{"LangCultureName": "es-ES", "DisplayName": "Spanish - Spain"},
{"LangCultureName": "es-UY", "DisplayName": "Spanish - Uruguay"},
{"LangCultureName": "es-VE", "DisplayName": "Spanish - Venezuela"},
{"LangCultureName": "sw-KE", "DisplayName": "Swahili - Kenya"},
{"LangCultureName": "sv-FI", "DisplayName": "Swedish - Finland"},
{"LangCultureName": "sv-SE", "DisplayName": "Swedish - Sweden"},
{"LangCultureName": "syr-SY", "DisplayName": "Syriac - Syria"},
{"LangCultureName": "ta-IN", "DisplayName": "Tamil - India"},
{"LangCultureName": "tt-RU", "DisplayName": "Tatar - Russia"},
{"LangCultureName": "te-IN", "DisplayName": "Telugu - India"},
{"LangCultureName": "th-TH", "DisplayName": "Thai - Thailand"},
{"LangCultureName": "tr-TR", "DisplayName": "Turkish - Turkey"},
{"LangCultureName": "uk-UA", "DisplayName": "Ukrainian - Ukraine"},
{"LangCultureName": "ur-PK", "DisplayName": "Urdu - Pakistan"},
{"LangCultureName": "Cy-uz-UZ", "DisplayName": "Uzbek (Cyrillic) - Uzbekistan"},
{"LangCultureName": "Lt-uz-UZ", "DisplayName": "Uzbek (Latin) - Uzbekistan"},
{"LangCultureName": "vi-VN", "DisplayName": "Vietnamese - Vietnam"}
]
  • 單位
  • 時區
    • 跨時區
    • 日光節約時間
  • 其它
    • 地址
    • 姓名
    • 電話號碼

(fin)

[內部分享]Cache 使用 Files 與 Redis

Why Cache ?

  1. 保護稀缺資源(database/disk io/server)
  2. 提高反應速度,減少延遲(Latency)

Cache Point

  1. 資料即時性/如何除錯/如何更新
  2. Hit Rate
  3. High Availability(HA)
  4. 單位時間承載量

Our Cache

  1. CDN(Cloudfront)
  2. OutputCache
  3. Memory Cache
  4. Redis Cache
  5. File Cache

More Cache not in above

  1. Browser Cache
  2. Database Execution Plan Cache (執行計劃快取)
  3. Elastic Search

File Cache

  • pro
    • 簡單易用
  • con
    • 咬檔
    • 不會自動過期
    • 自已要處理 lock 機制

Redis Cache

  • pro
    • 會自動過期
    • 有提供 Queue 的功能
    • 高速(in memory)
  • con
    • 單緖(Single Thread)
    • HA 的機制費用高
    • Redis 承載量受限於記憶體大小
    • 存儲的東西過大,會導致存取速度下降

實踐問題:在大流量的站台,Cache 過期時如何避免大量 Request 同時更新同一份 Cache ?

Ans: 使用 Lock ,
不要使用.NET 的lock ;.NET Lock 的機制問題在於,Lock 會導致其它 Thread 排隊
當系統處於高流量的情境底下,會發生間歇性 Latency 提高,
而且難以追查問題,也難以重現(一般的壓測無法達到如此高量)。

使用共用的 Lock Key 作判斷標準:

  1. Lock Key 存在,回傳 Cache Data
  2. Lock Key 不存在,建立 Lock Key(包含 Server Id)
  3. 重新取得 Lock Key 如果
    • Server Id 與 Request 相同,更新 Cache Data 並回傳
    • Server Id 與 Request 不相同,直接回傳 Cache Data

[Cache Double check Lock Patter(https://docs.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ee558270(v%3Doffice.14)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static object _lock =  new object();

public void CacheData()
{
SPListItemCollection oListItems;
oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
if(oListItems == null)
{
lock (_lock)
{
// Ensure that the data was not loaded by a concurrent thread
// while waiting for lock.
oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
if (oListItems == null)
{
oListItems = DoQueryToReturnItems();
Cache.Add("ListItemCacheName", oListItems, ..);
}
}
}
}

Other

  1. 使用多執行緖時要小心處理 Exception,不然會導致主程序被中斷
    (File Cache 寫入真實案例,多緖的錯誤不佳會使得 IIS 無法處理錯誤,進而中斷程序(w3wp.exe))
  2. AWS S3 是走 Https Protocal
  3. Redis Delete/Backup 會 Lock Thread
  4. Redis Command Timeout 極短,所以要注意單一 Cache 資料量大小 (建議資料要小於 1k?)

參考

(fin)

[異常記錄] 多語系架構上線

前情提要

很久很久很久以前,
【跨國語系基礎架構】上線了.
又過了很久很久 我們評估這多語系 API 需要上 CDN
我們評估這多語系 API 需要上 CDN

Release 項目與工作內容

  • 8/16 要 release 什麼?
    我們要將多語系開始開發的項目一次回台灣正式環境。
  • 我們作了什麼
    • sp23/sp24/sp25/sp26/sp27
    • 前端多語系底層架構的調整(含 CDN)
    • 國別設定
    • 還有一大堆 Merge 解衝突的項目…
  • 為什麼要等這麼久才上線 ?
    風險考量,我們先上了基礎架構,
    在 G3 環境上觀察了一段時間確定沒有問題才上線。
  • 講到風險,我們有多少保險 ?
    • 只上基礎架構 (讓異動最小)
    • 只上 G3 環境 (讓 impact 最小)
    • 藍綠部署 (標配,讓壞掉的時間儘可能縮短)
    • Merge Before Build (讓原始碼不受影響,rollback 時不會拔掉其它團隊的功能)

講那麼多,還不是壞掉了。

錯誤原因

錯誤畫面

錯誤畫面

錯誤原因

錯誤原因

多語系 CDN 的 Response Header Access-Control-Allow-Origin Protocol 與主頁面不符;

流程面

測試環境 測試結果
QA8 OK
QA OK
PP OK
鎖 Host 測試 OK
半數機器上線 OK
全數機器上線 OK,好 (壞了)

為什麼全數機器上線才發生異常。

  • QA8 沒有 CDN
  • 鎖 Host/半數機器上線未開 CDN
  • QA / PP CND 設定與正式環境不一致
    • RD 並未 Check 設定的一致性
    • RD 沒有權限

技術細節

  1. 使用 Partial View 與 OutputCache
  2. 小心 Browser Cache
  3. 站台上會有跨 Domain 的存取行為
    • Service to Official
    • Service to CDN
    • Official to Service
  4. CDN & Access-Control-Allow-Origin
  5. 稍微提一下 CORSModule

錯誤分析

錯誤分析

TranslationCDN : 用來防止瞬間量對 Server 的 Impact
FingerprintTag : 一份Cache的時戳, 用以取得新版多語系 Json 檔
site : BrowserCache 遇到跨 Domain 存取時, 會發生 CORS Error
  1. Partial View 會有 OutputCache
    → 保得了一時,保不了一世
  2. 為了 Browser Cache ,F2E 在 QueryString 作了加工。
  3. 網站跨 Domain 的存取行為,歷史共業。
  4. CDN & Access-Control-Allow-Origin
  5. CorsModule,有必要區分 protocol 嗎 ?

架構圖

1
2
3
4
if (httpContext.Request.Url.Scheme == Uri.UriSchemeHttps && (sourceUri == null || sourceUri.Scheme == Uri.UriSchemeHttps))
{
allowOrigin = allowOrigin.Replace("http:", "https:");
}

問題處理經過

  1. 第一時間 QA 有看到異常, 但是在 PO 的環境無法重現, RD 初步判斷為快取的問題, 並嘗試重現錯誤 。

  2. SRG 收到通報有客戶反應顯示異常,立即啟動藍綠部署,耗時 93 分鐘

  3. 縮小範圍至 CDN 與 Access-Control-Allow-Origin 異常,但是仍然無法完整重現錯誤(時好時壞)

  4. 申請 CDN 權限,確認各環境的設定值。

  5. 申請 QAn 測試用 CDN,在 QA8 環境反覆測試,
    發現頁面 OutputCache 會影響測試
    關閉 QA8 OutputCache
    測試步驟如下:

  6. 確認 Prod CDN 的 WhiteList Header 的設定有問題,
    那為什麼 PP/G3 不會有問題呢 ?
    => 在 PP/G3 設定為 Referrer

  7. 測試過程發現 x-cache Header 常常
    Miss from cloudfront,
    表示資料並非來自 CDN .
    實際測試 Origin 比 Referrer 更適合

回饋與後續

1. 團隊評估欠缺數據 →
2. 客戶反應異常。
3. 藍綠部署異常回覆速度,耗時 93 分鐘 → `已有RD著手改善`
4. 無法完整重現錯誤
5. RD 沒有 CDN 權限 → `已申請`
6. QAn 沒有設定 CDN → `沒有CDN的Issue沒必要特別設定(因為需要對外)`
7. 頁面 OutputCache 會影響測試。
8. PP / G3 與 Prod  CDN設定不一致 → `webapi/translate/* 已調整一致`
9. Release 三步驟 , 最後一步才會開啟 CDN

Q. 下次我們怎麼作 ?

補充資料

  • 什麼是 CDN ?
    什麼是 CDN

    Server 跟 CDN 就像工廠與便利店的關係, 你要買東西不用跑到工廠
    只要在離自已最近的便利店買就好了, 過期的商品(資料)會被丟掉
    重新跟工廠進貨(拉新資料)。
    
  • 什麼是 CORS ?

  • 什麼是 Origin

  • 什麼是 Referrer

  • Slide

(fin)

[踩雷筆記] .Net專案升級 SpecRun.Runner 與調整 CI

前情提要

  • 專案使用 Specflow 寫 BDD
  • Visual Stuio 找不到測試所以才升級 SpecRun 與 Specflow
  • Visual Studio 2017 升級到 15.8.1 後突然無法正常搜尋到測試
  • SpecRun.Runner 升級(1.2 → 1.8.2)

去年 12 月跟 Visual Studio 折騰了許久,才讓專案的測試項目重見光明
在今年與其它專案合併後,測試又從我們團隊的眼前消失了。

調整項目

升級 Specflow 與 SpecRun 相關套件
升級 Specflow 與 SpecRun 相關套件

取得 SpecRun 位於專案的 packages 資料夾中。
取得 SpecRun 位於專案的 `packages` 資料夾中。

設定 CI

由於 SpecRun 版本不符會導致 CI Job Error , 需要設定以新的 SpecRun 執行 CI

D:\SpecRun.Runner.1.8.2\tools\SpecRun.exe run D:\Project\Core.Test\bin\Debug\Core.Test.dll /baseFolder:Core.Test\bin\Prod /toolIntegration:vs201 0 /reportFile:Core.Test.TestResult.html

參考

(fin)

[踩雷筆記] 誰改了我的 package-lock.json ?

環境

OS Windows 10
npm v6.2.0
node v8.11.1

問題

承上篇[實作筆記] 設定 NPM Registry
後續發生的一些問題,
每當我執行 npm install 的時候都會異動到 package-lock.json 檔;
異動這個檔案並不意外,可以參考官方文件的說法。

奇怪的點是,異動竟然包含 Registry !?
全部都被置換成公司的 Domain , WTF ?

公司的 Domain

原因與坑

當執行 npm install 的時候,
node 會去檢查你實際安裝的 node_modules,
並產生 package-lock.json 檔。
可以把 package-lock.json 想像成 node_modules 的映射。
而恰巧之前所安裝過的檔案,是在 Registry 為 npm.mycompany 時下載的;
這導致產生 package-lock.json 的時候會映射出 npm.mycompany 的資訊。

小心有坑!!
即使刪除了 node_modules 再重新 npm install
仍然會產生錯誤的 package-lock.json;
這個原因是 npm 會有 npm-cache;
這個資料夾位在 %Users%\AppData\Roaming

解決方法

  1. 設定 npm registry

    npm set registry https://registry.npmjs.org

  2. 刪除專案底下的 node_modules 資料夾
  3. 刪除 npm-cache
  4. 重新執行 npm install

(fin)

[實作筆記] 設定 NPM Registry

原因

最近換了新電腦,在家工作時發生了 npm install Error;
錯誤訊息如下,明顯看到 npm 嘗試去連線 http://npm.mycompany.io
http://npm.mycompany.io 是公司內部的私有網路;
印象中沒有特別設定,可能是公司內的預設安裝設定的。

1
2
3
4
5
6
7
8
9
10
11
12
PS D:\Repo\Marsen\Marsen.Node.Express> npm i -g gulp
npm ERR! code ETIMEDOUT
npm ERR! errno ETIMEDOUT
npm ERR! network request to http://npm.mycompany.io/gulp failed, reason: connect ETIMEDOUT ***.***.***.***:80
npm ERR! network This is a problem related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly. See: 'npm help config'

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Mark Lin\AppData\Roaming\npm-cache\_logs\2018-07-29T07_17_25_263Z-debug.log

解法

一個簡單的方法是 VPN 回公司內部網路;
另一個方法是重新設定,

1
2
3
4
5
> npm get registry
http://npm.mycompany.io
> npm set registry https://registry.npmjs.org
> npm get registry
https://registry.npmjs.org

(fin)

[閱讀筆記] The Great Scrum Master 第二章

大綱

  • 心態模式
    • 教導和輔導
    • 移除障礙
    • 引導
    • 教練
    • 觀察

教導和輔導

初期需要一再解釋為什麼要實施 Scrum 和 Agile 方法和如何運作,
團隊成熟後,共享經驗,並且更多的實踐

移除障礙

排除團隊的障礙,是將責任、活動和所有權都下放給團隊,讓團隊可以自行解決問題

1
2
3
4
實務上資安、權限和風險上的控管似乎不可行?
雖然說信任團隊,但是上述的角度來看,這些限制是必要之惡。
新創團隊怎麼作 ? 規模擴大後的團隊又該怎麼作 ?
系統思考?

引導

確保會議有效率,使每次談話有目標/結果。

1
2
3
4
5
開會前確認討論的主題與範圍,
開會中確保有效討論與時間控制;
開會完產出相對的決定/行為/文件。
其中以行為最為重要,也是所謂的action item
或是下一步清單。

教練

Scrum Master 最重要技能之一,關注個人成長也關注團隊自組織、責任感與所有權

1
2
3
4
5
不知道這本書在供三小,知道的人請告訴我
我比較推薦以下這篇的說法,教導是單向的,教練則是的迴圈
教導比較像是說明、講解、指示;或許有點像上課、聽演講或是看一本書
教練比較有互動性,除了上述所說也包含了給予回饋、示範與局部修正
指導者與被指導者都會參與其中。

觀察

觀察、聆聽而不是干預;保持耐心再採取行動。

1
2
3
4
5
6
7
8
9
10
11
12
13
20180724讀書會回饋:
1. Scrum Master 要有意識的不作為(Actively Doing Nothing)
2. 移除障礙:還是先觀察,讓團隊自行解決問題,個人的問題或許不是團隊的問題;
站立會議是個人尋求團隊意見的好時機。
3. 引導的方法就是問問題與對話。
4. 引導分為個人與團隊
- 個人
引導作對方想作或是 Scrum Master 想作的事
- 團隊
尋找一個目標,發散 → 收斂 → 執行
再找下一個目標,發散 → 收斂 → 執行
持續這樣的步驟,並隨時回頭看看效果如何,
有些想法或許會被錯過

其它

教練的實例

提問篇
解答篇
Coaching example : Kasatkina
Coaching example : 跆拳道
Coaching example : 空手道

(fin)

[閱讀筆記] The Great Scrum Master 第三章

#ScrumMasterWay

第一個層次 — 我的團隊

Scrum Master 只對開發團隊負責,
「如何讓自已每天都發揮作用?」
建立具有敏捷思維與 Scrum 價值觀的自組織團隊是個長期活動。
第一步是觀察,並抑制親力親為的衝動(具體建議/親自排解障礙),

可能的問題在於,團隊缺乏理解、所有權、責任感與經驗;
或是團隊的抵制。

1
2
3
回饋:
沒有主管並不會讓團隊自組織!給團隊解決不能只靠再想想
https://www.facebook.com/91agile/posts/986977734810178

Scrum 的價值觀

  • 承諾、專注、開放、尊重、勇氣
    — ScrumAlliance 《Scaling Lean & Agile Development》
  • 誠實、開放、勇氣、尊重、專注、信任、授權和合作
    —Kenneth S.Rubin《Essential Scrum》
  • 謙虛、尊重、信任
    — 《Debugging Teams: Better Productivity through Collaboration》
    謙虛、尊重、信任

第二個層次 — 關係

  • Scrum Team

    • 建立連貫、自信的團隊
    • 將 PO 整合進入團隊
    • 建立三個角色平衡的關係
  • 利害關係人

    • 客戶、用戶、經理、銷售人員、維運人員、客服、其它團隊
    • 將自組織用于參與的所有人員

    這需要 Scrum Master 對 Scrum 定義、理解與解釋的能力,
    不只是會議/角色或產出物,而是從文化、價值觀與思維方式對 Scrum 的內化。
    在這層次下,需要建立靈活的虛擬團隊擁有所有權,承擔某些責任,
    有些團隊在解決問題後就可以淡出,有的要維持一段時間。

1
2
3
4
5
6
7
8
開發團隊與 Scrum 團隊不是組織中唯一的團隊 ?
持續存在的團隊 ? 專案團隊 ? DevOps ?
短暫存在的團隊 ? 救火團 ? 跨專案團隊 ?
這些團隊的資源從何而來 ?
持續存在又特殊的團隊? 維運?
花很多時間釐清問題,卻沒有辦法解決問題?
受限於什麼原因 ?
技術不足 ? 沒有人領導 ? 沒有所有權 ? 風險導向 ? 不受重視 ?

第三個層次—整個系統

Scrum 是「一種生活方式」,成為生活哲學的一部份,改造整個系統(世界)。

提示

  • 先觀察
  • 幫助團隊,讓團隊移除障礙
  • 引導不是讀一本書或上一次課
  • 教練法是提出問題的能力(你會問問題嗎?)
  • 不要停留在開發層次,融入工作生活之中
1
2
3
太高大上了,跟不上…
問個問題,如果障礙是組織內的要員或大主管呢 ?

Scrum Master 小組

如果要讓組織敏捷,核心是一個強大的 Scrum Master 小組。
如果組織在「第一個層次 — 我的團隊」中擁有一個強大的 Scrum Master 小組,
那麼 Scrum Master 只需要完善團隊就好了;
比起單獨創立完善一個 Scrum Team 或是依賴 Agile Couch,
Scrum Master 小組是改變組織最好的起點。

Scrum Master 小組的目標

  • 替其它人作好系統層次的準備
  • 關注整個系統
  • 建立虛擬組織讓人參與並擁有所有權

挑戰

  • Scrum Master 否定 Scrum Master 小組的價值
  • 防衛心理:
    • 缺乏同理心,從別的團隊角度觀察事情
    • 缺乏系統觀點與思維
    • 缺乏管理變革經驗

組織即系統

將組織視為系統而非階層架構。

  • 系統思考,了解彼此的關系與動態
  • 觀注 impact mapping

Cynefin 框架

  • 簡單明確(Simple / Obvious)
    • 你只需要分類,選擇最佳解即可
  • 人為/物理複雜(Complicated)
    • 像是組裝模型,你需要先分析計劃,
    • 當事情變得簡單明確即可。
    • 沒有最佳解,只有最適合的選擇
  • 抽象/化學複雜(Complex)
    • 重複實驗評估,直到事情逐漸明確可以進行下一步,
    • 通常要大量的試錯才能有解答
  • 混亂(Chaotic)
    • 你只能依賴直覺,先逃離危險,分析情況後再決定下一步
  • 無序(Disorder / Confusion)
    • 如果你無法分辨情況,就是處理無序的狀態
    • 先搜集資訊,分析再前進
      Cynefin 框架

練習

  1. Obvious : 多語抽換字串
  2. Complicated : 整個 sprint 範圍多個頁面抽換;
    RD 彼此衝突 / Merge Before Build 造成的衝突與浪費
  3. Complex : 風險控管多種理由不準上線
  4. Chaotic : 上線後引發 SQL 問題當下是混亂的

回饋

1
2
3
4
5
6
7
8
9
10
11
1.
組織或團隊會抗拒改變;
又或者組識本身的價值觀與 Scrum 有所抵觸。
以這個層面來說 Scrum Master 能作得很有限,
所以又有 Agile Coach 的產生 ? → 說穿了就是顧問 ?
第一現場的工作者給的問題,如果不虛心接受
以現場角度思考,全盤歸疚於心態問題,是在逃避問題
抱著過往成功不放,不願具體改變或聆聽異議,
由上而下獨幹而非由下而上改變,喊喊口號「速度感起來了!」
敏捷淪為口號,實踐就成了宗教儀式。
不論是 Scrum Master 或是 Agile Coach 都是觀察者/顧問的角色,
1
2
3
4
5
轉型的路上我質疑一切
質疑主管、質疑公司、質疑理論、質疑作法;
甚至質疑我自已,然後我的心態還不能崩了,
真是有病…
要正心,保持陽光。
1
2
3
4
5
6
7
8
9
10
11
12
13
Unit Tests Team ?
為什麼有這樣的想法 ? 單元測試很重要,卻沒有人寫。
原因1. 沒有時間
原因2. 流程內未包含寫單元測試與執行單元測試,
Scrum 的 User Story 或 Task 也不會包含,驗收條件也不包含 Unit Tests。
原因3. 責任規屬不明? QA Team 專心作測試,RD Team 專心作開發
沒有一個團隊專門來處理單元測試
原因4. 導入失敗
- 跨領域 BeckEnd、F2E、IOS、Android 缺乏足夠知識
- 跨專案開發資源就不夠了,怎麼寫測試 ?
- 遺留代碼難以開發,技術水平不夠,缺乏領頭羊。
- 讀書會成為逆向宣傳。
- 沒有人專職導入,導入船過水無痕。

Unit Tests Team ?

參考

(fin)

[閱讀筆記] The Great Scrum Master 第一章

ScrumMasterWay

大綱

  • Scrum Master 的角色與責任
    • 自組織
    • Scrum Master 的目標
    • Scrum Master Pattern
      • Scrum Master 是團隊成員
      • Scrum Master 是 Product Owner
      • Scrum Master 是人事經理
      • Scrum Master 兼任多支團隊
    • Scrum Master 領導
      • 僕人式領導

CH1 Scrum Master 的角色與責任

  • 不是團隊的祕書
  • 不是額外的開銷
  • 負責創造高績效團隊
  • Agile 與 Scrum 思想的專家(信徒)

質疑

1
2
3
4
5
我一直認為盲信是相當危險的,這個世界與其說*沒有銀子彈*,
不如說沒有狼人,或是說你面對的永遠不只是狼人,而是未知。
現場看到太多的 Scrum But(我比較喜歡叫 Scrum Buffet 或敏捷自助餐)
當人人都說「敏捷大法好」的時候,我分不清邪教大典/直銷與敏捷的差別了…
還是鬼島就是神祕力量能將好東西質變成孬東西呢?

自組織

我們應該如何組織我們自已,達成目標?

  • 決定誰作什麼
  • 協助對方
  • 學習新知
  • 劃分優先級

Scrum Master 要提醒個人,團隊是一個實體,比個人更重要

Scrum Master 的目標

  • Scrum Master 建立自組織的團隊
  • Scrum Master 教練與引導
  • Scrum Master 不負責交付
  • Scrum Master 負責排除障礙(而非斟茶遞水的祕書)
  • Scrum Master 鼓勵團隊承擔責任

Scrum Master Pattern

Scrum Master 是團隊成員

  • con
    • 參與過多,缺乏系統觀點與系統思考的能力
    • 缺乏領導能力與變革管理的技能
    • sprint 無法按時完成時,通常會不太願意改進團隊
    • 缺乏將進一步提昇團隊的能力
  • pro
    • 通常與團隊高度互相信任
    • 了解團隊的優缺點
  • result
    • Scrum Master 角色被邊緣化
    • Scrum Master 變成團隊助理或無事可作

Scrum Master 是 Product Owner

  • con
    • 角色本身會互相衝突
  • pro
    • Product Owner 較容易被視作團隊的一份子
  • result
    • Scrum Master 角色會被忽略
    • Product Owner 控制所有事情
    • 團隊缺乏自組織

Scrum Master 是人事經理

  • con
    • 團隊對 Scrum Master 缺乏信任
    • 往往變成下命令,教導而非輔導
  • pro
    • 優秀的領導者當 Scrum Master 可以加速過渡轉型期
  • result
    • 可以縮短轉型期
    • 團隊對缺乏自組織、自信與所有權

Scrum Master 兼任主管 可

能成為團隊成員無法暢欲所言的原因,更不樂見的是,也許主管本身就是阻礙。
但同時這也會帶來一些機會,擁有管理權限的主管,
會更有力道推動變革,也可以直接調動資源,給予團隊更快更實際的支援。

→ to be read one more time

Scrum Master 兼任多支團隊

  • con
    • Scrum Master 缺乏時間
    • 不同團隊同時發生問題時無法即時引導
    • 通常兼任超過三支團隊會缺乏足夠訊息
  • pro
    • Scrum Master 能快速學習
    • 較能了解不同團隊有不同文化
  • result
    • Scrum Master 能累積更多經驗
    • Scrum Master 在系統思考上表現較好
    • 更有可能將 Scrum 應用於整個組織
回饋
1
2
3
4
5
6
7
8
9
10
20180717 讀書會
Q:Scrum Master 應該先成為觀察者的角色,
再進一步作引導或指導,兼任多支團隊的情況下,
可能會受限於環境,導致無法作第一線的觀察,而導致效果不佳。
A:較成熟的團隊可以稍微放一下,多參與初心團隊,
自組織的成熟團隊就不必要每件事。
feedback:
1. 不成熟的 Scrum Mater 應該跟著成熟的 Scrum Master 共事。
2. 不成熟的團隊應由成熟的 Scrum Mater 帶領。
3. 成熟的團隊 Scrum Mater 的角色仍在,但是可以淡出。

Scrum Master 領導

  • Scrum Master 要注重整個組織,非單一支 Scrum 團隊,
  • 關心長期目標與策略。
  • 領導者不是由時間表所趨動的。

僕人式領導

  • 傾聽
  • 同理心
  • 治療關係
  • 要意示到自已是領導者(你要帶領團隊到何方?)
  • 說服而非權威
  • 承諾他人成長
  • Big Picture — 在日常與短期目標之中,抱持繪製遠景的能力
  • 管家 — 抱持開放與服務他人
  • 先見之明 — 經驗與直覺
  • 建立共同體

(fin)