[學習筆記] Linux 語法學習筆記 一

參考

學習筆記

Clear

清除目前 terminal 畫面

Cal

產生當下的月曆

$ cal

March 2018
Su Mo Tu We Th Fr Sa

         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

$ cal 2 1985

February 1985
Su Mo Tu We Th Fr Sa

            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

Date

顯示日期與時間

$ date

Sat Mar 10 19:01:37 UTC 2018

$ date  ‘+ %y-%m-%d %n %H:%M:%S:%N’

18-03-10
 19:06:24:126172657

pwd

目前所在的檔案路徑

Touch

建立檔案

mkdir

建立資料夾

cat

寫檔案 cat > filename

ctrl + d 可以離開編輯

讀檔案 cat < filename

合併檔案 cat file1 file2 > merged_file

$ cat > file1
this is file1
$ cat file1
this is file1
$ cat > file2
this is file2
$ cat file2
this is file2
$ cat file1 file2 > merged_file
$ cat merged_file
this is file1
this is file2

mv

重新命名檔案

mv origin_name new_name

rm

刪除檔案或資料夾

$ rm file_name

$ rm -r folder_name/

rmdir

刪除資料夾

$ rmdir folder_name/

cp

複製檔案

$ cp oldfile other_folder/newfile

ln

$ touch one
$ cat < one
$ ln one two
$ ls
one two
$ cat > one
this is one
$ cat < one
this is one
$ cat < two
this is one

hard link 會產生實體檔案,soft link 只是指標的轉向.
如果使用 soft link,當刪除原始檔案時,link 檔案將無法開啟.

檔案權限概觀

三種權限

  • read / 讀 / 100 => 4
  • write / 寫 / 010 => 2
  • execute / 執行 / 001 => 1

每個權限都有一個代號,
read 表示可讀權限, 意味著可以開啟檔案與看見內容,
代號為 4,二進位表示為 100
write 表示可以複寫其內容,
代號為 2,二進位表示為 010,
execute 代表可執行,適用可執行檔或 shell script,
代號為 1,二進位表示為 001.
三種權限都有的話,權限為(111=>7)

三種身份

  • owner 開啟的帳號
  • owner group 開啟的帳號所屬的群組
  • other group 其它的群組

新增一個檔案的時候,
預設只有讀寫,沒有執行的權限 (100|010=110=>6)

指令 umask 的設定值以三個八進位的數字“nnn”代表。
第一個設定數字給使用者自己(owner user),
第二個則是設定給用使用者所屬的群體(group),
第三個給不屬於同群體的其它使用者(other)。
每一位數字的設定值都是三項不同權限的數值加總,
read 權限數值為 4;write 權限數值為 2;execute 權限數值為 1。
結合了前三者的權限數值,單一的數字可設定的範圍是 0 ~ 7;
整體的可設定範圍是 000 ~ 777。
— 鳥哥的 Linux 私房菜

ls

列出資料夾中的所有檔案

ls foldername

列出指定的資料夾中所有的檔案

ls -l

列出資料夾中的所有檔案與其權限資訊

ls 最常被使用到的功能還是那個 -l 的選項,為此,很多 distribution 在預設的情況中, 已經將 ll (L 的小寫) 設定成為 ls -l 的意思了!其實,那個功能是 Bash shellalias 功能呢
— 鳥哥的 Linux 私房菜

chmod

修改檔案權限

sh-4.4$ ls -l
total 4
-rw-r–r– 1 33581 33581 978 Mar 12 17:30 README.txt
-rw-r–r– 1 33581 33581 0 Mar 12 17:32 test
sh-4.4$ chmod 777 test
sh-4.4$ ls -l
total 4
-rw-r–r– 1 33581 33581 978 Mar 12 17:30 README.txt
-rwxrwxrwx 1 33581 33581 0 Mar 12 17:32 test
sh-4.4$ chmod 444 test
sh-4.4$ ls -l
total 4
-rw-r–r– 1 33581 33581 978 Mar 12 17:30 README.txt
-r–r–r– 1 33581 33581 0 Mar 12 17:32 test

uname

顯示系統相關的資訊

$ uname -a                                                            
Linux e955582759de 3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 
2017 x86_64 x86_64 x86_64 GNU/Linux

選項與參數:
-a :所有系統相關的資訊,包括底下的資料都會被列出來;
-s :系統核心名稱
-r :核心的版本
-m :本系統的硬體名稱,例如 i686 或 x86_64 等;
-p :CPU 的類型,與 -m 類似,只是顯示的是 CPU 的類型!
-i :硬體的平台 (ix86)
— 鳥哥的 Linux 私房菜

file

查詢檔案基本資料(類型)

file *

jazzy: ASCII text
mark: empty
marsen: directory

wc

顯示檔案資訊

行數 字數 字元數 檔名

$ wc jazzy

3 10 39 jazzy

wc -l filename

顯示檔案行數資訊

wc -w filename

顯示檔案字數資訊

wc -c filename

顯示檔案字元數資訊

sort

印出排序過後的結果(遞增)

$ sort
owls
pigs
dogs
cats

cats
dogs
owls
pigs

sort filename

印出檔案內排序過後的結果(遞增)

cut

切割資料

參數:
-d 分割字元
-f index (從 1 開始)

範例

cat > filenames
Name-Sport-Age
Roger-Tennis-30
Nadal-Tennis-25
Tiger-Golf-37
Michael-Baseball-49

$ cut -d”-“ -f 1,3 filenames
Name-Age
Roger-30
Nadal-25
Tiger-37
Michael-49

dd

資料處理、拷貝、備份、轉碼;更多

$ cat > infile
this is the input file
$ cat infile
this is the input file

$ dd if=infile of=outfile conv=ucase
0+1 records in
0+1 records out
23 bytes copied, 6.6972e-05 s, 343 kB/s
$ cat outfile
THIS IS THE INPUT FILE

man

查詢其它指令用法

$ man ls

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
LS(1)	User Commands  LS(1)
NAME ls - list directory contents
SYNOPSIS ls [OPTION]... [FILE]...

DESCRIPTION
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of
-cftuvSUX nor --sort is specified.

Mandatory arguments to long options are mandatory for short options too.
-a, --all
do not ignore entries starting with .

-A, --almost-all
do not list implied . and ..

--author
with -l, print the author of each file

-b, --escape
print C-style escapes for nongraphic characters
Manual page ls(1) line 1 (press h for help or q to quit)

h看更多訊息

$ man ls
h

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
                   SUMMARY OF LESS COMMANDS

Commands marked with * may be preceded by a number, N.
Notes in parentheses indicate the behavior if N is given.

h H Display this help.
q :q Q :Q ZZ Exit.
---------------------------------------------------------------------------

MOVING

e ^E j ^N CR * Forward one line (or N lines).
y ^Y k ^K ^P * Backward one line (or N lines).
f ^F ^V SPACE * Forward one window (or N lines).
b ^B ESC-v * Backward one window (or N lines).
z * Forward one window (and set window to N).
w * Backward one window (and set window to N).
ESC-SPACE * Forward one window, but don't stop at end-of-file.
d ^D * Forward one half-window (and set half-window to N).
u ^U * Backward one half-window (and set half-window to N).
ESC-) RightArrow * Left one half screen width (or N positions).
ESC-( LeftArrow * Right one half screen width (or N positions).
F Forward forever; like "tail -f".
r ^R ^L Repaint screen.
HELP -- Press RETURN for more, or q when done

q退出查詢畫面

輸出用#組成的大形文字

實測未出現,上網查了一下 banner 好像有蠻多不同的類型可以安裝?

compress

壓縮檔案

zcat

讀取壓縮檔案

uncompress

解壓縮檔案

compress 已經退流行了。為了支援 windows 常見的 zip,其實 Linux 也早就有 zip 指令了! gzip 是由 GNU 計畫所開發出來的壓縮指令,該指令已經取代了 compress 。
— 鳥哥的 Linux 私房菜

小結

以上是一些基本的 Linux Command ,
下一篇,我們會建立.sh 檔,將 Linux Command 依照指定的順序執行
並使用 sh 命令執行
用以完成一些更進階的工作.

(more..)

[學習筆記] AWS EC2 學習筆記 AWS CLI 與 Login

安裝 AWS CLI

配置 AWS CLI

EC2 開機

EC2 開機

  • 直接開機跳過網路設定(也還沒有辦法設)
  • 第 5 步驟設定 TAG ,對找尋 ec2 的 instance 很有幫助

設定 Putty

連線機器

連線機器

ex:

1
ssh -i /path/my-key-pair.pem [email protected]

預設連線帳戶

For Amazon Linux, the user name is ec2-user.
For Centos, the user name is centos.
For Debian, the user name is admin or root.
For Fedora, the user name is ec2-user.
For RHEL, the user name is ec2-user or root.
For SUSE, the user name is ec2-user or root.
For Ubuntu, the user name is ubuntu or root.
Otherwise, if ec2-user and root don’t work, check with your AMI provider.

windows 好像是 Administrator ? 求補充

Docker

安裝 Docker

1
sudo yum install docker

啟動 Docker 服務,並讓它隨系統啟動自動載入

1
2
sudo service docker start
sudo chkconfig docker on

雷包

  • 重啟機器的話 public dns 會改變.(意味連線的命令參數會變)
  • 注意使用的 AIM, 不同的 Linux OS 會有不同的套件執行命令
  • ubuntu apt-get
  • CentOS yum

參考

(fin)

[讀書會] 單元測試的藝術 - 導讀、序與第一章

要知道的事

  1. 這是單元測試的藝術的閱讀筆記
  2. 筆記的意思就是不一定會有心得
  3. 這篇主要是導讀

譯者序

  • TDD , Test First to Think First
  • 什麼是好的單元測試?
  • 單元測試三支柱:可信任 可讀性 可維護
  • 綠色安全區域
  • 實務上導入的指引

入門建議

  • 了解如何隔離相依(Part II)
  • Stub 與 Mock 的差異,熟練隔離框架(NSubstitute)
  • 如何撰寫優秀的單元測試(Part III)

進階建議

  • 如何撰寫優秀的單元測試(Part III)
  • 如何在組織中導入單元測試(Part IV)
  • 針對遺留代碼的重構與測試,以及可測試性設計(Part IV)

避免

  1. 測試不穩定
  2. 過度指定
  3. 一次不只測一件事
  4. 測試程式重複過多
  5. 可讀性差

關於本書

前言

有寫測試, 也不保証專案成功,
一個失敗的單元測試案例,
作者歸納原因如下,

  • 脆弱的測試(Prod 改一點,測試就錯一大片)
  • 不易維護
  • 測試間相護依賴
  • 可讀性差

作者推薦的框架

學習路線圖

  • Part I 基礎知識
  • Part II 測試框架
  • Part III 最佳實踐
  • Part IV 組識導入/遺留代碼/設計

目錄

  1. 入門
    • 什麼是優秀的單元測試
    • 單元測試與整合測試的分別
    • 第一個單元測試
  2. 核心技術
    • Stub
    • IoC(DI)
    • 值、狀態與互動
    • 測試框架
    • 事件
    • 深入了解測試框架
  3. 測試程式碼
    • 自動化
    • 綠色安全區域
    • 可信任/可維護/可讀性
  4. 設計與流程
    • 組織導入
    • 遺留代碼
    • 設計與可測試性

定義單元測試

什麼是優秀的單元測試

  1. 自動化, 可重複執行
  2. 容易實現*
  3. 到第二天還有存在的意義(非臨時性的,ex:hotfix)
  4. 任何都可以一鍵執行
  5. 執行速度快
  6. 結果一致
  7. 可以完全控制(不與外部相依)
  8. 獨立於其他測試
  9. 失敗時,錯誤應該是明確的

整合測試

  1. 整合測試相依於真實物件
  2. 整合測試的結果不穩定
  3. 整合測試與單元測試應該被分開(見 ch7.2.2)
  4. 整合測試執行時間長
  5. 依據現實狀況無法完全控制
  6. 缺點: 一次測試的東西太多

理解測試趨動開發

  1. TDD 不保證產品會成功
  2. 步驟
    1. 寫一個失敗的測試
    2. 寫一個符合測試預期的產品程式碼,以通過測試
    3. 重構

TDD 的核心技能

  1. 可維護、可讀、可靠(這本書的目的)
  2. 寫出可維護、可讀、可靠的測試不等於 TDD,至於如何寫優秀的 TDD,作者推薦閱讀〈Test-Driven Development:by Example〉
  3. 就算執行 TDD,也不保証能設計一個完善的系統,作者推薦閱讀Growing Object-Oriented Software, Guided by Tests無瑕的程式碼

簡單說就是:

  • 寫好測試
  • 測試先行(TDD)
  • 設計

作者認為這是三種技能, 同時學習三種技能門檻會相當的高, 最後導致放棄.

小結

  • 優秀的測試就是
    • 自動化
    • 容易撰寫
    • 執行快速
    • 任何人都可以執行,並得到相同結果

揪錯

印刷錯誤

本書資源

  1. Samples
  2. The Art Of Unit Testing
  3. Videos

(fin)

[活動筆記] 變異測試 - 一種改進測試和代碼的 「新」 方法

應該知道的事

  • 範例使用 Java
  • 這場活動使用人肉找尋變異
  • 實務上應使用工具
  • 但是不能完全相信工具
  • 活動聯結
  • 講師是 Odd-e 的姚若舟
  • 簡報 preview 版

什麼是變異

前言

想像一下產品(Production)就是你的身體,
我們可以透過健康檢查(Unit Test);
檢查你的身體有沒有異狀 ?

但是檢查真的可靠嗎 ?
比如說一般的流感的快篩只有 50~60%的準確率,
我們的測試也無法達到 100%準確率(這裡不是指覆蓋率喔).
如何抓到測試抓不到的漏網之魚就是變異測試的目的.

我們透過讓 Production 產生變異(Mutation)
來確認我們的 Unit Test 是否可靠.

題外話,當大流行的時候會跳過快篩節省醫療資源,
因為可能有一半(50%)的患者都是流感,
而快篩準確率也只有 50%,加上時間及醫材成本,
不如直接開克流感能有效抑止疫情

變異測試(Mutation Testing)

變異後導致測試失敗?
yes , good
應該要失敗,表示你的測試有覆蓋到這個變異

no , test not covered
這表示你的測試並未

測試不一定能補捉變異

比如說 邊際值 或是 隱含的互動;
測試覆蓋率 100%也不一定能補捉變異
要麼少了 test case,
要麼多了無意義的代碼
看看以下例子
ex:

1
2
3
4
5
6
foo(x,y)
{
//// logic here
sideeffct();
return z;
}

反思一下, 測試過了代碼就沒問題 ?
不能捉到變異的測試,
有發揮它的功能嗎 ?
一般來說如果透過 TDD 進行軟體開發,
我們的測試應該是會恰巧符合一項 Test Case
而如果是先寫代碼再寫測試,
將很難通過變異測試(容易產生多餘的代碼)

找到變異的幾個方向

  • 邊界條件(< => <=)
  • 反向條件(< => >)
  • 移除條件(永真/永偽)
  • 數學
  • 遞增/遞減
  • 常量
  • 返回值
  • 移除代碼

先寫代碼再寫測試有問題是很正常的

Kata-PokerHands 範例

原碼(使用 java)

變異實例

有問題 ,反向測試案例不足

1
2
3
4
5
6
7
private List<Integer> getPairCardRanks(List<Integer> cardRanks) {
List<Integer> result = new ArrayList<>();
for (int index = 0; index < CARD_COUNT - 1; index++)
if (isTwoNeighborCardRanksEquals(index, cardRanks))
result.add(cardRanks.get(index));
return result;
}

有問題 , -1 但是預期中的行為

1
2
3
4
5
6
protected   Integer   getThreeOfAKindCardRank(List<Integer\> cardRanks) {
for (int index = 0; index < CARD_COUNT - 2; index++)
if (isThreeNeighborCardRanksEquals(index, cardRanks))
return cardRanks.get(index);
throw new IllegalStateException();
}

其它

  1. 沒有 TDD 沒有單元測試,別跑變異測試
  2. 至少要有行級別的覆蓋率(line coverage)
  3. 分支覆蓋(Branch Coverage)好一點 仍不夠
  4. 在需求不變的情況下,再作變異測試
  5. 以變異測試的角度來說,覆蓋率 100%是木有用的(testing coverage is useless)
  6. 發現變異怎麼辦
    • 報告(記錄)
    • 重現
    • 評估
    • 修改 或 補測試
  7. 依靠工具不要相信工具,上一步的評估
    Ex: mock 物件會取代互動實際的行為,導致變異測試失敗

Tools

參與者心得

  1. 變異測試 (Mutation Test) —  一種提高測試和代碼質量的 ”新”  方法速記

  2. Test - 變異(Mutation)測試之你的測試到底是寫爽的,還是有效的?

心得

  1. 佩服當天就能寫出文章的人
  2. 變異測試是好上加好的測試
  3. Odd-e 的講師真的很粉棒, 雖然不致到毀三觀 不過眼界大開

參考

(fin)

[活動筆記] 蝦皮購物新加坡研發團隊技術分享會

應該不用知道的事

  1. 雖然是「技術分享會」實際上在徵才
  2. 不過還是有半場的技術分享
  3. 91app 至少去了 10 個人(含前員工)
  4. 這篇文章對你應該沒有幫助

有關蝦皮

  • 屬於Sea 集團的一部份
  • 東南亞多國服務(新加坡、泰國、馬來西亞、印度、台灣、越南…)
  • 63e Request / Day
  • 8G IO / Mins

選擇

  • Native App / Web / Hybrid / RN ?
  • Cloud / Self machine ?
  • Php/ Nodejs / RoR / Django ?
  • Apache / Nginx ?
  • C ++ / Java / GoLang
  • Memcached / Redis ?
  • SPA / MPA ?
  • Mesos / Kubernetes ?

Qiz & Ans

1

用戶下單的時候, 先收錢還是先扣庫存?
扣掉最後一件庫存後, 收錢失敗怎麼辦?
你已經把「賣完」訊息發給了賣家, 怎麼辦?

2

計算金額用整數還是浮點數?(浮點數不準)

3

Android 一共有幾種螢幕的 DPI ?
Android WebView 和 Chrome 的 Webkit 有何不同 ?

4

Web Service 花最多時間在處理什麼 ?
如何壓搾最高的吞吐量 ?
IO, USE async

5

什麼樣的情境適合增加伺服器數量來增進效能?
stateless
那有狀態怎麼辦 ?

6

load balancer 效能到達瓶頸怎麼辦 ?
IP

7

一天 25TB 的 Log 數量,怎麼不會查到天荒地老

8

Cache & 超賣問題
什麼時候要清 Cache ?

9

Database Master 與 Slave 哪個壓力大 ?(Slave)
增加 index 的代價為何 ?(Space)
Table 多大要 shard ?
Database 多大要分庫 ?
分庫如何作 transaction ?

實踐

  1. Prototype 簡單 Production 困難 (邊際效應/熵)
  2. 可靠:言出必行,作不到也要早點說(知難行易)
  3. Redis 的資料超過 64G 就無法用 bgsave 有效存檔
  4. 在 Production 千萬別用 Redis 的 key 指令
  5. 衡量的基準(benchmark)為何?
  6. 不要對邏輯下 command(不要寫前因後果)
    • Don’t command How
    • Command Why
    • Collect your dots first
    • Connecting the dots

持久發展的研發團隊

  • knowledge
  • 保持開放
  • 尊重事實
  • 信任
  • 可靠
  • 找到根本原因(root cause)
  • 分析 修復 記錄
  • Docs
    • connection docs
    • collection docs

測試

  • 白箱測試
  • 黑箱測試

其它

  • Hypergraph
  • Tech Stack
  • Roles
    • countries PM
    • function PM
  • Scrum 是跑給老闆看的(!!?)
  • 馬來西亞不用小豬 ICON(各地風俗民情不同)

參考

(fin)

[翻譯] C# 的常見錯誤

出處

http://www.dotnetcurry.com/csharp/1417/csharp-common-mistakes

線上工具

https://dotnetfiddle.net

引言

C#是個好棒棒的言語,但是它仍會有超乎你想像的行為,
而且就算你是有經驗的開發者,你也要看一看這篇文章.
這篇文章不講幹話,還會給你代碼喔

C# Quiz

Null Value

Null 很危險啦, 你別在 Null 身上調用方法
(譯注:在公司的維運人員應該還蠻常見這個錯誤的 一 ω 一)

We are all aware that null values can be dangerous, if not handled properly.
Dereferencing a null-valued variable (i.e. calling a method on it or accessing one of its properties)
will result in a NullReferenceException, as demonstrated with the following sample code:

1
2
object nullValue = null;
bool areNullValuesEqual = nullValue.Equals(null);

就安全的角度,好像我們要不停的檢查 reference type 是不是 null ,
雖然這件事常常發生,好像也很難說成是非預期的行為了…
(譯注:又有種中槍的感覺)

To be on the safer side, we should always make sure that reference type values are not null before dereferencing them.
Failing to do so could result in an unhandled exception in a specific edge case.
Although such a mistake occasionally happens to everyone, we could hardly call it unexpected behavior.

看看這個代碼, null 值在 runtime 的時候不會有 type 的

1
2
string nullString = (string)null;
bool isStringType = nullString is string;

No, null 值在 runtime 的時候不會有 type 的
No, null 值在 runtime 的時候不會有 type 的
No, null 值在 runtime 的時候不會有 type 的
很重要所以說三次,
當然你也別想呼叫 GetType() 方法

The correct answer is No.

A null value has no type at runtime.

In a way, this also affects reflection.
Of course, you can’t call GetType() on a null value because a NullReferenceException would get thrown:

1
2
object nullValue = null;
Type nullType = nullValue.GetType();

純量呢?

1
2
3
int intValue = 5;
Nullable<int> nullableIntValue = 5;
bool areTypesEqual = intValue.GetType() == nullableIntValue.GetType();

那我們可不可能用反射(reflection)區分 nullable 跟 non-nullable 的值?
答案是不可能, 看看後面的代碼

Is it possible to distinguish between a nullable and a non-nullable value type using reflection?

The answer is No.

The same type will be returned for both variables in the above code: System.Int32.
This does not mean that reflection has no representation for Nullable, though.

1
2
3
Type intType = typeof(int);
Type nullableIntType = typeof(Nullable<int>);
bool areTypesEqual = intType == nullableIntType;

上面兩段程式在 runtime 拿到的 type 很不一樣喔,
一個是System.Int32一個是 System.Nullable'1\[System.Int32\]

當 null 遇上多載方法 (Handling Null values in Overloaded methods)

1
2
3
4
5
6
7
8
9
private string OverloadedMethod(object arg)
{
return "object parameter";
}

private string OverloadedMethod(string arg)
{
return "string parameter";
}

上面有兩個OverloadedMethod
猜猜看,傳入 null 時會呼叫哪一個方法?

1
var result = OverloadedMethod(null);

有人會猜編譯失敗嗎?
MAGIC ! 竟然可以編譯成功, 而回傳的值是 “string parameter” ,
一般來說,在編譯時期會作型別檢查,相同簽章的方法參數可以被轉型成另一個型別時,是可以編譯成功的喔.
而有明確型別的方法將被優先調用(譯注:求這段.Net Framework 的原碼來看一下,知道的人請告訴我)

如果要指定 null 參數呼叫的多載方法就要對 null 轉型唷,可以參考下面的方法.

1
var result = OverloadedMethod((object)null);

算術運算 (Arithmetic Operations)

好像很少用位移運算吼?
回憶一下 左移移 右移移

1
var shifted = 0b1 << 1; // = 0b10
1
var shifted = 0b1 >> 1; // = 0b0

bits 跑到底並不會重頭開始喔,一直移位到爆掉就變 0 了.
(這裡會用 32 是因為 int 是 32bit 的數值,你可以試試放超過 32 的數值到 for loop 裡會發生什麼事)

The bits don’t wrap around when they reach the end.
That’s why the result of the second expression is 0.
The same would happen if we shifted the bit far enough to the left (32 bits because integer is a 32-bit number):

1
2
3
4
5
var shifted = 0b1;
for (int i = 0; i < 32; i++)
{
shifted = shifted << 1;
}

The result would again be 0.

那我們是不是可以一次移 32 bit,讓它一次變成 0 呢?
靠北啊 竟然不行捏, 你只會拿到 1,
這跟運算子(operator)基本運算有關,在作位元運算的時候,
會拿第一個運算數除以第二個運算數後取餘數,
這導致我們只會拿 32 % 32 的結果 , 也就是 1 啦
(譯注:這段其實我不是很確定,如果錯誤請糾正)

However, the bit shifting operators have a second operand.
Instead of shifting to the left by 1 bit 32 times, we can shift left by 32 bits and get the same result.

1
var shifted = 0b1 << 32;

Right? Wrong.

The result of this expression will be 1. Why?

Because that’s how the operator is defined. Before applying the operation,
the second operand will be normalized to the bit length of the first operand with the modulo operation,
i.e. by calculating the remainder of dividing the second operand by the bit length of the first operand.

The first operand in the example we just saw was a 32-bit number, hence: 32 % 32 = 0.
Our number will be shifted left by 0 bits. That’s not the same as shifting it left by 1 bit 32 times.

好棒棒 你竟然可以看到這裡,
那我們繼續討論 & (and) 跟 | (or) 運算子吧,
這兩個運算子跟一般的運算子有點不一樣

  • 通常只要看運算子的第一個運算數就能得知結果
  • 在有掛 [Flag] attribute 的列舉它們好好用(看一下範例)
1
2
3
4
5
6
7
8
[Flags]
private enum Colors
{
None = 0b0,
Red = 0b1,
Green = 0b10,
Blue = 0b100
}
1
2
Colors color = Colors.Red | Colors.Green;
bool isRed = (color & Colors.Red) == Colors.Red;

上面這個刮號可不能省略喔, 因為(&)運算符的優先順序低於(==)運算符,
不過這段程式沒有刮號的話連編譯都不會過,真是好加在
另外在 .NET framework 4.0 之後的版本提供更棒的方法去檢查 flags

1
bool isRed = color.HasFlag(Colors.Red);

Math.Round()

猜一下這個值會是多少?

1
var rounded = Math.Round(1.5);

猜 2 的就答對了, 下一題
猜一下這個值會是多少?

1
var rounded = Math.Round(2.5);

還是 2 ,
因為預設會取最接近的偶數

No. The result will be 2 again. By default,
the midpoint value will be rounded to the nearest even value.
You could provide the second argument to the method to request such behavior explicitly:

1
var rounded = Math.Round(2.5, MidpointRounding.ToEven);

這個行為可以透過MidpointRounding參數改變

1
var rounded = Math.Round(2.5, MidpointRounding.AwayFromZero);

另外要小心浮點數的精度問題,
以下的例子結果會是 1,( 因為 float 的 0.1 實際上小於 0.1 一 ω 一 )
這提醒我們在處理精確數值時,應轉換成整數處理.
(譯注:使用 dotnet fiddle 時並不會有這個問題, 在 windows 環境下測試的確會有問題)

1
2
3
var value = 1.4f;

var rounded = Math.Round(value + 0.1f);

類別初始化

最佳實踐建我我們應該避免在建構子初始化類別,
特別是靜態建構子.
在初始化一個類別的順序如下

  1. 靜態欄位
  2. 靜態建構子
  3. 實體欄位
  4. 實體建構子

看看這個例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class Config
{
public static bool ThrowException { get; set; } = true;
}

public class FailingClass
{
static FailingClass()
{
if (Config.ThrowException)
{
throw new InvalidOperationException();
}
}
}

當我們嘗試實例化 FailingClass 時,你會得到 Exception;
值得注意的事,你拿到的會是TypeInitializationException
而並不是InvalidOperationException,

那麼我們是不是可以試著透過 try catch 補捉錯誤,
並修改靜態屬性,重新實體化 class 呢?
答案是不行

一個靜態建構值,如果它拋出一個異常,
那麼無論何時你想創建一個實例或以任何其他方式訪問這個類,
這個異常都會被重新拋出.

1
2
3
4
5
6
7
try
{
var failedInstance = new FailingClass();
}
catch (TypeInitializationException) { }
Config.ThrowException = false;
var instance = new FailingClass();

這個類別在程序重啟前是不能再被使用了(會拋出錯誤),
這在 C# 是個非常糟糕的實踐,
千萬別這樣設計你的類別.

The static constructor for a class is only called once.
If it throws an exception, then this exception will be rethrown
whenever you want to create an instance or access the class in any other way.

The class becomes effectively unusable until the process (or the application domain) is restarted.
Yes, having even a minuscule chance that the
static constructor will throw an exception, is a very bad idea.

繼承與類別初始化

繼承的類別初始化執行順序更加複雜,看看下面的例子

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
public class BaseClass
{
public BaseClass()
{
VirtualMethod(1);
}

public virtual int VirtualMethod(int dividend)
{
return dividend / 1;
}
}

public class DerivedClass : BaseClass
{
int divisor;
public DerivedClass()
{
divisor = 1;
}

public override int VirtualMethod(int dividend)
{
return base.VirtualMethod(dividend / divisor);
}
}

當我們初始化 DerivedClass

1
var instance = new DerivedClass();

你會得到一個除 0 的錯誤 DivideByZeroException
這與執行順序有關

  1. 呼叫 BaseClass 建構子
  2. 執行 DerivedClass VirtualMethod (overrid BaseClass)
  3. divisor 未賦值拋出 DivideByZeroException

多形 Polymorphism

這個例子只是要說明多形的概念與應用,
你可以透過轉形呼叫基底類別的方法.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var instance = new DerivedClass();
var result = instance.Method(); // -> Method in DerivedClass
result = ((BaseClass)instance).Method(); // -> Method in BaseClass
// The correct answer is: by using the new modifier.

public class BaseClass
{
public virtual string Method()
{
return "Method in BaseClass ";
}
}

public class DerivedClass : BaseClass
{
public new string Method()
{
return "Method in DerivedClass";
}
}

It’s typically used to hide the interface methods from the consumers of the class implementing it,
unless they cast the instance to that interface.
But it works just as well if we want to have two different implementations of a method inside a single class.
It’s difficult to think of a good reason for doing it, though.

另外一個例子是明確實作介面方法,
如果你的類別已經有同名的方法的話.
雖然沒有什麼好理由建議你這樣作.
(譯注:實務上我有在遇到歷史共業這樣作過…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var instance = new DerivedClass();
var result = instance.Method(); // -> Method in DerivedClass
result = ((IInterface)instance).Method(); // -> Method belonging to IInterface
It’s explicit interface implementation.

public interface IInterface
{
string Method();
}

public class DerivedClass : IInterface
{
public string Method()
{
return "Method in DerivedClass";
}

string IInterface.Method()
{
return "Method belonging to IInterface";
}
}

迭代器 Iterators

小心 Iterators 的陷阱
看看以下代碼:

1
2
3
4
5
6
7
8
private IEnumerable<int> GetEnumerable(StringBuilder log)
{
using (var context = new Context(log))
{
return Enumerable.Range(1, 5);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Context : IDisposable
{
private readonly StringBuilder log;

public Context(StringBuilder log)
{
this.log = log;
this.log.AppendLine("Context created");
}

public void Dispose()
{
this.log.AppendLine("Context disposed");
}
}

假設我們 foreach 呼叫 GetEnumerable 方法,
你預期 Context 類別會有什麼樣的行為?
我們會印出以下的 output 嗎?

Context created
1
2
3
4
5
Context disposed

1
2
3
4
5
var log = new StringBuilder();
foreach (var number in GetEnumerable(log))
{
log.AppendLine($"{number}");
}

不是的,
實際上印出的是

Context created
Context disposed
1
2
3
4
5

這點很重要,
因為實務上你很有可能 using dbconnetion 之類的物件,
那麼你在取得真正的資料之前,
你的連線就已經中斷了

This means that in our real world database example, the code would fail –
the connection would be closed before the values could be read from the database.

看看以下的修正

1
2
3
4
5
6
7
8
9
10
private IEnumerable<int> GetEnumerable(StringBuilder log)
{
using (var context = new Context(log))
{
foreach (var i in Enumerable.Range(1, 5))
{
yield return i;
}
}
}

譯注:看到這裡對 yield return 的使用情境才比較有感啊…

如果你不太熟yield return,其實它只是個語法糖,允許增量執行,
參考以下範例,或許能更容易理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private IEnumerable<int> GetCustomEnumerable(StringBuilder log)
{
log.AppendLine("before 1");
yield return 1;
log.AppendLine("before 2");
yield return 2;
log.AppendLine("before 3");
yield return 3;
log.AppendLine("before 4");
yield return 4;
log.AppendLine("before 5");
yield return 5;
log.AppendLine("before end");
}
1
2
3
4
5
6
7
var log = new StringBuilder();
log.AppendLine("before enumeration");
foreach (var number in GetCustomEnumerable(log))
{
log.AppendLine($"{number}");
}
log.AppendLine("after enumeration");

before enumeration
before 1
1
before 2
2
before 3
3
before 4
4
before 5
5
before end
after enumeration

值得注意的事, 如果你在 loop 當中重複執行以上的代碼,
那麼 Iterators 也會重複執行

1
2
3
4
5
6
7
8
9
10
var log = new StringBuilder();
var enumerable = GetCustomEnumerable(log);
for (int i = 1; i <= 2; i++)
{
log.AppendLine($"enumeration #{i}");
foreach (var number in enumerable)
{
log.AppendLine($"{number}");
}
}

輸出如下,可以明顯看到 GetCustomEnumerable 方法,
實際上被隱含的執行了兩次,
這在 Code Review 的階段也是難以被察覺的.

enumeration #1
before 1
1
before 2
2
before 3
3
before 4
4
before 5
5
before end
enumeration #2
before 1
1
before 2
2
before 3
3
before 4
4
before 5
5
before end

比較好的作法是將 IEnumerable ToList(),
如果你真的需要對 IEnumerable 的結果作 loop 的操作

1
2
3
4
5
6
7
8
9
10
var log = new StringBuilder();
var enumerable = GetCustomEnumerable(log).ToList();
for (int i = 1; i <= 2; i++)
{
log.AppendLine($"enumeration #{i}");
foreach (var number in enumerable)
{
log.AppendLine($"{number}");
}
}

輸出結果

before 1
before 2
before 3
before 4
before 5
before end
enumeration #1
1
2
3
4
5
enumeration #2
1
2
3
4
5

譯者小結

如果真的能夠預期所有的行為的開發人員,
真的是好棒棒,
對我來說 static class constructor 的行為是超乎預期的,
然後對 yield return 的使用場景更有感覺了.
本來預計農曆年就可以完成的翻譯,
竟然也拖了這麼久,看來我英文還是不行啊.

希望對大家有幫助,也請多多看原文 :)

(fin)

[學習筆記] AWS 註冊到建立安全性帳戶

該知道的事

  1. 僅作為學習 AWS 的過程記錄用
  2. 可能對你有幫助
  3. 可能對你沒幫助
  4. 有沒有幫助都歡迎你提出問題與討論

創建帳號

這段蠻簡單的,不贅敘;特別一提的事可以使用有 VISA 的金融卡作金額控管
比起信用卡動輒數萬到數十萬的額度,可以在金融卡存個 3000 之類的。
預算可以更彈性,而且精準的控制預算。

另外說一下,現在 AWS 有一年的免費額度(已經有好一陣子了),
在註冊流程跳過付款方式的設定,
實際上也是可以操作的 AWS 的(目前只有設定 IAM)。
(2018/01/31 更新)
確定可以使用有VISA的金融卡開戶,
另外當要實際使用 AWS 的服務時 EX: EC2, Lambda etc…
需要綁定信用卡(VISA 金融卡也可以)才能繼續使用。

綁定的過程會需要輸入電話,AWS 會撥一通電話給你,
螢幕上會出現 4 個數字,照畫面輸入即可完成信用卡(VISA 金融卡)的驗証。

權限控管

Root User

Root User
完成註冊後,一開始只能使用 email 登入,這個帳號可以存取 AWS 所有服務。
AWS 不建議使用 Root User 作為日常的管理帳戶, Root User 應該只被用來建立第一個 IAM

重點項目

  1. Root User 啟用 MFA
    MFA
    首先要下載驗証程式(Google Authenticator),
    然後下一步到以下畫面時,,用 Authenticator 掃瞄 QR Code,
    連續輸入兩次授權碼(輸入完第一組後,等待新的授權碼出現再輸入)

連續輸入兩次授權碼

可以在 IAM Console 檢查成功了沒

IAM Console 2. 建立 IAM User 與指定 Group 權限
AWS IAM 的權限觀念是透過 User 與 Group 來組合的,
權限是授與 Group , 而 User 隸屬於 Group 便擁有其權限,
同時 AWS 提供多組(347 組)預設的 Policies, 讓人選擇
當然也可以建立自已的 Policy. *不確定有沒有反向的 Policy ,
如果有當不同的 Group Policy 有衝突時該如何處理。

Policy

建立使用者時, 使用 AutoGenerated Password 時
要記得取得 password
在最後一步會按下 Show 就會顯示
Show Password 3. 設定 AWS Account ID 與 Alias
設定 AWS Account ID 與 Alias

Q & A

  1. 如何禁用 Root user 登入 ? 可以停用而不刪除一個 user account 嗎?
1
2
3
4
5
6
7
root account 無法停用
IAM User 可以透過 disable passwd 方式停用
root account 基本的 practice
1. 啟用 MFA
2. 移除 Access Credential
概念就跟 Windows Administrator or Linux root 一樣
需要時再用

參考

(fin)

[好文分享]應用部署的六種策略

引用出處

正文開始

目前有各種各樣的技術來將新應用部署到生產環境,
所以權衡對系統和終端使用者的影響降至最少,選擇正確的方式是非常重要的。
本文將著重討論如下部署策略:

  • 重建部署:版本 A 下線後版本 B 上線
  • 滾動部署(滾動更新或者增量釋出):版本 B 緩慢更新並替代版本 A
  • 藍綠部署:版本 B 並行與版本 A 釋出,然後流量切換到版本 B
  • 金絲雀部署:版本 B 向一部分使用者釋出,然後完全放開
  • A/B 部署布:版本 B 只向特定條件的使用者釋出
  • 影子部署:版本 B 接受真實的流量請求,但是不產生響應

我們來看一下每個策略最適合哪種使用者使用場景。
爲了簡化,我們使用 Kubernetes ,並用 Minikube 進行例子演示。
每個策略的配置例子和詳細步驟都可以在這個 git 倉庫 上找到。

重建部署

重建策略是一個冗餘的方式,它包含下線版本 A,然後部署版本 B。
這個方式意味著服務的宕機時間依賴於應用下線和啟動耗時。
重建部署

優點:

  • 便於設定
  • 應用狀態完整更新

缺點:

  • 對使用者影響很大,預期的宕機時間取決於下線時間和應用啟動耗時

滾動部署

滾動部署策略是指通過逐個替換應用的所有例項,
來緩慢釋出應用的一個新版本。
通常過程如下:
在負載排程後有個版本 A 的應用例項池,
一個版本 B 的例項部署成功,可以響應請求時,
該例項被加入到池中。
然後版本 A 的一個例項從池中刪除並下線。
考慮到滾動部署依賴於系統,
可以調整如下引數來增加部署時間:

  • 並行數,最大批量執行數:同時釋出例項的數目
  • 最大峰值:考慮到當前例項數,例項可以加入的數目
  • 最大不可用數:在滾動更新過程中不可用的例項數

滾動部署

優點:

  • 便於設定
  • 版本在例項間緩慢釋出
  • 對於能夠處理資料重平衡的有狀態應用非常方便

缺點:

  • 釋出/回滾耗時
  • 支援多個 API 很困難
  • 無法控制流量

藍綠部署

藍綠部署策略與滾動部署不同,
版本 B(綠)同等數量的被並排部署在版本 A(藍)旁邊。
當新版本滿足上線條件的測試後,
流量在負載均衡層從版本 A 切換到版本 B。
藍綠部署

優點:

  • 實時釋出、回滾
  • 避免版本衝突問題,整個應用狀態統一一次切換

缺點:

  • 比較昂貴因為需要雙倍的資源
  • 在釋放版本到生產環境之前,整個平臺的主流程測試必須執行
  • 處理有狀態的應用很棘手

金絲雀部署

金絲雀部署是指逐漸將生產環境流量從版本 A 切換到版本 B。
通常流量是按比例分配的。
例如 90%的請求流向版本 A,10%的流向版本 B。
這個技術大多數用於缺少足夠測試,或者缺少可靠測試,
或者對新版本的穩定性缺乏信心的情況下。

金絲雀部署

優點:

  • 版本面向一部分使用者釋出
  • 方便錯誤評估和效能監控
  • 快速回滾

缺點:

  • 釋出緩慢

A/B 測試

A/B 測試是指在特定條件下將一部分使用者路由到新功能上。
它通常用於根據統計來制定商業決策,而不是部署策略。
然而,他們是相關的,可以在金絲雀部署方式上新增額外功能來實現,所以我們這裏簡要介紹一下。
這個技術廣泛用於測試特定功能的切換,併發布使用佔大部分的版本。
下面是可以用於在版本間分散流量的條件:

  • 瀏覽器 cookie
  • 查詢引數
  • 地理位置
  • 技術支援:瀏覽器版本、螢幕尺寸、作業系統等
  • 語言
    A/B測試

優點:

  • 多個版本並行執行
  • 完全控制流量分佈

缺點:

  • 需要智慧負載均衡
  • 對於給定的會話,很難定位問題,分散式跟蹤是必須的

影子部署

影子部署是指在版本 A 旁邊釋出版本 B,
將版本 A 進來的請求同時分發到版本 B,
同時對生產環境流量無影響。
這是測試新特徵在產品負載上表現的很好用的方式。
當滿足上線要求後,則觸發釋出新應用。
這個技術配置非常複雜,而且需要特殊條件,尤其是分出請求。
例如一個購物車平臺,如果你想影子測試支付服務,
你可能最終會是使用者為他們的訂單支付兩次。
這種情況下,可以通過建立一個模擬的服務來重複響應使用者的請求。
影子部署

優點:

  • 可以使用生產環境流量進行效能測試
  • 對使用者無影響
  • 直到應用的穩定性和效能滿足要求後才釋出

缺點:

  • 雙倍資源,成本昂貴
  • 不是真實使用者測試,可能出現誤導
  • 配置複雜
  • 某種情況下需要模擬服務

總結

部署應用有很多種方法,實際採用哪種方式取決於需求和預算。
當釋出到開發或者模擬環境時,重建或者滾動部署是一個好選擇。
當釋出到生產環境時,滾動部署或者藍綠部署通常是一個好選擇,
但是新平臺的主流程測試是必須的。
藍綠部署和影子部署對預算有更高的要求,因為需要雙倍資源。
如果應用缺乏測試或者對軟體的功能和穩定性影響缺乏信心,
那麼可以使用金絲雀部署或者 AB 測試或者影子釋出。
如果業務需要根據地理位置、語言、作業系統或者瀏覽器特徵等這樣引數來給一些特定的使用者測試,那麼可以採用 AB 測試技術。
最後但並不是最不重要的,影子釋出很複雜,且需要額外工作來模擬響應分支流量請求,
當可變操作(郵件、銀行等)呼叫外部依賴時這是必須的,
這個技術在升級新資料庫是非常有用,使用影子流量來監控負載下的系統性能。
下表可以幫助你選擇正確的策略:
總結
取決於雲服務提供商和平臺,如下文件是理解部署的很好開始:

  • Amazon Web Services
  • Docker Swarm
  • Google Cloud
  • Kubernetes

希望這是有幫助的,如果有任何問題或者反饋,可以在下面評論

(正文結束)

補充表格翻譯


| 策略 | 服務不斷線 | 真實環境測試 | 預算成本 | 退版時間 | 使用者影響 | 複雜度 |
| ———- | ———- | ———— | ——– | ——– | ———- | —— | — |
| 重建部署 | ✖ | ✖ | ✖ | ★☆☆ | ★★★ | ★★★ | ☆☆☆ |
| 滾動部署 | ✔ | ✖ | ✖ | ★☆☆ | ★★★ | ★☆☆ | ★☆☆ |
| 藍綠部署 | ✔ | ✖ | ✖ | ★★★ | ☆☆☆ | ★★☆ | ★★☆ |
| 金絲雀部署 | ✔ | ✔ | ✖ | ★☆☆ | ★☆☆ | ★☆☆ | ★★☆ |
| A/B 部署 | ✔ | ✔ | ✔ | ★☆☆ | ★☆☆ | ★☆☆ | ★★★ |
| 影子部署 | ✔ | ✔ | ✖ | ★★★ | ☆☆☆ | ☆☆☆ | ★★★ |


非常實用的文章,可惜中譯的圖片並非 gif,原文的超聯結也掉失,
特別重新修正以上問題,留作記錄

(fin)

代碼審查與交付的戰爭ー標準、風格與原則

Coding Standard / Code Review / Pull Request & Delivery

故事背景

  1. 團隊的部署流程是 Github Flow 與 Git Flow 混用 , 給它起個名字叫 GG Flow 好了.
  2. GG Flow 的過程需要開發人員需要透過 Pull Request 將修改推送給產品
  3. 擁有權限 Merge Pull Request 的成員被叫作 Reviewer
  4. Reviewer 通常由較資深人員或部門主管擔任,所以通常有比較多的無用會議要開
  5. Reviewer 在 Merge 之前需要作 Code Review
  6. Reviewer 需要遵循 Coding Standard 作 Code Review

實務面臨的問題與副作用

Coding Standard 並不能考慮到所有狀況

  1. 所以 Reviewers 會定期針對不同的狀況開會討論 Coding Standard
    • Coding Standard 會不定期改變 , 但是透過 Reviewer 佈達的方式,讓第一線的 RD 其實難以知道其全貌.
    • Coding Standard 改變後不會全面的翻改程式,實務上是作到哪裡改到哪裡
    • 以上兩點導致 Source Code 裡面有很多符合不同時期的 Coding Standard 的 Code
    • 任一個時間點, 誰都無法保証完全符合最新的 Coding Standard
  2. 人性,開發者會COPY/PASTE 方法開發參考 Legacy Code 開發
    • Legacy Code 不符合新的 Coding Standard
    • Reviewer 也是人, 所以 Code Review 時也會疏漏,而 Merge 進去不符合新的 Coding Standard 的 Code
    • 所以 Source Code 裡面還是有很多不同時期的 Coding Standard 的 Code
  3. 回歸一開始的問題 Coding Standard 並不能考慮到所有狀況
    • 還沒有開會前, 不同的 Reviewer 會有不同的想法
    • 開會後,在執行 Code Review 時, 不同的 Reviewer 會有不同的作法
    • 當一個 PR 有多人 Reviewer 時, 會有不同的意見 PR 因此被延遲 Merge
    • 結果,交付會變慢.

反思,標準還是風格?

思考一下,開發程式碼的目標與價值是什麼 ?
寫出 Clearn Code ?
還是交付產品 ?
這樣子的 Source Code 真的是 Clearn Code 嗎?

自問自答

Q1. 我們該有標準嗎?

A1. 當然要有標準,不過標準之所以為標準,應該有以下幾個特點.

  • 它應該要很簡單, 像是 Class 與欄位的命名規則
  • 它應放諸四海皆準, 不應該輕易被修改
  • 它應該可以被自動化的檢測
    假設能作到這 3 點, 這件事應該可以被自動化工具處理掉 .

Q2. 實務上就是很複雜, 所以才需要討論制訂標準啊

A2.
在實務上遇到很複雜的情況, 大多需要依賴約定成俗方式規範.
這是一種風格原則 ;
簡單的分類方法,
如果無法透過自動化工具作檢測,
就不應該歸類為標準.

註:有機會再介紹自動化的檢測工具

Q3. 風格原則標準有何不同?

A3. 如上所說,標準應該能被自動化,
風格應該是團隊的文化自然形成的產物,
具體的實作可以透過讓開發者彼此之間作代碼審核
或是結對編程培養出屬於團隊的風格,
風格要基於標準之上,但是不能違反原則;

以下的原則可以作為參考

  • 可以建置並通過測試
  • 可讀性
    • self documenting
    • 有用的註解
  • 公開方法要可以被測試
    • 小心使用靜態類別
    • 注意 new Instance 的時機
    • 重複的代碼應重構
  • 保持 SOLID

初期的可能會發生在「{」要不要換行之類的問題上揪結之類的蠢事,
如果可以自動化,就把它作成標準吧…
如果不行的話, 就別揪結了.

實務上可能遇到各種狀況,
把 Reviewer 的權限下放到各個開發者身上,
或是使用結對編程,
就讓團隊成員去討論與決定風格.

以標準為根基,原則為天,
踩穩腳步,不要超出天空,
就讓團隊自由發揮吧.

最後,持續交付會比每兩周花一個小時開會決定 Style 的細節好多了. 不是嗎?

其它團隊分享的具體作法

  1. 超過一定時間就讓成員擁 Merge 權限
  2. Release 權限仍集中控管
  3. 錯了再改就好(保持敏捷)
  4. 給 pair 作 code review 與 merge (避免一人思維陷井)
  5. 兩個人無法解決時找第三方
  6. release 功能 優先於 一致的 coding standard
  7. 品質由測試管控而非 reviewer
  8. 先有測試才有重構
  9. 可讀性 優於 枝微末節的 coding standard 實踐
  10. 善用自動化工具( sonarqube / stylecop )

(fin)

補充 社群觀點
  • coding style 一般不管的。
  • class name/variable name,一定要叫有意義的名字。
  • local scope variable,換多少行,indentation,這些是小事
  • 一個成熟的 developer,隨時會被上司命令這些遠古火星文明(legacy system)去做考古工作
  • coding style 這些事,就像 emacs 和 vim 之戰一樣,戰到 skynet 出來了也不會戰完的
  • 如果要開會去討論 coding style,最終很可能讓團隊口服心不服地去跟隨我的 Coding Style。
  • 在 Coding Style 這種低層次的小事上用光了團隊成員之間互相容忍的能量,而在更重要的大事上無法好好合作。
  • 有很多事是比 Coding Style 重要的。
    • Object Modeling 是否跟 business logic 一致?
    • 還是 Object 有這個 attribute 但是根本沒在用?
    • Code Change 是否有做好測試?
    • 系統架構是否合理
    • 有做好 High-Avalibility 嗎?
    • 有沒有 Race Condition?
  • 是其是,非其非。真正有道理的,你說了對方便自然會聽下去。
  • 「Senior」是代表自己在專業上懂得比別人多,而不是比別人身份高級。

一年後的我想要什麼?

你的目標是什麼?

自由

什麼是自由?

  1. 情感上的自由
  2. 時間上的自由
  3. 經濟上的自由

經濟上的自由是一切的基礎

  1. 更多的收入
    1. 被動的收入
    2. 更高的薪資
  2. 更有成就感的工作
    1. 被同事尊重
    2. 被上司認可
    3. 受人歡迎
  3. 更多的選擇
    1. 技術提昇
    2. 領域擴展
    3. 人脈
  4. 健康的身體
  5. 更多享受生活

一年後的我想要什麼?

一年後的我想要什麼?

  1. 更高的薪資
    1. 維持現狀 K (x)
    2. 跳糟 K * 1.3 (x)
    3. 爭取加薪 K * 1.1
    4. 獎金與分紅
  2. 更有成就感的工作(什麼是成就感)?
    1. 擁有可以引以為豪的產品
      1. 拆解單體為服務導向
      2. 架構升級

    2. 分享與教學
      1. Blog
      2. 內/外部sharing
      3. 單元測試導入

  3. 更多的選擇
    1. 技術轉移
      1. Web 技術 轉移 為 Service導向技術
      2. container 技術
      3. cloud 技術

    2. 技術提昇
      1. .Net
      2. Infra
      3. Domain know how

爭取加薪 K * 1.1

而這些目標需要什麼才能爭取到?

分為三個面向,技術提昇、技術擴展與自我實現,

技術提昇

首先目前我擁有的技術能力有

  1. .Net solution的 Web Developer能力
  2. 同時兼顧有 DB 與 F2E 基礎進階能力

這與我過去的選擇有關, 一直以來都在 Web 深入研究
未來的一年仍要朝這個方向發展.
但是會改由 Web 導向轉變成服務導向,
而 Web 開發只是我本身所能提供給公司的一個服務而已,
跟著 .Net 的腳步我想把前台(包含大馬但不限於)昇級上一個版本,
包含目前使用的舊版 libary 與 Framework,
如此一來可以使用到新版 .Net 的語法,
同時也可以解開一些導入測試與微服務時遇到的困境.

現有能力列表

  1. C# & .Net Framework Solution (inculde Linq & Entity Framework )
  2. javascript (jQuery & Angular etc..)
  3. Database with Sql (MsSQL solution)
  4. Source Controle (Git)

略懂

  1. nodejs (with expressjs) & php(codeigniter) & ruby (RoR)
  2. Jenkins

技術的擴展

我認為公司的單體架構已經面臨到不得不拆的狀況,
公司也有意朝這個方向走那是最好不過的了,
但對現存的.NET 開發者而言,我認為人人都要有危機意識
我看到的現象

  1. 頁面會被CMS取代
  2. 大部份的API可以被Lambda取代
  3. 主流程的部份在跨國的目標下會逐步變成微服務

基於以上幾點, 除了.Net 的 solution 外,
更多情況是要使用別的 solution 或是混用,
對此我的視野必須有所提昇,

  1. Linux Bash
  2. Container 技術
  3. Cloud (AWS/Azure/GCP)
  4. Node.js
    在未來的一年開發流程或是維運流程會有很大很快的變化
    要多聽多看多想多問,公司有很多人才要儘可能的跟他們學習.

自我營銷

最後是自我實現的部份,
自我營銷是我很弱的一部份,
不善交際,不喜歡人群
這點我從去年就開始調整,
多參與公司內部的分享,不要害怕說錯
假裝自已是對的,再虛心接受別人的指點
不需要導師,因為人人都是我的導師
開始寫Blog並且貼到社群網站給人鞭
這是我目前的 https://blog.marsen.me

今年會繼續朝這個方向衝刺.
多分享 多犯錯 然後接受反饋學習.
兩個部份是我可以練習分享的機會
一個是測試的導入,
我們的遺留代碼,有很多可以分享的部份,
二是讀書會,
借由讀書會可以練習分享,
同時學習別人怎麼分享,
並且看完一本書,一舉數得.

具體主管可以幫助我的部份

  1. 加薪(沒有比這個更務實的了)
  2. 明確指出我的錯誤或是作的好的部份

Do more do faster

(fin)

Please enable JavaScript to view the LikeCoin. :P