刚刚接触IT行业的程序员都会有一个痛点,自己写的代码觉得很好,但是别人看你的代码的时候,总觉得太乱了,没有规范。后面维护的程序员就痛苦了。为什么我会提出这个问题,我就是从这一样走过来。今天推荐看的一本书《代码整洁之道》。

<>思维导图

<>总结:

<>代码是团队沟通方式。

* 设计思想流程图编写。
* 代码结构清晰,注释合理,方法参数备注。
* 遵循团队制定的代码规范,就必须遵循下去,新手进来也要遵循。
<>有意义的命名

* 使用有意义且可拼写的变量名 #反面 $ymdstr = $moment->format('y-m-d'); #正面 $currentDate =
$moment->format('y-m-d');
* 同种类型的变量使用相同词汇 #反面 getUserInfo(); getClientData(); getCustomerRecord(); #正面
getUser();
* 使用易检索的名称 #反面 //What the heck is 86400 for?(86400到底是干什么的) addExpireAt(86400);
#正面 // Declare them as capitalized `const` globals.(用常量大写来声明变量) interface
DateGlobal { const SECONDS_IN_A_DAY = 86400; } addExpireAt(DateGlobal::
SECONDS_IN_A_DAY);
* 使用解释型变量 #反面 $address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/'; preg_match(
$cityZipCodeRegex, $address, $matches); saveCityZipCode($matches[1], $matches[2]
); //*对比 #正面 $address = 'One Infinite Loop, Cupertino 95014'; $cityZipCodeRegex
= '/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/'; preg_match($cityZipCodeRegex, $address,
$matches); list(,$city, $zipCode) = $matchers; //list()把数组中的值赋给一组变量
saveCityZipCode($city, $zipCode); //这里只用了 $city 和 $zipCode 变量。
*
避免心理映射

不要让读者在脑中将你的名称译为他们熟知的名称。

*
命名
类名:不应当时动词,避免使用Manager、Processor、Data、Info这样的类名。
方法名:动词或者动词短语,言到意到,意到言到 。eg:getName()
使用领域名称:eg :AccountVisitor =>Visitor模式
别用双关语:避免将同一单词用于不同的目的。
不添加没用的语境: eg:GSDAccountAddress =>Address

<>函数

* 方法有多短小才合适没有定论,但是长达500行的一个方法,绝对让阅读者起杀人之心。 #反面 // 获取个人信息 Private UserDTO
getUserDTO(Integer userId) { //获取基本信息 … 此处写了10行 //获取最近的一次订单信息 … 此处写了30行 //
获取钱包余额、可用优惠券张数等 ... 此处写了30行 return userDTO; } #正面 // 获取个人信息 Private UserDTO
getUserDTO(Integer userId) { //获取基本信息 UserDTO userDTO= getUserBasicInfo(userId)
; //获取最近的一次订单信息 userDTO.setUserLastOrder(getUserLastOrder(userId)); //
获取钱包、可用优惠券张数等 userDTO.setUserAccount(getUserAccount(userId)); return userDTO; }
Private UserDTO getUserBasicInfo(userId); Private UserLastOrder getUserLastOrder
(userId); Private UserAccount getUserAccount(userId);
*
单一责任(一个函数只负责一件事情)

*
每一个函数一个抽象层级(阅读代码自顶向下代码:向下规则)
总分的写法(个人理解):总是写步骤,分是写步骤需要的方法。

*
使用描述性的名称(动词+关键词)
eg:writeField
* 减少if/else嵌套,多使用多态,一个函数做一件事,遵从单一责任 #反面 // 修改用户密码,这个例子只有3层嵌套,很温柔了 public
booleanmodifyPassword(Integer userId, String oldPassword, String newPassword) {
if (userId != null && StringUtils.isNotBlank(newPassword) && SpringUtils.
isNotBlank(oldPassword)) { User user = getUserById(userId); if(user != null) {
if(user.getPassword().equals(oldPassword) { return updatePassword(userId,
newPassword) } } } } #正面 // 修改用户密码 Public Boolean modifyPassword(Integer userId,
String oldPassword, String newPassword) { if (userId == null || StringUtils.
isBlank(newPassword) || StringUtils.isBlank(oldPassword)) { return false; }
User user= getUserById(userId); if(user == null) { return false; } if(!user.
getPassword().equals(oldPassword) { return false; } return updatePassword(userId
, newPassword); }
* 函数方法参数过多,如何优化。 #反面 Class Book { public function create($name, $cateId,
$author, $year, $price, $publish, $country, $language) { $params = [ 'name' =>
$name, 'cateId' => $cateId, 'author' => $author, 'year' => $year, 'price' =>
$price, 'publish' => $publish, 'country' => $country, 'language' => $language, ]
; } } #真面 class BookModel { protected $name; protected $cateId; protected
$author; protected $year; protected $price; protected $publish; protected
$country; protected $language; public function getName() { return $this->name; }
public function setName($name) { $this->name = $name; } public function
getCateId() { return $this->cateId; } public function setCateId($cateId) { $this
->cateId = $cateId; } public function getAuthor() { return $this->author; }
public function setAuthor($author) { $this->author = $author; } public function
getYear() { return $this->year; } public function setYear($year) { $this->year =
$year; } public function getPrice() { return $this->price; } public function
setPrice($price) { $this->price = $price; } public function getPublish() {
return $this->publish; } public function setPublish($publish) { $this->publish =
$publish; } public function getCountry() { return $this->country; } public
function getLanguage() { return $this->language; } public function setLanguage(
$language) { $this->language = $language; } } #控制器调用 Class Book { public
function create(BookModel $bookModel) { $params = [ 'name' => $bookModel->
getName(), 'cateId' => $bookModel->getCateId(), 'author' => $bookModel->
getAuthor(), 'year' => $bookModel->getYear(), 'price' => $bookModel->getPrice(),
'publish' => $bookModel->getPublish(), 'country' => $bookModel->getCountry(),
'language' => $bookModel->getLanguage(), ]; } }
* 抽离try/catch
1、 使错误处理代码从主路径代码中分离出来得到简化。
2、关键try应该是这个函数的第一个单词且catch/finally后无其他内容。
3、消灭错误码 #反面 // 获取个人信息 Private UserDTO getUserDTO(Integer userId) { try {
//获取基本信息 ... 此处写了10行 //获取最近的一次订单信息. ...此处写了20行 // 获取钱包、可用优惠券张数等 ...此处写了20行 }
catch (Exception e) { logger.error(e); return null; } } return userDTO; } #正面
// 获取个人信息 Private UserDTO getUserDTO(Integer userId) { //获取基本信息 UserDTO userDTO
= getUserBasicInfo(userId); //获取最近的一次订单信息 userDTO.setUserLastOrder(
getUserLastOrder(userId)); // 获取钱包、可用优惠券张数等 userDTO.setUserAccount(
getUserAccount(userId)); return userDTO; } Private UserDTO getUserBasicInfo(
userId); Private UserLastOrder getUserLastOrder(userId); Private UserAccount
getUserAccount(userId){ try{ // TODO } catch( Exception e) { //TODO} }
* 别重复自己
比如:算法重复了多次,还与其他代码混在一起,修改是需要修改4个地方,整体的可读性下降。

*
注释
1、法律信息(版权及著作权声明)
2、提供信息的注释,函数名
3、对意图的解释——某个决定后面的意图
4、阐释
5、警示
6、TODO注释(工作中将需要完成的功能列出来,完成就注释)

*
格式
1、垂直格式:用大多数为200行、最长500行的单个文件构造出色的系统是可能的,尽管这并非不可违背的原则,也应该乐于接受。短文通常比长文件易于理解。
1.1、源文件名称简单,程序的结构先总再分,阅读从上往下读。
1.2、每组代码行展示一条完整的思路。这些思路用空白行区隔开。每个空白行都是一条线索,标识出新的独立概念。
1.3、如果说空白行隔开了概念,靠近的代码则暗示了它们之间的紧密关系。所以,关系紧密的代码应该互相靠近。
1.4、方法相关的方法应给放在附近,避免跳来跳去。
2、横向格式:保持代码短小。
2.1、水平方向的间隔和靠近:使用空格字符分隔,不在函数名和左圆括号加空格。
2.2、水平对齐:不是把强调的声明变量拉开距离。
2.3、缩进:突显层次感
2.4、空范围:有时while或for的语句体为空。空范围缩进,用括号包围起来。
2.5、开发前先定好团队规则,缩进,命名类、变量和方法。

*
对象与数据结构
1、在不改动既有数据结构前提下添加新函数,面向对象在不改动既有的函数前提下添加新类
2、得墨忒耳定律是什么?
得墨忒耳定律-对象 O 的 M 方法,可以访问/调用如下的: 1.这个对象自己拥有的方法; 2.传入该方法的参数的方法; 3.该方法创建的对象的方法; 4.
该对象直接拥有的对象的方法; 换言之:每个单元(对象或方法)应当对其他单元只拥有有限的了解。
打个比方:假设我在便利店购物。付款时,我是应该将钱包交给收银员,让她打开并取出钱?还是我直接将钱递给她?(不要和陌生人说话。)class A{ private
B b= new B(); private void methodE(){} public void methodA(C c){ D d = new D();
methodE(); //1这个对象自己拥有的方法,可调用 c.print(); //2传入该方法的参数的方法,可调用 d.invert();
//3该方法创建的对象的方法,可调用 b.kill(); //4该对象直接拥有的对象的方法,可调用 F f = b.getF(); f.rock();
//5 该对象依赖对象的实现的模块,不可调用。 } }
3、最精炼的数据结构,是一个 只有公共变量、没有函数的类,叫数据传送对象(DTO).

* 错误处理
1、使用异常而非返回码。只要新增Exception的异常了而无需修改错误码枚举类
2、先写try-catch-finally语句。先构造try代码块的事物范围,维护好该范围的事务特征。
3、依调用者需要定义异常了将第三方API打包是好的实践手段。
4、定义常规流程。特例模式:创建一个雷或配置一个对象用来处理特例,客户就不用应付异常行为了
5、别返回NULL值

技术
©2019-2020 Toolsou All rights reserved,
el-select同时获取label和value值airflow 定时任务+时间设定+cron表达式JQ get请求 拼接 url 参数 (查询条件)非父子组件之间的三种传值办法pytorch之ResNet18(对cifar10数据进行分类准确度达到94%)airflow问题系列2 —— task保持running假死状态Keras训练数据加载实现小结使用VS2019 “Windows桌面应用程序”模块创建Win32窗口STM32红外寻迹小车11-5 指定位置输出字符串