郭⾄至軒 [:kuoe0]
Software Engineer at Mozilla
kuoe0.tw@gmail.com
在開始⼯工作以前
我以為我會寫扣
Photo credit: Toomore, CC 2.02016.05.02 @成⼤大資⼯工
郭⾄至軒 [:kuoe0]
Software Engineer at Mozilla
kuoe0.tw@gmail.com
在開始⼯工作以前
我以為我會寫扣
Photo credit: Toomore, CC 2.02016.05.02 @成⼤大資⼯工
code
Update: May 2, 2016
Attribution-ShareAlike 3.0
(CC BY-SA 3.0)
http://creativecommons.org/licenses/by-sa/3.0/
關於我
- 成⼤大資⼯工系⺠民國 101 年畢業
- 成⼤大資⼯工所⺠民國 103 年延畢
- ⺫⽬目前於 Mozilla 打⼯工度⽇日
- 專⻑⾧長:
- 什麼都碰⼀一點(打雜)
龐⼤大的扣
“20 世紀,最⼤大的開源碼專案就是
Mozilla,其中的程式碼約為數⼗十萬⾏行。
-Jserv
時⾄至今⽇日...
$ cloc mozilla-central
---------------------------------------------------------------------------------------
Language files blank comment code
---------------------------------------------------------------------------------------
C++ 9310 655681 510876 3605447
JavaScript 23090 472137 478171 2619350
HTML 39156 213777 64569 1835986
C/C++ Header 12623 369164 708616 1630724
C 3309 265682 385116 1590975
Python 2962 96486 116409 394024
Java 2099 50050 86259 229256
IDL 1252 14057 0 101759
---TL;DR---
善⽤用⼯工具(⼈人)來追扣
- 網⾴頁(以 Firefox 來說):
- https://github.com/mozilla/gecko-dev
- https://dxr.mozilla.org/
- 指令⼯工具:
- grep: http://linux.die.net/man/1/grep
- find: http://linux.die.net/man/1/find
- git: https://git-scm.com/
- gdb (on runtime): https://www.gnu.org/software/gdb/
- rr (on runtime): http://rr-project.org/
- 問問題:
- Mentor
- Author
- Colleague
https://dxr.mozilla.org/ https://github.com/
git grep
關於問⼈人
“⼤大家都很忙。你可以問問題,頻率⼤大概
⼀一、兩天⼀一次。如果是每⼗十五分鐘就要
問⼀一次的話就不太好了...
-外國同事
從寫扣到進扣
Develop
Test
Push to
inbound
FirefoxReview Push to
central
Test
根本爛扣
測試爆炸
這扣還⾏行
測試通過 測試通過
這扣能動
爛扣
記憶體洩漏
memory leak
未使⽤用變數
unused variable
懸空指標
dangling pointer
函式 / 變數命名不好
bad naming
效率不佳
low performance
Reviewer 不喜歡
dislike by reviewer
記憶體洩漏
memory leak
未使⽤用變數
unused variable
懸空指標
dangling pointer
函式 / 變數命名不好
bad naming
效率不佳
low performance
Reviewer 不喜歡
dislike by reviewer
爛扣
int main() {
int* x = new int(10);
return 0;
}
記憶體洩漏
memory leak
未使⽤用變數
unused variable
懸空指標
dangling pointer
函式 / 變數命名不好
bad naming
效率不佳
low performance
Reviewer 不喜歡
dislike by reviewer
爛扣
int main() {
int x;
return 0;
}
記憶體洩漏
memory leak
未使⽤用變數
unused variable
懸空指標
dangling pointer
函式 / 變數命名不好
bad naming
效率不佳
low performance
Reviewer 不喜歡
dislike by reviewer
爛扣
int main() {
int* x = new int(10);
delete x;
cout << *x << endl;
return 0;
}
記憶體洩漏
memory leak
未使⽤用變數
unused variable
懸空指標
dangling pointer
函式 / 變數命名不好
bad naming
效率不佳
low performance
Reviewer 不喜歡
dislike by reviewer
爛扣
int main() {
char* x = “a message”;
return 0;
}
爛扣
記憶體洩漏
memory leak
未使⽤用變數
unused variable
懸空指標
dangling pointer
函式 / 變數命名不好
bad naming
效率不佳
low performance
Reviewer 不喜歡
dislike by reviewer
單元測試 (UNIT TEST)
#include “func.h”
int func1() {
return 1;
}
char func2() {
return ‘a’;
}
#include “func.h”
bool test_func1() {
int ret = func1();
if (ret == 1)
return true;
else
return false;
}
bool test_func2() {
char ret = func2();
if (ret == ‘a’)
return true;
else
return false;
}
int func1();
char func2();
func.h
func.cpp test.cpp
程式碼退回
編譯根本不會過
⾃自⼰己寫的 test 不會過
把別⼈人的 test 弄壞
扣的開發與維護
沒使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
hw1
沒使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
hw1
沒使⽤用版本控制系統時 我的電腦
hw1_v1
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:嗚嗚嗚,好吧...(OS:怕把原本
可以正常運作的版本弄壞,複製⼀一份好
了!) hw1_v2
沒使⽤用版本控制系統時 我的電腦
hw1_v1
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:嗚嗚嗚,好吧...(OS:怕把原本
可以正常運作的版本弄壞,複製⼀一份好
了!)
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
hw1_v2
沒使⽤用版本控制系統時 我的電腦
hw1_v1
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:嗚嗚嗚,好吧...(OS:怕把原本
可以正常運作的版本弄壞,複製⼀一份好
了!)
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
學⽣生:嗚嗚嗚嗚嗚,好吧...(OS:再複
製⼀一份好了,免得改壞...)
hw1_v2
hw1_v3
沒使⽤用版本控制系統時 我的電腦
hw1_v1
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:嗚嗚嗚,好吧...(OS:怕把原本
可以正常運作的版本弄壞,複製⼀一份好
了!)
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
學⽣生:嗚嗚嗚嗚嗚,好吧...(OS:再複
製⼀一份好了,免得改壞...)
…
…
…
…
…
助教:⽼老師說還是太簡單,我們再加最
後⼀一次功能!
hw1_v2
hw1_v3 hw1_v…
hw1_v… hw1_v…
沒使⽤用版本控制系統時 我的電腦
hw1_v1
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:嗚嗚嗚,好吧...(OS:怕把原本
可以正常運作的版本弄壞,複製⼀一份好
了!)
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
學⽣生:嗚嗚嗚嗚嗚,好吧...(OS:再複
製⼀一份好了,免得改壞...)
…
…
…
…
…
助教:⽼老師說還是太簡單,我們再加最
後⼀一次功能!
學⽣生:助教...我硬碟爆了 QQ
hw1_v2
hw1_v3 hw1_v…
hw1_v… hw1_v…
使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
hw1
使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
hw1
使⽤用版本控制系統時 我的電腦
hw1
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:沒問題!
original
v2
使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:沒問題!
助教:⽼老師說還是太簡單,再加另⼀一個
功能! hw1
original
v2
使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:沒問題!
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
學⽣生:喔喔好的,沒問題!
hw1
original
v2
v3
使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:沒問題!
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
學⽣生:喔喔好的,沒問題!
…
…
…
…
…
助教:⽼老師說還是太簡單,我們再加最
後⼀一次功能!
hw1
original
v2
v3
使⽤用版本控制系統時 我的電腦
學⽣生:YA,作業 1 完成!
助教:⽼老師說作業 1 太簡單了,要加些
功能才⾏行!
學⽣生:沒問題!
助教:⽼老師說還是太簡單,再加另⼀一個
功能!
學⽣生:喔喔好的,沒問題!
…
…
…
…
…
助教:⽼老師說還是太簡單,我們再加最
後⼀一次功能!
學⽣生:助教...同學的硬碟爆了 QQ
hw1
original
v2
v3
v…
v…
實際開發上常⽤用功能...
git checkout -b
<branch>
- 建⽴立開發新功能⽤用的 branch
- 建⽴立⼀一個 debug 的 branch
git rebase -i <commit>
- 調整 commit 的順序
- 將 commit ⼀一分為⼆二
- 合併多個 commit 合為⼀一個
git rebase <branch> - 將⾃自⼰己的修改套到指定的 branch
git commit --amend - 將⺫⽬目前的修改也放到前⼀一個 commit 中
WORK IN MOZILLA
RUSThttps://www.rust-lang.org/
https://play.rust-lang.org/
關於 RUST
- 針對速度、安全與平⾏行化所設計的系統程式語⾔言
- 強型別 (strong typing)
- 靜態作⽤用域 (static scoping)
- 由 Mozilla Research 贊助與主導開發
HELLO WORLD
fn main() {
println!("Hello, world!");
}
變數
- 變數預設為不可修改的 (immutable)
- 對 immutable 的變數進⾏行修改,編譯器會告訴你!
- 把沒有修改必要的變數宣告為可以修改的 (mutable)
- ⼀一個 mutable 的變數都沒有被修改,編譯器會告訴你!
- 不得使⽤用未初始化的變數
- 使⽤用未初始化的變數,編譯器會告訴你!
錯誤範例 程式碼 錯誤訊息
試圖對 immutable
變數進⾏行修改
fn main() {
let x: i32 = 10;
x = 20;
println!("{}", x);
}
<anon>:3:5: 3:11 error: re-
assignment of immutable variable
`x` [E0384]
<anon>:3 x = 20;
^~~~~~
⼀一個 mutable 變
數從沒被修改
fn main() {
let mut x: i32 =
10;
println!("{}", x);
}
<anon>:2:9: 2:14 warning: variable
does not need to be mutable,
#[warn(unused_mut)] on by default
<anon>:2 let mut x: i32 = 10;
^~~~~
使⽤用未初始化的
變數
fn main() {
let x: i32;
println!("{}", x);
}
<anon>:3:20: 3:21 error: use of
possibly uninitialized variable:
`x` [E0381]
<anon>:3 println!("{}", x);
^
所有權 (OWNERSHIP)
- 確保記憶體對應到的變數只有⼀一個
- 賦值運算、參數傳遞都是 move(交出所有權)
- 不得使⽤用已經被 move 的變數
錯誤範例 程式碼 錯誤訊息
賦值運算
fn main() {
let x = vec![1, 2, 3];
let y = x;
println!("{}", x[0]);
}
<anon>:4:20: 4:21 error: use of moved
value: `x` [E0382]
<anon>:4 println!("{}", x[0]);
^
參數傳遞
fn print_first_elem(v:
Vec<i32>) {
println!("{}", v[0]);
}
fn main() {
let x = vec![1, 2, 3];
print_first_elem(x);
println!("{}", x[0]);
}
<anon>:8:20: 8:21 error: use of moved
value: `x` [E0382]
<anon>:8 println!("{}", x[0]);
^
借⽤用與參考 (BORROWING & REFERENCE)
- 使⽤用借⽤用語法可以避免 move 的發⽣生
- 借⽤用的變數預設也是不可修改的
- immutable borrowing
- 要修改借⽤用的變數需要明確指出是可修改的
- 被借⽤用的變數本⾝身也需要是可修改的
- mutable borrowing
- 被借⽤用的變數在歸還前不得進⾏行修改的操作
- 被借⽤用為可修改的變數時不得再被借⽤用
語法 程式碼 輸出
immutable borrowing
fn main() {
let x = 10;
let y = &x;
println!("{}", y);
}
10
mutable borrowing
fn main() {
let mut x = 10;
{
let y = &mut x;
*y += 1;
}
println!("{}", x);
}
11
immutable borrowing
on function
fn print_first_elem(v: &Vec<i32>) {
println!("{}", v[0]);
}
fn main() {
let x = vec![1, 2, 3];
print_first_elem(&x);
println!("{}", x[0]);
}
1
mutable borrowing on
function
fn inc_first_elem(v: &mut Vec<i32>) {
(*v)[0] += 1;
}
fn main() {
let mut x = vec![1, 2, 3];
inc_first_elem(&mut x);
println!("{}", x[0]);
}
2
錯誤範例 程式碼 錯誤訊息
不得修改被借⽤用中的
變數
fn main() {
let mut x = 10;
let y = &x;
x += 1;
println!("{}", x);
}
<anon>:4:5: 4:11 error: cannot
assign to `x` because it is
borrowed [E0506]
<anon>:4 x += 1;
^~~~~~
被借⽤用為可修改的變
數時不得再被借⽤用
fn main() {
let mut x = 10;
{
let y = &mut x;
let z = &x;
}
println!("{}", x);
}
<anon>:5:18: 5:19 error:
cannot borrow `x` as immutable
because it is also borrowed as
mutable [E0502]
<anon>:5 let z = &x;
^
總結
- Rust 編譯器很會抓錯
- 還會給你建議的修改⽅方法
- 預設 move 的⾏行為
- 確保了只有⼀一個變數擁有該記憶體的所有權
- 預防懸空指標 (dangling pointer)
- 只能有⼀一份 mutable borrowing
- 確保資料⼀一致性
- 我也不熟,想瞭解更多請移駕:
- https://www.rust-lang.org/documentation.html
- http://askeing.github.io/rust-book/
Q&A

在開始工作以前,我以為我會寫扣。