最近在code review时发现了个有趣的现象:两个水平差不多的开发者做同一个需求,一个2小时完成,另一个花了两天还在"优化架构"。差别不大,但效率天差地别。
后来我意识到,他们用的其实是两种完全不同的思维方式。
假设现在要做一个用户资料编辑页面,用户可以切换账户、偏好设置、安全这三个tab。
咱们通常的思路是:
这个过程本身没啥问题,问题是:我们花在"怎么做"的时间,往往比花在"做"的时间还长。
他们其实是这样的:
直接想象UI(5分钟)
写最简单能用的版本(30分钟)
export default function UserProfile() {
const [tab, setTab] = useState('account');
return (
<div>
<button onClick={() => setTab('account')}>账户</button>
<button onClick={() => setTab('preferences')}>偏好</button>
<button onClick={() => setTab('security')}>安全</button>
{tab === 'account' && <div>账户内容</div>}
{tab === 'preferences' && <div>偏好内容</div>}
{tab === 'security' && <div>安全内容</div>}
</div>
);
}
就这样。没有Redux,没有复杂的文件结构,就是让它能跑起来。
看着代码,优化一遍(1小时)
搞定
这样算下来,总时间反而更少。而且最关键的是:代码从第30分钟就能跑起来,能看得到。
说起来有点矛盾,但确实是这样:当你看到代码跑起来以后,你才知道真正需要什么。
纸上谈兵的时候,你能想象出各种复杂场景:
但实际开发时你会发现:
所以那些快速交付的人,他们并不是"不讲究",而是先看到问题,再对症下药。
假设现在有10个类似的需求要做,分别用这两种方式:
方式A:先架构后编码
方式B:先简单后优化
而且方式B还有个好处:前两个小时,代码就跑起来了,产品经理能看到东西。
有个很重要的点要说清楚:这不是鼓励大家写烂代码。
Build-First的意思是:
不是说不要设计,而是设计的时机不一样。
举个例子,一开始写的时候:
// 有点rough,但能跑
const [account, setAccount] = useState(initialAccount);
const [pref, setPref] = useState(initialPref);
const [security, setSecurity] = useState(initialSecurity);
跑了一阵子以后,你会发现有一个共同的模式 —— 三个状态的操作逻辑类似。这时候再统一起来:
// 现在才优化
const [profile, dispatch] = useReducer(reducer, initialProfile);
// 一个action处理所有更新
dispatch({ type: 'UPDATE_FIELD', tab: 'account', field: 'name', value: '...' });
这个重构是在看到了真实问题以后才做的,而不是在"猜测可能有这个问题"的时候就提前设计。
我觉得很多人被教"坏"了。
上学时,老师教设计模式、教架构思想,这些本身都没错。但问题是,学完以后我们就开始过度应用。
一个三人小项目,也要考虑"未来的扩展性"。一个简单的表单,也要套用MVC模式。两个组件共享一个布尔值,也要上Context API。
时间久了,我们就养成了一个习惯:必须把架构设计好了,才能开始写代码。
但如果你观察那些高效能的开发者,他们的做法恰好相反。他们知道什么时候应该简单,什么时候应该复杂。
可以从下一个需求开始试试:
第一步(15分钟)
第二步(编码中)
第三步(review时)
第四步(下次做类似需求时)
这样坚持下去,你会逐渐发展出一套自己的"经验库"。新需求来时,你能快速判断:"这个需要简单方案"或者"这个需要上状态管理"。
这个直觉,就是那些快速交付开发者的秘密。
我们都想写高质量代码,但有时候我们把"高质量"理解错了。
"高质量"不是提前考虑所有可能,而是能快速响应真实需求。
不是最完美的架构,而是最合适当前场景的设计。
下次再听到"这个功能架构还没定呢"的时候,可以反问一下:真的需要提前定吗?还是能先跑起来再说?
很多时候,答案会让你惊讶。