如何為開(kāi)源項(xiàng)目撰寫 RFC
關(guān)于 RFC
很多人都一再?gòu)?qiáng)調(diào)過(guò) RFC 的重要性,@tison??在?如何參與 Apache 項(xiàng)目社區(qū)
??中提到:
對(duì)于任何 non-trivial 的改動(dòng),都需要有一定的描述來(lái)表明動(dòng)機(jī);對(duì)于大的改動(dòng),更需要設(shè)計(jì)文檔來(lái)留存記憶。人的記憶不是永久的,總會(huì)忘記最初的時(shí)候自己為什么做某一件事情,設(shè)計(jì)文檔的沉淀對(duì)于社區(qū)擺脫人的不確定性演化有至關(guān)重要的作用。
我在?如何在開(kāi)源項(xiàng)目中做重構(gòu)?[3] 也詳細(xì)闡述了我對(duì) RFC 的理解:
一個(gè)好的開(kāi)源項(xiàng)目不僅僅是由代碼組成,拋開(kāi)開(kāi)源共同體談抽象的技術(shù)和代碼是沒(méi)有意義的。因此向開(kāi)源項(xiàng)目提交大型的變更之前,我們必須要闡述清楚自己的想法,解釋動(dòng)機(jī),讓開(kāi)源共同體知道自己想做什么,想怎么做。
這些落到紙面上的文檔在討論時(shí)能夠補(bǔ)充信息,完善想法,構(gòu)建出更好的設(shè)計(jì)。從長(zhǎng)期角度看,文檔能夠幫助后來(lái)者理解當(dāng)時(shí)為什么要提出這樣的設(shè)計(jì),從而避免重復(fù)踩坑。不僅如此,一份好的設(shè)計(jì)文檔往往還能夠影響、啟發(fā)其他開(kāi)源項(xiàng)目的設(shè)計(jì),從而促進(jìn)整個(gè)行業(yè)進(jìn)步。
不難發(fā)現(xiàn),運(yùn)作良好的開(kāi)源項(xiàng)目往往有著完善的 RFC 流程,他們之間的關(guān)系是相輔相成的:
Rust RFCs[4]
CockroachDB RFCs[5]
Ethereum EIPs[6]
那么問(wèn)題來(lái)了:
如何撰寫一份 RFC
在我看來(lái)撰寫 RFC 是一件非常自然的事情,不知道如何寫的根本原因往往是準(zhǔn)備還不夠。提出一個(gè)新的想法總是簡(jiǎn)單,但是將想法落地成為可行的方案需要付出艱苦的努力,RFC 就是這種努力的具象化。
我在撰寫 RFC 的時(shí)候通常會(huì)經(jīng)歷如下步驟:
收集背景資料
分析可行方案
撰寫 RFC
社區(qū)討論
收集背景資料
最辛苦也是最容易被遺漏的一步就是收集背景資料。
在有了一個(gè)好想法之后,我們需要查閱歷史的 RFC 和相關(guān) Issues/PR 來(lái)了解這個(gè)這個(gè)想法是否可行。在這一步,我們需要搜集足夠的資料以回答下列問(wèn)題:
在此之前,相關(guān)的模塊是如何工作?現(xiàn)在遇到了怎樣的問(wèn)題?是否確有必要做改動(dòng)?
在相關(guān)領(lǐng)域有沒(méi)有類似的工作,現(xiàn)況如何?在其他項(xiàng)目中有沒(méi)有類似的參考經(jīng)驗(yàn)?
過(guò)去有沒(méi)有考慮過(guò)這個(gè)想法?當(dāng)初為什么否決了它?現(xiàn)在情況發(fā)生了怎樣的變化?
收集背景資料能夠讓我們掌握更多上下文,對(duì)相關(guān)模塊了解更深入,避免提出想當(dāng)然的改進(jìn)。其次,收集背景資料能夠避免我們進(jìn)行重復(fù)的工作。畢竟太陽(yáng)底下沒(méi)有新鮮事,新想法可能早就已經(jīng)被前人嘗試并論證過(guò)不可行。
在提出 RFC: Config Backward Compatibility之前,我做了如下工作:
與提出相關(guān)問(wèn)題的用戶進(jìn)行了一對(duì)一的溝通,了解了他的訴求和需要
閱讀 Databend 與 Config 處理相關(guān)的核心邏輯,了解現(xiàn)在如何處理
了解其他類似項(xiàng)目如何實(shí)現(xiàn) Config 兼容邏輯
分析可行方案
在充分掌握背景資料后,下一步需要分析可行的方案。
技術(shù)問(wèn)題往往存在著多種可能性,不要嘗試找到唯一的正確答案,而要在多種方案中做分析和調(diào)研并挑選出相對(duì)更好的方案。有時(shí)會(huì)需要開(kāi)發(fā)出簡(jiǎn)單的 Demo 以驗(yàn)證自己的想法。
我在這一步中經(jīng)常會(huì)犯下列的錯(cuò)誤:
? 偷懶:明知道存在其他的可能性卻不主動(dòng)調(diào)研。這往往會(huì)導(dǎo)致進(jìn)入討論階段時(shí)被社區(qū)指出并且非常被動(dòng)地做追加解釋,往返消耗的時(shí)間遠(yuǎn)大于自己事先想考慮清楚。
? 路徑依賴:設(shè)計(jì)方案時(shí)只考慮應(yīng)付當(dāng)下的問(wèn)題,沒(méi)有跳出來(lái)看到更好的可能。
? 自我辯護(hù):誕生想法的同時(shí)往往也會(huì)附贈(zèng)一個(gè)大概的思路,在調(diào)研的時(shí)候就很容易帶有明顯的偏向性,即使方案出現(xiàn)了比較嚴(yán)重的問(wèn)題也不愿意放棄,而是不斷增加扭曲的設(shè)定。
? 提前實(shí)現(xiàn):在調(diào)研方案的時(shí)候就已經(jīng)寫出了完整的實(shí)現(xiàn),最后方案的分析變成了具體實(shí)現(xiàn)的討論和復(fù)制。
這些問(wèn)題往往會(huì)導(dǎo)致后續(xù)撰寫 RFC 時(shí)出現(xiàn)明顯的偏向性,得出的結(jié)論有失偏頗。輕則 RFC 做大幅度調(diào)整,重則與維護(hù)者出現(xiàn)嚴(yán)重的分歧,甚至言語(yǔ)沖突。盡量避免類似的問(wèn)題,努力做到公正客觀的評(píng)價(jià)不同實(shí)現(xiàn)方案。當(dāng)然,每個(gè)人都有自己的技術(shù)偏好,所以也不用過(guò)于苛求公平,只要能夠把優(yōu)勢(shì)與弊端分析清楚即可。
撰寫 RFC
在完成準(zhǔn)備工作之后才真正進(jìn)入到撰寫 RFC 的階段。不同的項(xiàng)目往往有著不同的格式與要求,需要因地制宜地做改變。大部分 RFC 都會(huì)包括如下內(nèi)容:
背景/動(dòng)機(jī)
詳細(xì)說(shuō)明
基本原理
未解決的問(wèn)題
未來(lái)可能性
背景/動(dòng)機(jī)?這個(gè)章節(jié)需要說(shuō)明本次變更的背景和動(dòng)機(jī),解釋為什么要做這個(gè)變更,根據(jù)不同的情況,需要具體說(shuō)明也會(huì)略有不同。
比如新功能需要說(shuō)明為什么現(xiàn)有功能無(wú)法滿足需求,它將會(huì)支持怎樣的使用場(chǎng)景,預(yù)期的產(chǎn)出是什么;功能重構(gòu)修改則需要說(shuō)明現(xiàn)存的實(shí)現(xiàn)存在著哪些問(wèn)題,之前做過(guò)什么嘗試等。
詳細(xì)說(shuō)明?這個(gè)章節(jié)則需要具體闡述項(xiàng)目需要怎么做變更。同樣需要根據(jù)項(xiàng)目實(shí)際情況做調(diào)整,以 Rust 為例,它將該章節(jié)分為兩部分:
Guide-level explanation 解釋從用戶的角度看,這個(gè)變更帶來(lái)了怎樣的變化,引入了什么新概念,增加了什么新語(yǔ)法 Reference-level explanation 則從技術(shù)的角度說(shuō)明如何實(shí)現(xiàn),與其他的特性如何交互,需要考慮哪些邊緣 case 注意在這個(gè)章節(jié)中不要大面積地粘貼具體的實(shí)現(xiàn),而是簡(jiǎn)明概要地說(shuō)明思路并輔以必要的代碼,這將有助與 Reviewer 理解宏觀思路而不是陷入到實(shí)現(xiàn)細(xì)節(jié)中。
基本原理?基本原理章節(jié)中需要講解為什么要這樣來(lái)實(shí)現(xiàn)。
有沒(méi)有其他的實(shí)現(xiàn)方案?他們各有什么優(yōu)缺點(diǎn),什么原因驅(qū)使我們采用了 A 方案而不是 B 方案?現(xiàn)存技術(shù)如何?其他項(xiàng)目是怎么實(shí)現(xiàn)的,他們各自考慮的出發(fā)點(diǎn)如何?
未解決的問(wèn)題?這個(gè)章節(jié)需要說(shuō)明本變更的局限性,比如在 review 中提出了某些目前還無(wú)法解決的問(wèn)題,可以將他們記錄在該章節(jié)中。
未來(lái)可能性?未來(lái)可能性章節(jié)用于記錄本變更未來(lái)的可能性,已經(jīng)考慮到但是沒(méi)有在本次變更中實(shí)現(xiàn)的想法。
比如引入了一個(gè)新特性,這個(gè)特性在未來(lái)能夠與其他的特性做怎么樣的結(jié)合。或者在 review 時(shí)有人提出超出當(dāng)前 RFC 的范圍的想法,可以先記錄在這里供后人參考。
社區(qū)討論
在完成 RFC 后即可提交到社區(qū)進(jìn)行討論。
在經(jīng)歷這么多工作之后,我們自然不希望自己的 RFC 被否定,所以我們需要積極地參與社區(qū)討論,回應(yīng)社區(qū)成員的關(guān)切,根據(jù)大家的反饋來(lái)調(diào)整自己的實(shí)現(xiàn)方案:補(bǔ)充沒(méi)考慮到的地方,調(diào)整實(shí)現(xiàn)的思路,必要的時(shí)候?qū)?RFC 做拆分,實(shí)現(xiàn)其中的一部分等等。身處同一個(gè)開(kāi)源共同體,社區(qū)成員的利益是趨向一致的,大家的終極目標(biāo)都是為了把項(xiàng)目做好。將他人的反對(duì)意見(jiàn)視作對(duì)自己想法的攻擊,消極地與社區(qū)成員做對(duì)抗往往不利于 RFC 的進(jìn)一步推進(jìn)。
我為 Databend 提交的 RFC:?Config Backward Compatibility??曾經(jīng)是一個(gè)更大的 Scope:Versioned Config。在原始的 RFC 中,我計(jì)劃為 databend config 引入 version 的概念,從而能夠自信的做出破壞性變更。但是社區(qū)成員對(duì)該設(shè)計(jì)提出了復(fù)雜性的質(zhì)疑,他們普遍認(rèn)為這個(gè)設(shè)計(jì)太復(fù)雜了,會(huì)引入非常多冗余的代碼。不僅如此,Databend 目前還沒(méi)有發(fā)布穩(wěn)定版本,客觀來(lái)看沒(méi)有引入版本化配置的必要。結(jié)合社區(qū)的反饋意見(jiàn),我做出了自己的回應(yīng)
?:
Our community members have great concern about the complexity of introducing a versioned config at this stage(no stable release, no production users). It seems better to only split outer and inner configs and leave the decision of versioned config till the future.
調(diào)整本次 RFC,將版本化配置的想法移動(dòng)到了 Future possibilities,本次變更只是引入一次重構(gòu),將暴露給用戶的配置和內(nèi)部使用的配置做拆分。在做出本次調(diào)整后,社區(qū)給出了 LGTM 并合并了這個(gè) RFC,進(jìn)入到具體的實(shí)現(xiàn)階段。
總結(jié)
撰寫 RFC 是跟社區(qū)溝通交流想法的有效渠道。通過(guò)完成收集背景資料、分析可行方案、撰寫 RFC和社區(qū)討論等步驟,結(jié)合項(xiàng)目的實(shí)際,我們誰(shuí)都可以寫出一份可靠的提案。
給自己最愛(ài)的開(kāi)源項(xiàng)目提交一份 Proposal 吧!
引用鏈接
?@tison:?https://github.com/tisonkun/
?如何參與 Apache 項(xiàng)目社區(qū):?https://zhuanlan.zhihu.com/p/93334196
?如何在開(kāi)源項(xiàng)目中做重構(gòu)?:?https://xuanwo.io/2022/01-refactor-in-open-source-project/
?Rust RFCs:?https://github.com/rust-lang/rfcs
?CockroachDB RFCs:?https://forum.cockroachlabs.com/c/open-source-contributors/rfc/6
?Ethereum EIPs:?https://github.com/ethereum/EIPs
?RFC: Config Backward Compatibility:?https://github.com/datafuselabs/databend/pull/5324
?回應(yīng):?https://github.com/datafuselabs/databend/pull/5324#issuecomment-1125794431
關(guān)于 Databend
Databend 是一款開(kāi)源、彈性、低成本,基于對(duì)象存儲(chǔ)也可以做實(shí)時(shí)分析的新式數(shù)倉(cāng)。期待您的關(guān)注,一起探索云原生數(shù)倉(cāng)解決方案,打造新一代開(kāi)源 Data Cloud。
Databend 文檔:https://databend.rs/
Twitter:https://Twitter.com/Datafuse_Labs
Slack:https://datafusecloud.slack.com/
Wechat:Databend
GitHub :https://github.com/datafuselabs/databend