作为初学者,您可能不会过多考虑代码风格。采用以下三个原则,可以立即提高您的代码质量。
在过去几个月中,我有机会指导一组才华横溢的新网页开发人员,他们参加了 TechLabs 的数字塑造者计划。
看到这个团队从零开始学习到最终发布应用程序的学习过程真是太有趣了。当我审查他们的代码时,它让我想起了自己作为开发者的头几年。特别是当您是自学的,没有任何正式的教育背景,您只会不停地尝试。您无法感知好的或坏的代码实践。您会对任何能够工作的东西感到高兴。
这让我想到了一个问题:“哪些编码原则是我希望早些时候就知道的?”这里就是它们!
您可以立即在编码实践中实施这些简单的提示。虽然简单,但它们对我的代码编写方式产生了很大的影响。
注意:尽管标题明确指出“前端开发人员”,但这些原则适用于编程的所有领域。
1、使用“提前返回”代替嵌套条件语句
在Web开发中,您会遇到很多需要检查特定条件是否满足的情况。
举个例子,假设您有一个API路由,用于验证请求并返回一个用户对象:
export const handler = async (req, res) => {
if (req.method === "POST" || req.method === "OPTIONS") {
const email = validateEmail(req.body.email);
if (email) {
const user = getUserByEmail(email);
if (user) {
return res.status(200).json({ user });
} else {
return res.status(404).json({ message: 'No user found' });
}
} else {
return res.status(422).json({ message: 'Missing email' });
}
} else {
return res.status(405).json({ message: 'Unsupported message' });
}
}
虽然这个函数中没有太多的逻辑封装,但它看起来已经有些杂乱无章了。具体来说,这段代码存在以下两个问题:
很难跟踪代码流程。我们需要从左到右而不是从上到下阅读代码(箭头反模式)。
很难找到每个 if 对应的 else 语句。它们被 if 语句的大体量隔开了。
改进这段代码的一个简单技巧是使用“提前返回”模式(Return-Early-Pattern)。“提前返回”模式会在不满足条件时终止函数的执行,以便函数的期望结果始终出现在最后。如果我们重新编写上面的 API 路由,它将如下所示:
export const handler = async (req, res) => {
if (req.method !== "POST" && !req.method !== "OPTIONS") {
return res.status(405).json({ message: 'Unsupported message' });
}
const email = validateEmail(req.body.email);
if (!email) {
return res.status(422).json({ message: 'Missing email' });
}
const user = getUserByEmail(email);
if (!user) {
return res.status(404).json({ message: 'No user found' });
}
return res.status(200).json({ user });
}
使用“提前返回”模式后,我们可以轻松地从上到下跟踪代码执行。由于我们假设一切顺利,只检查缺失的值,因此避免了嵌套太多条件。
最后,我们可以一眼看到函数的期望结果,它位于最底部。
2、为人类编写代码
归纳前一个提示的内容,我们得到了第二个原则:编写易于他人阅读而非机器的代码。
这听起来很平凡,但起初却让我彻底改变了思维方式。当我开始编程时,我总是把它看作是与计算机交流的一种方式。我们告诉计算机要做什么。但我们编写的代码是由同事阅读和理解的,而不是机器。
我们的同事是需要阅读和理解代码的人。最终,计算机将一切都转换为 0 和 1,并不关心可读性。让我们以 groupBy 函数为例:
const groupBy = (arr, groupFn) =>
arr.reduce(
(grouped, obj) => ({
...grouped,
[groupFn(obj)]: [...(grouped[groupFn(obj)] || []), obj],
}),
{}
);
我们清楚地展示了如何编写复杂的单行函数来执行简单的操作:对数组进行分组。
尽管这可能让您感觉更加专业,但对于任何需要审查代码的人来说,这确实会使事情更加难以理解。相比之下,考虑以下实现方式:
const groupBy = (arr, groupFn) => {
const grouped = {};
for (const obj of arr) {
const groupName = groupFn(obj);
if (!grouped[groupName]) {
grouped[groupName] = [];
}
grouped[groupName].push(obj);
}
return grouped;
};
我们可以从上到下阅读这段代码,并立即了解每行代码的作用。
尽管这可能看起来没有之前的实现方式那么酷炫,但是以后所有需要重新审查这段代码的人都会因为这种易于阅读的实现方式而感谢您。
3、将信息隐藏在函数背后
作为初级开发人员,改进代码风格的最后一个想法是将不相关的信息隐藏在函数背后。这也有助于提高代码的可读性。
如果您熟悉 React,Hooks 是这一原则的一个很好的例子:
import React, { useState, useEffect } from 'react';
function FriendListItem(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
在这里,我们有一个组件,它输出一个带有动态状态颜色的列表项。虽然这段代码可以正常运行,但它封装了与 FriendListItem 组件的目的不直接相关的逻辑。
如果我们提取该逻辑并创建一个名为 useFriendStatus 的自定义 Hook,我们可以简化该组件,如下所示:
import React, { useState, useEffect } from 'react';
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
这样做有两个好处:
我们可以重用 useFriendStatus 的逻辑。
我们将组件简化为其功能的实质内容。
更一般地说,隐藏信息的原则是将不相关的信息封装在抽象函数背后。
因此,我们不需要关心抽象函数内部发生了什么(实现细节)——我们可以更专注于它的目的,即函数的名称(问题域的级别)。
总结
我希望这些小技巧对您有所帮助!本质上,编写更好的代码通常只是让它更易于阅读和理解,无论是对于您自己还是对于其他人来说。
原文:
https://konstantinmuenster.medium.com/3-tips-to-write-better-code-as-a-beginner-frontend-developer-ea0fe9b3492c作者:Konstantin Münster
非直接翻译,有自行改编和添加部分,翻译水平有限,难免有疏漏,欢迎指正