拜托,大廠做項(xiàng)目可不簡單!
揭秘一線大廠研發(fā)流程
大家好,我是魚皮。
很多未工作過的小伙伴都很好奇:企業(yè)中做項(xiàng)目是怎樣的流程?尤其是大廠那些百萬用戶的項(xiàng)目,和自己學(xué)編程時(shí)做項(xiàng)目到底有什么區(qū)別呢?
實(shí)話說,區(qū)別可大了!
自己開發(fā)項(xiàng)目那是單打獨(dú)斗,自己掌握命運(yùn),不會拖垮隊(duì)友;但企業(yè)中開發(fā)項(xiàng)目是開團(tuán)打本,大家是一根繩上的螞蚱,每個(gè)人都會影響整個(gè)項(xiàng)目。

我自己也在幾家公司實(shí)習(xí)過,不得不說,大廠和其他公司的研發(fā)流程也有很大的區(qū)別。
因此,對于大多數(shù)同學(xué),如果沒有在大廠工作過,對很多研發(fā)環(huán)節(jié)可能都是一無所知的。
所以今天給大家揭秘一下大廠的項(xiàng)目研發(fā)流程,幫大家開拓思路。
正好之前有同志質(zhì)疑我的日常工作就只有寫代碼和摸魚?!這篇文章就作為回?fù)簦屗靼祝诖髲S做項(xiàng)目,可不止寫代碼那么簡單!

大廠研發(fā)流程揭秘
為了規(guī)范團(tuán)隊(duì)、保證項(xiàng)目的進(jìn)展,大廠研發(fā)流程通常還是比較復(fù)雜的。
可以分為很多個(gè)階段,用一張思維導(dǎo)圖來概括:

需要注意的是,以上階段并不是完全按從上到下的順序執(zhí)行,階段間可能存在交叉,比如 技術(shù)選型 其實(shí)在 設(shè)計(jì)階段 就應(yīng)該考慮。
正式工作一年多,我也是經(jīng)歷過多次項(xiàng)目的完整研發(fā)流程的。下面就以我的視角,帶大家快速過一遍~
(為了內(nèi)容更有趣,以下故事有虛構(gòu)成分)
需求階段
今天是周一,魚皮像往常一樣騎著他的小電動車來到公司,殊不知,等待他的是一場噩夢的開始。
需求產(chǎn)生
上午十點(diǎn),產(chǎn)品妹子找到魚皮,告訴他:咱們的系統(tǒng)上線后,用戶表示很多功能并不好用,需要大改。
老板也找到魚皮,告訴他:我今天打開頁面竟然加載了十幾秒,咱們這個(gè)系統(tǒng)的性能太爛了吧!
魚皮心想:嘔豁,完蛋!估計(jì)得做個(gè)新的項(xiàng)目了,又要開會了。

果然,沒過多久,屏幕上彈出了一條 “歡迎加入會議” 的邀請。
需求評審
第二天上午,老板、產(chǎn)品、測試、幾位開發(fā)大哥和魚皮一起來到會議室,具體討論昨天提到的那些需求 是否合理、要不要做 ?
產(chǎn)品妹子打開文檔,說到:這一期呢,我們要做這幾個(gè)需求,下面我來詳細(xì)講一下,大家一起評估下有沒有問題。
需求分析
接下來,產(chǎn)品妹子正在對著屏幕侃侃而談、瘋狂輸出時(shí),旁邊的開發(fā)大哥坐不住了。
開發(fā)大哥:這個(gè)需求不合理啊!
產(chǎn)品:為啥不合理?用戶就是有這個(gè)需求啊!
開發(fā)大哥:我知道,實(shí)現(xiàn)不了啊!
于是開始了經(jīng)典的產(chǎn)品開發(fā)撕逼大戰(zhàn)。。。

而魚皮正躲在角落冷靜分析 這個(gè)需求怎么做 ,過了一會兒,提出了一種改動低、實(shí)現(xiàn)快的解決方案,平息了這場戰(zhàn)爭。
排期
確定需求合理、可實(shí)現(xiàn)之后,產(chǎn)品妹子問到:那這個(gè)需求啥時(shí)候能上線呀?
開發(fā)大哥:我這周忙,下周吧。
產(chǎn)品:用戶可能比較著急,這周就要呢!
開發(fā)大哥:我知道,做不完啊!
于是開始了經(jīng)典的產(chǎn)品開發(fā)撕逼大戰(zhàn)。。。

魚皮:要不我們把這個(gè)需求拆解為功能 A 和功能 B,這周我先把功能 A 做了,功能 B 排到下周二測試,下周四上線?
就這樣,我們一個(gè)個(gè)安排了需求的計(jì)劃完成日期。
設(shè)計(jì)階段
終于開完會了,看了下時(shí)間,都該下班了!
唉,需求討論完了,產(chǎn)品的工作是完成了一些,可魚皮的工作才剛剛開始。
急著開始寫代碼么?
不,想好怎么寫代碼比寫代碼更重要。
架構(gòu)設(shè)計(jì)
魚皮打開寫文檔軟件和畫圖軟件,開始梳理整個(gè)系統(tǒng),從整體到局部,依次設(shè)計(jì)出系統(tǒng)的層次結(jié)構(gòu)、各層間交互的接口和通訊方式、每層之間包含哪些重要模塊、模塊選擇何種物理部署方式等。

概要設(shè)計(jì)
寫完架構(gòu)設(shè)計(jì)后,魚皮開始對著產(chǎn)品妹子寫的 PRD(產(chǎn)品需求文檔),分析需求,然后依然是從整體到局部,先整理出系統(tǒng)需要的功能模塊,再分析每個(gè)功能模塊內(nèi)有哪些子模塊。
和抽象的架構(gòu)設(shè)計(jì)相比,概要設(shè)計(jì)和需求的關(guān)系更緊密,是對架構(gòu)設(shè)計(jì)的細(xì)化。
打個(gè)比方大家就明白了,你要蓋一棟樓,架構(gòu)設(shè)計(jì)就是從整體來考慮,總共有幾層、每層管道怎么接、每層有幾戶、地基怎么打等;而概要設(shè)計(jì)就是考慮每戶套件的內(nèi)部怎么劃分,哪里是客廳、哪里是衛(wèi)生間。
很多情況下,概要設(shè)計(jì)和架構(gòu)設(shè)計(jì)可能會在一個(gè)文檔中進(jìn)行,劃分并不明確。
詳細(xì)設(shè)計(jì)
想好系統(tǒng)有哪些功能后,魚皮就開始具體分析每個(gè)功能如何實(shí)現(xiàn),用到哪些算法、需要注重哪些細(xì)節(jié)等。
方案對齊
寫好設(shè)計(jì)文檔后,下次會議上,魚皮和其他的開發(fā)同學(xué)(前端、后端等)一起針對自己設(shè)計(jì)的方案展開討論,最終產(chǎn)生一個(gè)統(tǒng)一的方案,然后大家分工去做就好了。
測試用例設(shè)計(jì)
為了保證系統(tǒng)功能的正常穩(wěn)定,測試同學(xué)(或者叫 QA)是非常重要的,測試不是像我們自己做項(xiàng)目一樣對著網(wǎng)頁點(diǎn)幾下就 ok 了。
在大公司中,為了保證測試的覆蓋度、提高測試效率,一般是要設(shè)計(jì)測試用例的,比如:用戶點(diǎn)擊 “登錄”,未傳任何數(shù)據(jù),期望結(jié)果是警告用戶輸入用戶名和密碼。

測試用例設(shè)計(jì)完后,需要其他同學(xué)一起來評審把關(guān),而不是只交給測試同學(xué)。因?yàn)橐粋€(gè)人很容易忽略掉很多測試細(xì)節(jié),最好讓更熟悉代碼的開發(fā)同學(xué)一起幫忙補(bǔ)充。
魚皮自己也寫了幾個(gè)測試可能會遺漏的用例,和測試同學(xué)一起進(jìn)行了確認(rèn),盡量讓問題暴露在測試階段而不是線上。
研發(fā)準(zhǔn)備
寫了快一周的設(shè)計(jì)文檔,終于準(zhǔn)備開始動手搭建項(xiàng)目了。但在此之前,還有一些準(zhǔn)備工作要進(jìn)行。
技術(shù)預(yù)研
如今技術(shù)發(fā)展太快,新技術(shù)層出不窮,所以魚皮首先對項(xiàng)目中需要或可能需要用到的技術(shù)進(jìn)行了調(diào)研。
技術(shù)選型
通過調(diào)研,魚皮得到了幾個(gè)可以滿足需求的技術(shù),但他開始糾結(jié):這么多技術(shù),我該用哪一個(gè)呢?是用 SSM 框架還是 Play 框架呢?用 guava 包還是 Apache Commons 呢?
魚皮又打開了寫文檔軟件,開始對比不同技術(shù)的優(yōu)劣,頭疼啊,技術(shù)選型要考量的因素太多了,比如:
單從技術(shù)考慮:性能、易用性、穩(wěn)定性、主流程度和生態(tài)、文檔詳細(xì)度
結(jié)合團(tuán)隊(duì):團(tuán)隊(duì)成員對技術(shù)的熟悉度、掌控度(有無精通該技術(shù)的人)
結(jié)合業(yè)務(wù):是否適應(yīng)業(yè)務(wù)的量級(單機(jī) or 微服務(wù))、是否適應(yīng)業(yè)務(wù)(讀多、寫多 or 分析多)
對于關(guān)鍵的項(xiàng)目,魚皮自己還不敢完全確定選型,因此在寫好自己的選型文檔后,與同事和 Leader 一起討論,才最終確認(rèn)。
資源申請
確認(rèn)好技術(shù)后,就要申請資源。比如魚皮用到了 MySQL 數(shù)據(jù)庫,但是這個(gè) MySQL 從哪兒來呢?
以前的話,魚皮都是去買一臺云服務(wù)器,自己搭建 MySQL。但是在企業(yè)中,一般是有集中管理和分配資源的平臺的,直接到平臺填寫預(yù)算、等領(lǐng)導(dǎo)審批、然后等著下發(fā)資源就好了。千萬不能私自用自己的或買外部的服務(wù)器來部署項(xiàng)目,不安全!
魚皮這次直接申請到了 2 萬多一年的云數(shù)據(jù)庫,真的是爽死了。

環(huán)境準(zhǔn)備
申請好數(shù)據(jù)庫等資源后,魚皮按照申請機(jī)器的版本搭建了一模一樣的本地開發(fā)環(huán)境和測試環(huán)境,后面就可以直接連接了。
項(xiàng)目初始化
環(huán)境準(zhǔn)備妥當(dāng)后,由于是新項(xiàng)目,魚皮要搞一個(gè)最小可運(yùn)行的初始化項(xiàng)目 Demo,使用 腳手架 自動生成代碼,而不是從零開始一個(gè)個(gè)新建文件、手敲重復(fù)代碼。
依賴安裝
生成了項(xiàng)目代碼后,魚皮使用包管理工具(前端 yarn、Java Maven / Gradle 等)自動安裝依賴,然后項(xiàng)目 Demo 就可以運(yùn)行啦!
研發(fā)階段
前期準(zhǔn)備完成后,這才到了程序員朋友們最熟悉的寫代碼環(huán)節(jié),也是魚皮最愛的環(huán)節(jié)。

因?yàn)橹霸O(shè)計(jì)方案時(shí)需要保持冷靜、仔細(xì)思考,沒法邊聽歌兒邊做;而方案設(shè)計(jì)好后,已經(jīng)明確了該怎么做,寫代碼實(shí)現(xiàn)就很簡單了,頂多是遇到一些坑,上網(wǎng)搜索去解決就好了。
本地開發(fā)
開發(fā)時(shí),一般魚皮會先在本地寫代碼,通過配置熱更新工具,實(shí)現(xiàn)代碼更新時(shí)自動重新編譯打包,而不用手動重啟項(xiàng)目,大大提高了開發(fā)效率。
對了,企業(yè)開發(fā)都會使用版本控制系統(tǒng)的,比如 Git,開發(fā)前記得先創(chuàng)建一個(gè)自己的分支,在這個(gè)分支上開發(fā)。
遠(yuǎn)程開發(fā)
現(xiàn)在還有一種比較流行的遠(yuǎn)程開發(fā)方式,就是可以像編輯本地文件一樣編輯遠(yuǎn)程文件,直接修改服務(wù)器上的代碼。一般我們每位研發(fā)同學(xué)是有自己的開發(fā)機(jī)的,通過遠(yuǎn)程開發(fā)就省去了反復(fù)部署調(diào)試的麻煩,提高效率。一般用 VSCode 等開發(fā)工具,安裝遠(yuǎn)程開發(fā)插件就可以實(shí)現(xiàn)了。
代碼優(yōu)化
魚皮在寫代碼的時(shí)候,始終保持主動優(yōu)化代碼的好習(xí)慣,注重代碼的時(shí)空復(fù)雜度;并且當(dāng)重復(fù)代碼多了,會想辦法抽象成函數(shù)或者使用設(shè)計(jì)模式。之前專門寫文章分享過我的編程習(xí)慣:我寫代碼時(shí)的小倔強(qiáng) 。
單元測試
注意!不要聽到測試就以為是測試同學(xué)的工作,開發(fā)同學(xué)也同樣需要編寫小粒度的測試來為自己的代碼負(fù)責(zé)。
魚皮一般會為每個(gè)數(shù)據(jù)庫讀寫函數(shù)和業(yè)務(wù)邏輯函數(shù)編寫單元測試,像 Java 的話一般用 JUnit 等工具,還可以用 Jacoco 生成測試覆蓋度報(bào)告。每次修改關(guān)鍵代碼后,都要執(zhí)行一遍單元測試,防止意外錯(cuò)誤。

開發(fā)聯(lián)調(diào)
魚皮終于寫好了后端代碼,也自測完成了,下面就是把寫好的代碼打包構(gòu)建,然后把可執(zhí)行項(xiàng)目包發(fā)布到測試服務(wù)器上,和前端同學(xué)一起聯(lián)調(diào),讓他請求我的接口,驗(yàn)證系統(tǒng)的功能是否可用。
測試驗(yàn)證
魚皮和前端聯(lián)調(diào)完畢后,告知了測試和產(chǎn)品同學(xué)。
測試驗(yàn)證是企業(yè)中至關(guān)重要的環(huán)節(jié),甚至可以說是最后一道防線。測試的目的是找 Bug,盡量發(fā)現(xiàn)系統(tǒng)中的問題,把它們扼殺在測試階段。
在企業(yè)中,測試驗(yàn)證又有很多類型。
集成測試
集成測試比單元測試粒度更大,是把多個(gè)模塊或代碼單元放在一起,驗(yàn)證模塊之間的集成和調(diào)用關(guān)系。
因?yàn)閱蝹€(gè)函數(shù)的執(zhí)行可能是正常的,但把多個(gè)函數(shù)組合在一起順序調(diào)用,可能就會出現(xiàn)問題。
打個(gè)比方,我們有個(gè)吃面包系統(tǒng):
功能 A:小魚吃一個(gè)面包
功能 B:小皮吃一個(gè)面包
每次只有一個(gè)面包,獨(dú)立執(zhí)行功能 A 和 B 都是允許的。但如果兩個(gè)一起執(zhí)行,后執(zhí)行的那個(gè)功能就會報(bào)錯(cuò)。

系統(tǒng)測試
系統(tǒng)測試比集成測試的粒度更大,測試對象是整個(gè)系統(tǒng),不僅包括軟件,還可能覆蓋對硬件的測試。
產(chǎn)品體驗(yàn)
除了測試同學(xué)要驗(yàn)證系統(tǒng)可用性,產(chǎn)品妹子也要體驗(yàn)下功能是否符合預(yù)期、是否易用。大多數(shù)情況下,產(chǎn)品會在體驗(yàn)時(shí)提出修改建議,開發(fā)可能還要再去做一些修改。
驗(yàn)收測試
測試和產(chǎn)品妹子終于表示沒有問題啦,那就到了最后一步,把整個(gè)產(chǎn)品或功能給最終的用戶來體驗(yàn)。老板 用戶說沒問題,才是真的沒問題!
提交階段
系統(tǒng)沒問題之后,魚皮就可以把代碼發(fā)布到遠(yuǎn)程倉庫了,一般使用 Git 和 SVN 等版本控制系統(tǒng)。
代碼提交
魚皮首先在本地觸發(fā)代碼提交(git commit),為保證規(guī)范,在大項(xiàng)目中一般會使用提交檢測插件,防止你把錯(cuò)誤的代碼進(jìn)行了提交。
代碼推送
下一步就是把本地的提交推送到遠(yuǎn)程的同名分支。一般大廠會有推送檢測工具,檢測代碼的錯(cuò)誤、圈復(fù)雜度、代碼規(guī)范等,和提交檢測一樣,防止你把錯(cuò)誤或不規(guī)范的代碼進(jìn)行了推送。
合并請求
代碼分支推送到遠(yuǎn)程之后,魚皮發(fā)起了一個(gè)分支合并請求(MR),希望把該分支的代碼合并到主干分支(沒問題的代碼)。

代碼審查
并不是發(fā)起了合并請求就能直接合并,還要通過代碼審查,即 CR。
審查又分為兩種方式:人審和機(jī)審。
相信不少同學(xué)都知道人審,一般是由你的上級和其他項(xiàng)目負(fù)責(zé)人來閱讀和評論你的代碼,覺得沒問題就 Approve(通過),否則打回去修改。
那機(jī)審是個(gè)啥呢?其實(shí)就是機(jī)器自動檢測你的代碼是否符合規(guī)范,是否能夠成功自動化構(gòu)建等,一般是由項(xiàng)目負(fù)責(zé)人配置的,可以幫助發(fā)現(xiàn)一些人工難以發(fā)現(xiàn)的問題。
剛接觸新項(xiàng)目的時(shí)候,魚皮經(jīng)常被機(jī)審折磨得苦不堪言,經(jīng)常被提示一些莫名其妙的代碼問題,比如加號要換行,文件行末要加空行等。但后來注意編碼習(xí)慣后,就很自然地適應(yīng)了,的確不錯(cuò)。
發(fā)布階段
代碼審查通過后,魚皮的項(xiàng)目代碼就可以發(fā)布上線啦。

打包構(gòu)建
傳統(tǒng)上線方式是開發(fā)人員到正式服務(wù)器上拉取代碼,然后安裝依賴,再通過工具把代碼打包構(gòu)建,得到部署包,通過 Nginx、Tomcat、Docker 等技術(shù)運(yùn)行。
但這樣效率很低,有很多重復(fù)工作。所以大廠一般是用自動化構(gòu)建的,像 Jenkins、各種 CI / CD 工具等。代碼合并到主分之后,由機(jī)器把代碼打包構(gòu)建為最終的部署包。
預(yù)發(fā)布
為了防止上線出問題,一般我們會先在預(yù)發(fā)布環(huán)境部署項(xiàng)目,再觀察一下是否能夠正常運(yùn)行。
正式發(fā)布
預(yù)發(fā)布測試正常后,魚皮終于等到了上線的這一刻。大項(xiàng)目一般都會部署在多臺機(jī)器上,所以不可能一臺臺登錄機(jī)器去發(fā)布部署包。
通常公司會提供可視化發(fā)布平臺,點(diǎn)選需要發(fā)布機(jī)器(一般先灰度,選一小部分機(jī)器,再全量發(fā)布),點(diǎn)擊一鍵發(fā)布,等項(xiàng)目管理員審批通過之后,就交給機(jī)器自動部署吧!
后續(xù)
魚皮曾天真地以為項(xiàng)目上線之后,就可以高枕無憂了。但后來發(fā)現(xiàn),項(xiàng)目上線之后,同樣需要保持警覺。雖然已經(jīng)測試過,但仍然時(shí)不時(shí)會出現(xiàn)個(gè)預(yù)期之外的小 Bug,還是很考驗(yàn)心態(tài)的。

來看看上線之后,魚皮做了哪些事呢?
監(jiān)控運(yùn)維
魚皮會定期查看項(xiàng)目的監(jiān)控面板,觀察項(xiàng)目的運(yùn)行情況,機(jī)器的負(fù)載等。
統(tǒng)計(jì)分析
魚皮在代碼中添加了一些日志,可以利用 ELK 等日志收集可視化平臺對這些日志進(jìn)行分析,從而感知到用戶的行為,進(jìn)一步優(yōu)化業(yè)務(wù)和系統(tǒng)。
比如我會統(tǒng)計(jì)用戶執(zhí)行 SQL 查詢的耗時(shí),對重復(fù)率高的慢 SQL 進(jìn)行針對性地優(yōu)化。
事件反饋
有的時(shí)候,用戶自己都不能清楚地描述 Bug,而且歷史 Bug 也不方便找到。所以公司內(nèi)部一般會有事件反饋平臺,產(chǎn)品等內(nèi)部同學(xué)在接收到 Bug 時(shí),會在該平臺發(fā)布一個(gè) Bug 事件,詳細(xì)描述 Bug 出現(xiàn)的時(shí)間、狀況、詳情等,便于我們開發(fā)集中分析和處理問題。

文檔沉淀
每次上線了新功能和項(xiàng)目,魚皮都會通過寫文檔來記錄項(xiàng)目的背景、設(shè)計(jì)方案、開發(fā)過程和一些坑點(diǎn),便于后續(xù)其他同學(xué)了解項(xiàng)目,這是非常重要的!利人利己。
曾經(jīng)分享過我的寫文檔技巧:如何寫好文檔?
迭代優(yōu)化
最后,一個(gè)需求的結(jié)束往往只是另一個(gè)需求的開始。像魚皮最近在跟進(jìn)的項(xiàng)目,一期做完做二期,二期還沒做完三期就來了;還要抽出時(shí)間去優(yōu)化以前的代碼,這日子遙遙無期,沒盼頭啊!
以上就是本期分享,看完本文后,歡迎閱讀我之前的這篇文章:大廠機(jī)密!30 個(gè)提升團(tuán)隊(duì)研發(fā)效能的錦囊 ,了解更多大廠技術(shù)。
我是魚皮,點(diǎn)贊 + 在看 還是要求一下的,祝大家都能心想事成、發(fā)大財(cái)、行大運(yùn)。

往期推薦
