慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

阮一峰的网络日志

科技爱好者周刊(第 396 期):互联网通信的替代方案 科技爱好者周刊(第 396 期):互联网通信的替代方案 - 阮一峰的网络日志 科技爱好者周刊(第 395 期):软件开发的第三种方式 科技爱好者周刊(第 395 期):软件开发的第三种方式 - 阮一峰的网络日志 科技爱好者周刊(第 393 期):脑腐状态 科技爱好者周刊(第 392 期):axios 投毒与好莱坞式骗术 科技爱好者周刊(第 391 期):AI 的贫富分化 科技爱好者周刊(第 390 期):没有语料,大模型就是智障 套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的"套壳"疑云 科技爱好者周刊(第 389 期):未来如何招聘程序员 科技爱好者周刊(第 388 期):测试是新的护城河 零安装的"云养虾":ArkClaw 使用指南 科技爱好者周刊(第 387 期):你是领先的 科技爱好者周刊(第 386 期):当外卖员接入 AI 字节全家桶 Seed 2.0 + TRAE 玩转 Skill 科技爱好者周刊(第 385 期):马斯克害怕中国车企吗? 智谱旗舰 GLM-5 实测:对比 Opus 4.6 和 GPT-5.3-Codex 科技爱好者周刊(第 384 期):为什么软件股下跌 科技爱好者周刊(第 383 期):你是第几级 AI 编程 Kimi 的一体化,Manus 的分层 科技爱好者周刊(第 382 期):独立软件的黄昏 AI native Workspace 也许是智能体的下一阶段 科技爱好者周刊(第 381 期):中国 AI 大模型领导者在想什么 科技爱好者周刊(第 380 期):为什么人们拥抱"不对称收益" 科技爱好者周刊(第 379 期):《硅谷钢铁侠》摘录 我如何用 AI 处理历史遗留代码:MiniMax M2.1 升级体验 科技爱好者周刊(第 378 期):预测是新的互联网热点 科技爱好者周刊(第 377 期):14万美元的贫困线 科技爱好者周刊(第 376 期):太空数据中心的争议 科技爱好者周刊(第 375 期):一扇门的 Bug 终于有人做了 Subagent,TRAE 国内版 SOLO 模式来了 科技爱好者周刊(第 374 期):6GHz 的问题 VS Code 使用国产大模型 MiniMax M2 教程 科技爱好者周刊(第 373 期):数据模型是新产品的核心 国产大模型接入 Claude Code 教程:以 Doubao-Seed-Code 为例 科技爱好者周刊(第 372 期):软件界面如何设计 大模型比拼:MiniMax M2 vs GLM 4.6 vs Claude Sonnet 4.5 科技爱好者周刊(第 371 期):一个乐观主义者的专访 科技爱好者周刊(第 370 期):正确的代码高亮 错误处理:异常好于状态码 科技爱好者周刊(第 369 期):Tim 与罗永浩的对谈 科技爱好者周刊(第 368 期):不要这样管理软件团队 一天之内,智谱和 Anthropic 都发了最强编程模型 科技爱好者周刊(第 367 期):Nano Banana 的几个妙用 科技爱好者周刊(第 366 期):旧金山疯狂的 AI 广告 科技爱好者周刊(第 365 期):流量变现正在崩塌 科技爱好者周刊(第 364 期):最难还原的魔方 科技爱好者周刊(第 363 期):最好懂的神经网络解释 科技爱好者周刊(第 362 期):GitHub 工程师谈系统设计 科技爱好者周刊(第 361 期):暗网 Tor 安全吗?
軟件工程的最大難題
阮一峰 · 2021-05-10 · via 阮一峰的网络日志

一、引言

大學有一門課程《軟件工程》,研究如何組織和管理軟件項目。

說實話,這門課不適合本科生,因為學生可能體會不到,課程到底要解決什麼問題。只有親身參與過大項目的開發,經歷過大團隊,才能感受為什麼軟件工程很重要,又很難做對。

軟件開發有一個難題,叫做"擴展"(scaling),即怎樣服務更多的用戶。 你有10000個併發用戶,跟你有10個併發用戶,這是完全不同的概念,哪怕功能完全相同,背後的實現是完全不一樣的。併發用戶數上升一個數量級,軟件就必須重構,大量問題隨之產生。

大項目的技術難度高,管理難度更高,而且大團隊的生產率往往很低,行動緩慢。 《軟件工程》就是研究,如何擴展軟件和團隊,適應大項目的需要。

國外有很多專著,研究這個問題。前些日子,我讀到一篇文章,推薦了兩本書。第一本叫做《加速:構建和擴展高性能技術組織》,第二本叫做《規模:生物,城市和公司的普遍法則》。

我看了這兩本書的介紹,覺得很有啟發,下面就做一些摘錄。

二、大項目的困境

一個典型的大型軟件項目,開發過程通常是下面這樣。

最開始的時候,它是一個小項目,開發人員就是兩三個人,甚至可能只有一個人。產品比較簡單,功能很有限。

第一版發佈後,拿給客戶使用,反響不錯。客戶要求的新功能,能夠很快開發出來,Bug 修補也很快,因為早期客戶往往可以與開發人員直接溝通,快速反饋。

公司於是決定投入更多人員,開發這個項目。團隊慢慢變大了,軟件開始變得複雜,開發速度逐漸變慢了,2.0 版花費的時間比預期要長一點。Bug 的修復難度開始增加。總之,新功能的開發日程變久了。

公司的自然反應是進一步擴充團隊。但是更多的新成員其實會降低其他人的生產率,一個普遍現象是團隊規模越大,每個人的平均生產率越低。

幾年以後,代碼逐漸老化,複雜性不斷增加,項目開始停滯不前。某些極端的情況下,軟件的維護成本變得非常高昂,並且幾乎不可能進行更改。

最終,這個項目成為技術債務,等待被新項目替換。

三、為什麼大項目的開發效率低?

大項目就像一頭大象,讓人望而生畏。可是一旦需要奔跑,大象就會步履蹣跚,被獵犬遠遠甩在後頭。它快不起來的原因有兩個。

(1)代碼複雜度

隨著代碼量的增長,單個開發者想要理解整個代碼庫,變得越來越困難。如果團隊超過五個人,每個人負責一個功能,那麼單個人幾乎不可能追蹤系統的所有工作進度。

當你中途加入團隊,整個項目是一個緊密耦合的大型系統,你又不理解系統的每一個工作細節。這時,你就不太敢修改以前的代碼,因為不知道隨之而來的全部影響。

你不真正理解系統,也就不會感到自己是代碼的主人。你會很猶豫要不要重構,過時的代碼開始累積,技術債務就這樣出現了。長此以往,開發變得越來越不愉快和令人無法滿意,最終導致人才流失。後面接手的新人,更難於重構那些遺留下來的代碼。

(2)團隊原因

隨著團隊成員的增加,交流成本開始指數式上升。如果整個團隊有 n 個程序員,為了瞭解其他人的工作,你需要跟 n - 1 個人逐一交流(口頭或者書面),那麼整個團隊的交流路徑總數就是 n * (n - 1) / 2。這意味著,交流成本的增長速度是人員增長速度的平方,團隊人數越多,協同的難度就越大。

大團隊保持扁平化管理,也會越來越困難,必須拆分成較小的群體。這時,對等的交流會被自上而下的交流所取代。團隊成員會感覺,自己從平等的利益相關者,轉變為普通的工作人員,工作動機受到了影響,責任感和主人翁意識都會淡漠。

管理層為了解決問題,會嘗試組建新團隊和新的管理架構。但是,不管怎麼做,大型組織都很難保持所有成員的積極參與。

四、解決方法:代碼解耦

大項目的開發效率不高,把這個問題歸咎於程序員的技術水平低和管理不善,都是沒用的。 根本原因是軟件規模的增長,必然使得代碼和團隊變得笨重。 除非很早就認識到問題的根據,採取緩解對策,否則前面描述的情況,遲早都會出現。

解決這個問題,要從代碼和團隊兩方面著手。

代碼層面的解決方法是,將軟件解耦,拆分成組件或者模塊,防止各個部分緊密地耦合在一起。每個組件和模塊,都可以獨立開發,通過公開的接口被其它部分調用。

這樣的話,就大大減輕了開發者的負擔,只需要負責自己的代碼即可,不需要關心其他部分的實現。每個部分都可以單獨重構,不擔心影響到其他部分。

五、解決方法:團隊解耦

除了代碼解耦,團隊層面也需要解耦,要把人員分開。

這可以參考互聯網的架構。互聯網是迄今為止最成功的大型軟件解耦實例,它之所以能夠擴展,是因為它由一個個獨立的節點組成。為了防止節點之間互相依賴,各個節點都遵循以下規則。

  • 遵守公開的通信協議。
  • 不需要了解其它節點的內部實現,就可以與之通信。
  • 節點之間不直接共享狀態,只通過通信交換數據。
  • 每個節點單獨開發和部署。

大團隊也應該遵循類似的原則,進行解耦。

  • 每個子團隊都可以獨立運作,不依賴外部人員。
  • 子團隊內部的運作,不需要被外部知道。
  • 子團隊之間的協調,應該按照公開的協議和規則,最好能夠自動完成,避免私下協商。

六、團隊解耦的注意點

團隊解耦有一些注意點。

(1)子團隊的人數不宜過多,每個子團隊最好不要超過5個人。

(2)子團隊應該是一個小型的全功能軟件開發組織。

很多大團隊按照人員角色分組,比如架構組、開發組、DBA 組、測試組、工程組等等,這是錯誤的。這樣完全沒有解耦,還是瀑布式流程,各組之間依然互相依賴,工作時必須與別組單獨協商。而且,可能會產生利益衝突,比如,開發組希望儘快交付,而測試組希望多一點時間測試。

正確做法是按照軟件的業務功能分組,每組負責一個全流程的軟件大功能,設計、編碼、測試、部署、支持等人員都在同一組。這樣才能做到解耦,以及獨立的交付和重構。每組內部使用什麼工具、如何實現某個功能,都是自己決定,各組之間不需要共享內部細節,也不依賴別組的工作。

(3)大團隊應該保障子團隊的自主權,按照子團隊提供的功能和商業價值,進行資源分配。

(4)軟件架構師的角色很重要。

軟件架構師的關注點,不應該是團隊使用的工具和技術,而是各種服務與整個系統運行狀況之間的協議和通信,保證代碼和團隊可以正確解耦。

(5)代碼解耦和團隊解耦的關係。

理想情況下,代碼解耦與團隊解耦保持一致,形成一對一的關係,一個子團隊負責一個獨立的模塊。實際運作中,一個子團隊負責幾個模塊也可以,但是一個模塊不能由多個子團隊來參與。

(6)通信(模塊之間的、子團隊之間的)儘量規範化,爭取做到過程簡單、文檔充分,最好有規範的 API,這樣無需任何人員交流,就能建立通信。

(完)