
節日剛來,公司把隔壁業務線的一個核心骨幹提拔成了前端組長。
新上任,他花了整整一個晚上,在內網的 Confluence 上寫了一份👉 《前端團隊研發協作與編碼規範》。
為了體現專業度,他還特意把文件連結發到了全員群裡,並且配置了非常嚴格的 ESLint 和 Husky 提交攔截。
我隨手點開那份規範看了一眼,裡面有一段關於網路請求和 TypeScript 型別的規定,寫得非常理想主義😢。
我直接把原文件的部分片段,給你們摘錄出來👇:
4.1 嚴禁使用 any業務代碼、公共元件、工具函式、介面定義、狀態管理中,均嚴禁出現
any。4.2 嚴禁使用 unknown 規避 any
unknown僅允許在底層工具函式中使用,業務代碼中不得使用unknown作為後端資料兜底型別。4.3 介面出入參必須完整定義所有後端介面必須定義請求參數和回應參數。
當時開會在投影機上過這份文件時,大家紛紛鼓掌說好,覺得咱們的程式碼終於能擺脫草台班子的氣質,向大廠開源規範看齊了😁。
結果晚上臨近發版,我幫他們組 Review 一段緊急合入的業務程式碼時,差點笑出聲。
理想中的規範是一塵不染的,但現實業務裡的程式碼全是泥巴。我給你們看看,為了躲避這段嚴苛的規範,一線開發兄弟在提測倒數的重壓下,寫出的程式碼:
typescript 体验AI代码助手 代码解读复制代码// 後端老哥下午臨時改了表單的回傳結構,把原本的陣列改成了一個逗號分隔的字串
// 前端兄弟急著提測,但又被 Git Hook 死死卡住不讓提交
// 於是他為了繞過嚴禁使用 any的規範,寫出了這種極其敷衍的宣告:
type MagicType = unknown; // 高級 any,完美騙過簡單的 ESLint 掃描
interface UserFormRes {
userId: number;
// 先 unknown 占位
dynamicExtData: MagicType;
}
const UserProfile = () => {
const [data, setData] = useState<UserFormRes | null>(null);
const renderPrivilege = () => {
// 規範要求:必須用可選鏈,必須做型別兜底
// 於是業務層出現了一坨安全轉換程式碼:
const extStr = (data?.dynamicExtData as string) || '';
const list = extStr.split(',').filter(Boolean);
// 強行把 boolean 轉換回後端有時候亂傳的 0 和 1
const isVip = (data?.dynamicExtData as any)?.is_vip == '1' || false;
return <div>{/* 渲染邏輯 */}</div>;
}
}
再去翻翻那一天的 Git 提交紀錄。 原本規範裡白紙黑字寫著,Commit Message 必須是 feat(模組名): [JIRA號] 更新詳情。 但大家被攔截規則搞煩了,又不想去查具體的命令格式,於是那一晚的紀錄裡,滿屏都是用快捷指令強行繞過的產物:
git commit -m "fix" --no-verify
看著新負責人在群裡無奈地圈人,問大家為什麼不按規範來,我其實非常理解他的挫敗感的🤔。
在這個行當混了這麼多年,帶過好幾個大大小小的團隊,我見過太多這種死在搖籃上的技術規範。很多人總覺得,只要規矩定得細,配上攔截工具,大家就會乖乖就範。
但這忽略了一個最致命的現實:前端是直接扛業務壓力的最後一環。
當產品經理站在你座位旁邊,問你為什麼這個按鈕點下去沒反應?測試在群裡瘋狂 @你,倒數還有半小時就要封板上線。這個時候,你腦子裡只有一件事:把邏輯跑通,讓錯誤消失。
這時候誰有空去翻那十幾頁的文件,查一查這個巢狀了四層、連後端自己都說不清楚的 JSON 結構,到底該怎麼老老實實寫成 Interface?
當你的規範阻礙了同事準時下班,一線的開發者有一萬種方法繞過你的各種 Lint 工具。
那麼,既然這種事無巨細的規範行不通,團隊程式碼是不是就活該變成垃圾堆?
其實也並不是。真正有效的前端管理,從來不是寫小作文,而是抓大放小。
我現在帶專案,從來不限制組員在具體的單個業務文件裡怎麼折騰。我不在乎他是不是多寫了幾個毫無意義的 div 巢狀,也不在乎他是不是為了圖省事寫了個 as any。那些東西雖然不優雅,但最多就是他自己幾個月後接手時看著頭痛,影響面可控。
但我會死守工程的底線邊界。給大家看一個我平時做 Code Review 絕對會當場打回重寫的真實案例:
javascript 体验AI代码助手 代码解读复制代码// 某個新人寫在促銷活動頁面的程式碼
// 這種程式碼我一眼都不會讓它合進主分支
useEffect(() => {
// 錯誤 1:在業務元件裡直接裸寫 fetch,繞過全域請求實例
fetch('https://api.nurverse.com/v1/get-discount')
.then(res => res.json())
.then(data => {
setDiscount(data.price);
})
.catch(err => {
// 錯誤 2:私自吞掉報錯,不接入統一監控
console.log(err);
});
},[]);
我不強制他定義完美的入參出參,但我絕對不允許他裸調介面和私自吞掉錯誤🫡。
因為一旦這個介面報了跨域,或者後端拋了 500,全域的 Axios 攔截器抓不到它,公司的統一監控大盤也收不到告警資訊。到了第二天客訴找上門,全組人都要陪著他排查到底是哪個節點掛了,這就是在給整個團隊挖坑。
我會讓他老老實實改成這樣👇:
typescript 体验AI代码助手 代码解读复制代码// 所有的網路層互動,必須走基礎封裝
import { http } from '@/utils/request'; // 統一的請求封裝
import { reportMonitor } from '@/utils/monitor'; // 統一的監控上報
useEffect(() => {
// 必須通過全域 http 實例呼叫,自動帶上 Token、重試機制和全域攔截
http.get('/v1/get-discount')
.then(data => setDiscount(data.price))
.catch(err => {
// 非共用錯誤,業務側攔截後必須手動上報大盤
reportMonitor('Discount_Fetch_Fail', err);
});
}, []); // 依賴陣列根據實際情況補充
發現差別了嗎?
管理技術團隊,和敲鍵盤寫程式碼是兩套完全不同的邏輯。程式碼只要邏輯對,它就永遠按預期執行,但人就不是🤷♂️。
任何一項技術規範的落地,本質上都是一次團隊內部的習慣磨合。別再拿著那份十幾頁的文件試圖去改造全組人了。砍掉那些脫離業務的偽需求,刪掉那些讓人抓狂的強制檢查,去關注那些真正拖慢團隊協作的鏈路瓶頸🫵。
當你的團隊成員發現,你定的每一條規則,都是在幫他們少踩坑、少背鍋、能準時下班的時候。根本不需要任何強制文件,你提倡的最佳實踐,自然會成為大家的工作習慣。
這才是一個前端負責人,真正該有的技術管理品味。
你們說是不是呢?