你的第一份大型開源專案--Servo 瀏覽器
- 2018-01-29
- Liu, An-Chi 劉安齊
Your First Big OSS Project: Servo Browser
¶ 前言
開放原始碼軟體,又稱開源軟體(Open Source Software),顧名思義是將軟體的原始碼公開。詳細介紹可以看維基百科介紹以及什麼是開源一文。
身為軟體開發者,我們常常會需要很多工具來幫助我們更簡單完成工作,而且我們都知道沒事不要自己造輪子,這時候就會看看網路上有沒有現成的工具。例如想要開發機器學習可能就會用 Tensorflow,想要開發網頁前端可能會使用 Angular,想要開發 Android App 可能會用 Kotlin,平常用的 gcc 或 clang,甚至 Linux 作業系統通通都是開源軟體。
取之於社會,回饋於社會。在我們享受開源軟體的無窮好處之虞,也想為開源軟體盡一份心力,不僅讓更多人受惠,也滿足自己的成就感。貢獻開源有很多種,可以是協助建立文件、幫忙翻譯、解決 bug、開發新功能,此外開源軟體也有分大跟小,大的專案例如 Chrome 瀏覽器,小的專案可能只是 VSCode 的擴充功能。當我們野心比較大的時候,就會希望自己能貢獻一些大型專案,而不是小專案而已,而且會希望自己能開發出核心功能,不僅僅是改個小 bug 或幫忙翻譯文件而已。
但是大型開源軟體往往已經發展過於龐大,面對已經有數十萬、數百萬行的軟體而言,一個新手想要參一咖並不容易,更何況還沒有其他開源經驗。
本篇將選定 Servo 瀏覽器作為一個想要貢獻大型開源專案新手的第一份專案,目前我在 Servo 專案中在八百名貢獻者中排名約前五十,算是活躍貢獻者之一。此外因為我本身熱愛開源,所以也參加了不少開源專案。希望透過我的經驗,帶大家進入開源的世界!
¶ 什麼是 Servo 專案
Servo 專案是 Mozilla 的實驗性質瀏覽器引擎,目的是加強安全性以及採用平行化加速處理,並慢慢將成熟的模組移植到 Mozilla 旗下的瀏覽器 Firefox。Servo 以 Rust 語言開發,該語言強項正是安全性與平行化。當初就是發現很多 Firefox 有很多 bug 是 C++ 產生,其中最常見的問題便是記憶體錯誤,於是後來有了 Rust 語言的誕生。在使用 Rust 情況下,幾乎不會產生原本 C++ 導致的問題。
¶ Servo 有什麼好處
如果說將一個開源專案成熟度分為三級:成熟、中間、陽春,Chromium(Chrome 的開源版本)就是成熟,而 Servo 則是中間,因為 Servo 還在開發中,只完成最重要的工程,還有很多細節沒有實作。
不過這也是初學者學習 Servo 好處,因為專案還沒發展過於龐大,學習曲線相對 Chrome 這類專案來說,比較不那麼陡。藉由開發 Servo 的過程,更容易對瀏覽器有更完整的了解,之後去看 Webkit、Gecko、Blink 等發展已久的大型瀏覽器引擎時,也會更容易上手。
此外因為很多功能還沒實作,初學者比較有機會直接對核心模組(Core Module)貢獻,通常發展已久的大型專案核心部分都已經非常龐大或完整,新手比較難有機會對其貢獻,即使是核心模組的 bug 難度通常也很高,畢竟那是程式最重要的部分,幾乎不會有低級的錯誤。
但由於 Servo 還處於中期,很多瀏覽器該有的重要功能,因為重要順序稍微低一點所以還沒實作,就是新手大展身手的好時機,並且瀏覽器都會遵循網頁技術的規範,所以開發時常常有文件可以對照著開發。
除了上述幾點之外,因為 Servo 是一個網路瀏覽器,意即就是在寫一個讓人可以打開網頁的程式,你會對瀏覽器如何處理網頁有更深入的理解。對前端工程師來說,也許瀏覽器就像個黑盒子,開發好的網頁給瀏覽器執行就會渲染出網頁畫面,但是對其中的機制卻不太了解。當我們了解一個網頁是如何從網頁原始碼被解析,到渲染出圖層被渲染出來之後,在寫網頁的時候就能針對瀏覽器運作的機制做優化。
¶ 在開始貢獻之前
有一些基礎知識我們必須先瞭解,首先 Servo 以及目前市面上數以百萬計的開源專案都是採用 Git 版本控制工具,以及 Github 這個網路協作平台,目的是要讓程式碼方便管理以及讓多人可以同時開發。
關於 Git 與 Github 的科普入門可以看這篇(1)和這篇(2)文章,作者本身並非工程師,相信對原本熱愛寫程式的大家來說應該會很好懂。如果還有一些不清楚,可以多 Google 幾篇文章應該就會有點感覺了!
當你會使用 Git 和 Github 之後,你需要知道什麼是 Fork 和 Pull Request,這是 Github 上提交 Patch(補丁)的方式。當你有新的點子,或是想要修補臭蟲,就可以透過 Fork 動作複製一份原始碼,然後進行修改後。實際改好程式碼之後,就可以就可以發出 Pull Request(合併請求),請原本專案的管理者將你的更動,合併到原始的專案中。
再來就是 Servo 主要是以 Rust 語言當作軟體的開發語言,以 Python 作為輔助工具語言,所以需要先去了解一下語言怎麼寫,語法是怎樣等等。並且因為我們開發的是網路瀏覽器,最好要能懂怎麼寫一個簡單的網頁,包含 HTML、CSS、JavaScript。
此外每個開源專案都會有自己的「Code of Conduct」,裡面會規範貢獻者該遵守的規則,通常就是必須友善包容,不得污辱謾罵其他人。
¶ 瀏覽器原理
知道瀏覽器是怎麼一回事對我們開始開發瀏覽器會很有幫助,How Browser work 是一篇很好的起手文,他宏觀的解釋瀏覽器在幹嘛,也就是你打開 Chrome、Safari 這些軟體是怎麼去讓網頁變成看得見的網頁。比較深入可以看我寫的《來做個網路瀏覽器吧!》系列文章,此系列文章可以邊研究 Servo 專案邊看,應該會讓你更快上手!
¶ 取得源碼、編譯 Servo
在我們繼續了解怎麼參與貢獻專案之前,先來用源碼編譯看看,確定能編譯成功我們才能繼續下一個步驟。
首先到 Servo 的 Github 頁面,先點「Fork」複製一份原始碼到自己的帳號底下。
接著要把源碼從自己的複製的版本下載下來:
git clone https://github.com/你的Github帳號/servo.git
接著照 Servo 的環境建設指南,選擇你的系統環境,將需要的套件安裝和設定。
這邊假設你是使用 Ubuntu,那流程就會是:
# rustup 是 rust 語言的工具,為 Servo 專案必備
curl https://sh.rustup.rs -sSf | sh
# 安裝套件
sudo apt install git curl autoconf libx11-dev \
libfreetype6-dev libgl1-mesa-dri libglib2.0-dev xorg-dev \
gperf g++ build-essential cmake virtualenv python-pip \
libbz2-dev libosmesa6-dev libxmu6 libxmu-dev \
libglu1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev \
libharfbuzz-dev ccache clang
# Ubuntu 17.04 之後
sudo apt install libssl1.0-dev
# Ubuntu 17.04 之前
sudo apt install libssl-dev
這邊要注意的是,Servo 的源碼隨時在更新,需要用到的套件可能也會改動,這面這些只是我寫文章當下所需要的,時間久了可能就不準,到時候還是必須上 Servo 的 Github 去看比較準。
接著就可以試著編譯看看了,先進入專案,然後我們會用到 mach
工具,這是 Servo 專案的入口程式,用來執行各種指令。
cd servo
# 編譯
./mach build -d
# 執行
./mach run -d https://google.com
原則上如果設定都照指南完成,應該可以順利編譯和執行,如果過程中產生任何無法解決的問題,可以在 Servo 專案上面發布 issue,說明你的環境設定和錯誤訊息。
順利執行的話應該能看到有視窗跳出來,並且將 Google 的頁面渲染出來了。
¶ 開始貢獻
我覺得開源專案中最困難的一步,就是真的要來修改原始碼,一開始我們大概無法直接去實現新的功能、增加一個模組,通常是先去找有沒有簡單的 bug 可以解決。
多數待解決的問題都會列在 issue 頁面上。在 Servo 上可以去找「E-esay」標籤的 issue 當作起手,通常是團隊成員認為最簡單適合新手的,才會標上此標籤。
Servo 專案事實上用到很多子專案以及衍伸專案,例如 webrender 模組就被獨立切出來。所以如果想要看看更多待解決的問題,可以使用 Servo Starters 這個網站來查詢議題,裡面收集包含 Servo 專案以及周遭專案的的各種起手問題。
由於我們第一次參加這個開源專案,從中選一個標有 Easy
或 Good First Issue
等標籤的問題會比較適合。接著就來介紹如何開發。
¶ 開發流程
這邊以 Servo 專案為例講解流程,而以 Github、Gitlab 為平台開發的大型專案工作,不管是不是開源(差別只是公開或是私有),其實流程都很類似,可以說是現代軟體開發的制式流程了!
大致可以歸納成以下步驟:
- 找到目標
- 參考文件
- 實際開發
- 單機測試
- 送出審查
- 自動化測試
- 進入主幹
¶ 找到目標
首先就是要找想做什麼,一但選好你有興趣的 issue,確認對話串中沒有人聲明說目前正在進行中,你就可以聲明要認領這個問題。
如果看了問題覺得有興趣,可是卻還是沒概念,這時候不用怕,總之先喊說你想要解決。
通常標註 E-esay
標籤本來就是希望給新手練習的機會,此外即便沒有標註簡單標籤,任何的 issue 也可以大膽去接,因為在開源社群中大家都很樂於幫助新手和回答任何問題。
你可以在 issue 下這樣留言:
Hi @someone, I would like to take this issue.
Hi @someone, I would like to take this issue.
Someone 可能是專案的成員,或著是發布 issue 的其他貢獻者,總之在你開始工作前記得先喊一聲,先搶先贏,喊到的人就必須試圖將 issue 解決,而其他人不應該再來跟你搶。
以 Servo 來說,你可以在下面留言 @highfive: assign me
,highfive
是此專案的機器人,它會替 issue 自動加上「被認領」標籤。
有任何不懂,或是開發過程中遇到困難,千萬不要怕問很白痴的問題。大家都是從問白癡問題開始學起的,專家眼中的 Easy
可能是新手眼中的 Super Hard
。
所以這時候你可以問更多細節:
- Could you tell me where is the relevant code?
- What is the purpose of
Foo Function
and how it affectsbar Function
? - How could I test the result? How could I write a new test?
- Are there any specification? Where is it?
或是你覺得 issue 本身就描述的很難懂了,完全沒有概念要怎麼做。這時候可以直接問能不能給更多細節:
Hi @someone, I would like to solve this issue. However I don’t know how to do. Could you tell more detail about how to implement/fix this issue.
Hi @someone, I would like to solve this issue. However I don’t know how to do. Could you tell more detail about how to implement/fix this issue.
發布 issue 的作者或是其他貢獻者會來回答你,如果你還是覺得不清楚,可以繼續追問,不用怕對方不耐煩或是覺得丟臉,開源社群就是這樣注重互相幫助,重點就是你敢不敢問。
¶ 參考文件
不同的專案都會有必須遵從的規範和文件,例如一個影音播放軟體,就需要遵從各種影片格式來做處理,或是模組與模組之間可能已經定義好 API 如何設計。
而瀏覽器開發最常參考的兩個文件分別是 W3C 和 WHATWG 兩個組織所規範的:
針對不同的技術部份,會有各種文件明確規範,如 DOM、XHR、CSS 等等。
基本上所有開發都必須遵從規範,瀏覽器開發者依照規範設計瀏覽器,網頁開發者依照規範設計網頁,規範可以說是兩者的橋樑,確保網站設計者心中想的網頁,可以正確被瀏覽器渲染出來。並且因為大家都遵照同一份規範設計瀏覽器,才能讓 Chrome 顯示的畫面跟 Firefox 一樣,不然網頁開發者豈不是要針對不同瀏覽器都寫一份程式碼?
¶ 實際開發
這邊以這個 issue: Support cloning steps for textarea/input 為例,假設我們選定這個當作要解決的目標。
這個 issue 是因為 WHATWG 的 HTML 文件有更新,所以要讓 Servo 與最新的標準一致。而要修正的地方就是直接對照文件變動的部分。
對應的 Pull Request 是這一支,可以看到我改了兩個檔案,一個是 htmltextareaelement.rs
另個是 cloning-steps.html.ini
。
rs
即為 Rust 檔案,顧名思義是處理 HTML text area element,所以針對這個檔案做改動。
.ini
檔比較特殊,他是指通過不了 WPT 測試(等等會介紹)的檔案,例如 cloning-steps.html
還通過不了,所以有 cloning-steps.html.ini
來記錄。因為這邊實作之後可以通過了,所以就把 .ini
檔案刪除。
總之這步驟就是將 issue 中所描述的問題解決,可能是除 bug,或是增加新功能。過程中碰到問題都可以在 issue 上發問。
¶ 單機測試
Web Plateform Tests(WPT) 是 W3C 的專案,針對目前網路文件的規範制定的測試,用意是確保大家都有乖乖遵守規範走。Chrome、Firefox、Safari、Edge 等主流瀏覽器,都會確保新的 commit 通過測試,才會合併進 master。
在 Servo 專案中,大多數的程式碼都會對應到 WPT 測試的某部分。例如你改了 Canvas 的相關程式碼,WPT 裡面就有關於 Canvas 的測試。
如果不清楚改動 Servo 的程式碼對應到的是什麼 WPT 測試,可以直接在 issue 或 PR 上發問。
而在其他專案中,可能會要求你針對改動的部分,寫新的 Unit Test,總之測試是為了證明自己改動的程式碼是有效的。
¶ 送出審查
你改好程式碼之後,就可以發 Pull Request(PR),意思是希望你的改動可以被放進專案中。
首先將改好的 branch 先 push 進入自己倉庫,然後上 Github 自己的倉庫,點擊「New Pull Request」
接著會進入比較頁面,先選取你剛剛新改的 branch,這邊假設是 fix
(記得要把你的改動上傳到 Fork 的 Repo)。
Github 會將你自己的 fix
這個分支與 servo 專案的 master
做比較。然後就可以點「Create new pull request」。
接著在專案的 Pull Request 頁面就會有你剛剛發出的新 PR,接著就等待 Reviewer 來審查。
在這邊要插題一下,一般的開源一個專案中都大概可以分為三種職位,分別為 Member、Commmiter 或 Reviewer、Contributor。Member 為專案核心成員,可以決定專案的方針,大型變動都必須有核心成員同意,以及審查新的核心成員。Commiter 或 Reviewer 有權限直接對專案存取,同時也為專案的審查者,負責審查新的 PR,但無決定專案走向的權限。Contributor 為一般的貢獻者,必須提交 PR 給 Reviewer 審查,審核通過 Patch 才會被合併進專案中。
Reviewer 會針對你的 PR 給建議,然後你會需要改進你的程式碼。當你的改動被審查者同意之後,審查者會給你一個r+
代表同意讓 PR 被合併了。以 Servo 專案來說,審查者會呼叫機器人 @bors-servo r+
告訴機器人他同意變動,讓機器人去跑下一步驟的自動化整合測試。
每個專案在這邊的步驟可能不太一樣,但核心概念就是你的補丁必須要有審查者同意才行。而行話術語 r+
代表核可,r-
代表否決,不過被否決別灰心,持續與審查者討論並修改,最後拿到 r+
!
¶ 自動化整合
任何大型軟體的開發週期,都會有持續整合(CI)的步驟,開源專案自然也不例外。簡單來說,持續整合就是確保新的變動,可以順利編譯,可以順利通過所有測試,通過所有檢測項目之後,變動才能被整合進專案中。
在 Servo 專案中,被 r+
的 PR,機器人會讓這個 PR 去跑 CI,在這個網站中可以觀察測試的情況,測試項目包含:Linux、Windows、macOS、Arm 編譯、Linux 和 MacOS 上跑 web platform tests(WPT)、模糊測試、單元測試、nightly Rust 編譯。
解釋一下,因為 Servo 是跨平台瀏覽器,所以要確保每個平台都能順利編譯。WPT 先前解釋過,所有瀏覽器會遵從文件規範。測試 nightly Rust 是因為 Servo 和 Rust 相輔相成,所以要確保最新版的 Rust 能順利編譯 Servo。
¶ 進入主幹
當 CI 順利跑完沒有錯誤,程式碼就可以順利安全地合併到專案中。通常這個步驟都是自動化的,Servo 中也是由機器人負責這步驟。
假若 CI 過程中發現有測試過不了,就會回到送出審查的步驟,你必須重新提交新的正確程式碼,然後讓審查者重新認可。如此循環直到 CI 能順利通過,你的改動才會被合併到主幹中。
如果你的 patch 順利被 merge 進專案中,恭喜你,你現在已經是這個專案的貢獻者之一了!
¶ 結論
本文大致介紹如何加入一個開源專案,雖然是以 Servo 瀏覽器為例,但其實大多數專案的流程和思維都差不多。不過開源流程可能會有所差異,像是 Apache、Linux 這類的就是採用 Mail List 的協作方式,貢獻者會直接將 patch 寄給審查者,並不透過平台。而本文則是以 Github 平台開發為例,目前 Github 上已經有數百萬的專案了!
如果你有興趣加入開源專案,從小型的專案開始會比較容易,但若是你和我一樣喜歡挑戰大型專案,我認為 Rust、NodeJS、React、Angular 或是 Servo 都是不錯的選擇,他們都是 Github 開發,且社群活躍。社群活躍與友善度對一個新手來說非常關鍵,能不能得到適當幫助是最重要的事情!
我覺得參與開源專案很有意思,可以學習新的知識,對軟體開發更加熟練,學習和世界各國的開發者溝通,且當自己的貢獻成為數百、數千萬使用者的軟體的一部分也會非常有成就感。
我想開發軟體絕對不是難事,在社群、專案成員的幫助下,即使有困難也容易得到幫助,但難的是如何與人溝通,開發者來自不同國家,如何用英文正確表達想法、說服對方才是最不簡單的地方。
最後,開源是一種無償付出的精神,你不會有實質回饋,但你可能因為自己做了一件了不起的事而有成就感。開源講求熱情,唯有持續從成就感中獲得動力,才有力氣繼續無私地為社會貢獻。
願大家都能從開源中找到自己的熱情! 😋