【编码错误】新手程序员常见的编码错误
新手程序员常见的编码错误
文章目录
- 前言
- 一、没有了解需求就开始写代码
- 二、不沟通交流就开始做需求
- 三、代码素养差
- 四、编码问题总结
- 4.0不注重代码格式
- 4.0.1空格
- 4.0.2换行
- 4.1随意命名
- 4.1.1有意义的参数名
- 4.1.2见名知意
- 4.2从不写注释
- 4.3方法过长
- 4.4参数过多
- 4.5代码层级太深
- 4.6硬编码
- 4.7不正确的日志打印
- 4.8没校验入参
- 4.9返回值格式不统一
- 4.10提交到Git的代码不能编译通过
- 4.11不处理没用的代码
- 4.12从不写单元测试
- 4.13 魔数和字符串
- 4.13.1魔数
- 4.13.2字符串
- 4.14释放指针未判断
- 4.14.1释放之前未判断
- 4.14.2释放之后未置空
- 4.15出现大量重复代码
- 4.16源数据未使用const
- 4.17代码中过多的ifelse判断
- 4.17.1switch优化
- 4.17.2策略模式(多态)
- 总结
前言
前言:新手程序员基本上都会犯的错误盘点,很多人刚开始写代码都是迫不及待的项目一到手就开始敲,一定一定一定要想想清楚,再开始动手写代码,一个合格的码农,是一个有思想的码农!而不是上来就敲代码的机器人。
一、没有了解需求就开始写代码
作为新手,为了展示自己的能力,刚刚拿到需求,就开始迫不及待地上手写代码,这是大忌!
有些人匆匆看一眼需求就开始做框架,有些人没看仔细没捋清楚就自以为了解了就开始写,到最后发现跟需求跑偏。更有些莽夫程序员上手就直接敲,只看类型不看需求就开始干。
建议:怎么说呢,有干劲是好的,但是一定要把项目需求,完完整整的,条理清晰的搞清楚。这样会减少很多很多很多的工作难度
二、不沟通交流就开始做需求
有的新手程序员不爱说话,不爱沟通,有的时候需求都理解错误了,结果最后做出来才发现,只能加班返工。其实很简单的一件事情往往都会被忽略,就想去考试你连考的什么科目都不看清楚,上去就答题那又怎么可能考高分呢
建议:一定要记得在拿到需求的时候,和对方多多进行交流和沟通,这样子才可以很好的理解需求,不会误解,从而少做很多无用功。不懂就问嘛,又不丢人。做事没有计划多办都是在做无用功三:沟通的时候就只是沟通,不懂得记录
文档的作用,很多时候不是用来沟通的,而是用来做记录的,很多的需求还是通过口头沟通,但是不写文档做记录,后续就容易扯皮。这里要划重点做笔记,有多少程序员在这个地方吃过亏,掉这个坑里的程序员堆起来怕是能绕地球十圈了。
建议:一定要记得现在沟通的时候做好记录,免得对方在后期反口!
三、代码素养差
第三点是大多数新手常遇到的问题,归其一点主要原因就是代码写的少、看得少。优秀的代码看多了写多了可以极大的提升你的代码素养。写代码其实跟写文章一样的,有异曲同工之妙。以下我以本人学习期间常遇到的一些编码问题的总结,分享出来与大家共勉。
常见的编码问题:
四、编码问题总结
4.0不注重代码格式
4.0.1空格
有时候必要的空格没有加(示例)
void test1(){addLog("test1");if (condition1){if (condition2){if (condition3){log.info("info:{}",info);}}}
}
正解:
void test1() {addLog("test1");if (condition1) {if (condition2) {if (condition3) {log.info("info:{}", info);}}}}
4.0.2换行
改换行时没有换行(示例)
//更多菜单m_menuMore = new QMenu(this);m_menuMore->setCursor(Qt::PointingHandCursor);m_menuMore->setStyleSheet(QSS_MORE_MENU);aboutAction = new QAction(tr(ABOUT_NAME), m_menuMore);aboutAction->setIcon(QIcon(QString(ABOUT_PATH)));
正解:
//更多菜单m_menuMore = new QMenu(this);m_menuMore->setCursor(Qt::PointingHandCursor);m_menuMore->setStyleSheet(QSS_MORE_MENU);aboutAction = new QAction(tr(ABOUT_NAME), m_menuMore);aboutAction->setIcon(QIcon(QString(ABOUT_PATH)));
4.1随意命名
代码中虽然没有强制要求参数、方法、类或者包名该怎么起名。但如果我们没有养成良好的起名习惯,随意起名的话,可能会出现很多奇怪的代码。一个好的命名可以让人见名知意
4.1.1有意义的参数名
代码如下(示例):
int a = 1;
int b = 2;
String c = "abc";
boolean b = false;
4.1.2见名知意
int supplierCount = 1;
int purchaserCount = 2;
String userName = "abc";
boolean hasSuccess = false;
4.2从不写注释
有时候,在项目时间比较紧张时,很多人为了快速开发完功能,在写代码时,经常不喜欢写注释。
此外,还有些技术书中说过:好的代码,不用写注释,因为代码即注释。这也给那些不喜欢写代码注释的人,找了一个合理的理由。
写注释有助于很快的去理解代码的逻辑跟用意
比如:
void GfSso::on_TimerEvent() {#ifdef _WIN32HWND m_hwndDisplay = (HWND)this->winId();FLASHWINFO fInfo;fInfo.cbSize = sizeof(FLASHWINFO);fInfo.hwnd = m_hwndDisplay; //要闪烁的窗口的句柄,该窗口可以是打开的或最小化的fInfo.dwFlags = 3; //闪烁的类型fInfo.uCount = 8; //闪烁的次数fInfo.dwTimeout = 300; //闪烁的频度,毫秒为单位;FlashWindowEx(&fInfo);// FlashWindow(HWND(this->winId()), true);#endifm_pTimer->stop();
}
4.3方法过长
void GfSso::showGfMsgBox(int msgType, QString text) {int width = 0;int height = 0;switch (msgType) {case 0: {gfMsgBox *msgBox = new gfMsgBox(this, MsgBoxType_Warn, text);QRect rect = this->geometry();//计算显示原点locationX = rect.x() + (this->width() - widgetX) / 2;locationY = rect.y() + (this->height() - widgetY) / 2;msgBox->move(width, height);msgBox->exec();} break;case 1: {gfMsgBox *msgBox = new gfMsgBox(this, MsgBoxType_Warn, text);QRect rect = this->geometry();//计算显示原点locationX = rect.x() + (this->width() - widgetX) / 2;locationY = rect.y() + (this->height() - widgetY) / 2;msgBox.exec();} break;case 2: {gfMsgBox *msgBox = new gfMsgBox(this, MsgBoxType_Warn, text);QRect rect = this->geometry();//计算显示原点locationX = rect.x() + (this->width() - widgetX) / 2;locationY = rect.y() + (this->height() - widgetY) / 2;msgBox.exec();} break;default:break;}
}
可以改为:
void GfSso::getCoordinate(int &locationX, int &locationY, int widgetX, int widgetY) {QRect rect = this->geometry();//计算显示原点locationX = rect.x() + (this->width() - widgetX) / 2;locationY = rect.y() + (this->height() - widgetY) / 2;
}
void GfSso::showGfMsgBox(int msgType, QString text) {int width = 0;int height = 0;switch (msgType) {case 0: {gfMsgBox *msgBox = new gfMsgBox(this, MsgBoxType_Warn, text);getCoordinate(width, height, msgBox->width(), msgBox->height());msgBox->move(width, height);msgBox->exec();} break;case 1: {gfMsgBox msgBox(this, MsgBoxType_Right, text);getCoordinate(width, height, msgBox->width(), msgBox->height());msgBox.exec();} break;case 2: {gfMsgBox msgBox(this, MsgBoxType_Error, text);getCoordinate(width, height, msgBox->width(), msgBox->height());msgBox.exec();} break;default:break;}
}
4.4参数过多
示例:
void fun(String a,String b,String c,String d,String e,String f) {...
}void client() {fun("a","b","c","d",null,"f");
}
4.5代码层级太深
示例:
if (a == 1) {if(b == 2) {if(c == 3) {if(d == 4) {if(e == 5) {...}...}...}...}...
}
这段代码中有很多层if判断,是不是看得人有点眼花缭乱?
对于深层级的判断可以先行判断不满足条件的逻辑,先返回。
4.6硬编码
这里举个例子:
mProxy = new pkiAgentProxy("CommonTest", "e3d93edf-d7e4-13da-2eaf-d63724026f34", "56a4d6a2-ef41-8ee7-d3a5-ac3a7ccdb9d7");
当这样的使用范围很广时或者需要更改时就会变得很麻烦。可以使用宏的方式定义,这样只需要改变一处的宏就可以一劳永逸了。
#define APP_NAME "CommonTest";
#define APP_ID "e3d93edf-d7e4-13da-2eaf-d63724026f34";
#define APP_TOKEN "56a4d6a2-ef41-8ee7-d3a5-ac3a7ccdb9d7";mProxy = new pkiAgentProxy(APP_NAME ,APP_ID ,APP_TOKEN );
4.7不正确的日志打印
在我们写代码的时候,打印日志是必不可少的工作之一。
因为日志可以帮我们快速定位问题,判断代码当时真正的执行逻辑。
但打印日志的时候也需要注意,不是说任何时候都要打印日志,比如:
map<int, int>::iterator ret = m.find(1);if (ret != m.end()){cout << "查找到数据元素为:" << ret->first<<" "<< ret->second << endl;TRUSTCONTROL_DEBUG("找到数据元素!");}else{cout << "元素未找到" << endl;TRUSTCONTROL_DEBUG("未找到数据元素!");}
}
对于有些查询接口,在日志中打印出了请求参数和接口返回值。
咋一看没啥问题。但如果传入值非常多,比如有1000个。而该接口被调用的频次又很高,一下子就会打印大量的日志,用不了多久就可能把磁盘空间打满。
对于日志我们只需要打印需要的或者错误的地方就可以了
4.8没校验入参
void parseStr(constr char *str){std::string = str;}
乍一看没什么问题,但是如果传进来的str是NULL时就会报错了。所以参数为指针时记得要做入参判断
4.9返回值格式不统一
对接接口返回值结构不一致:
{"ret":0,"message":null,"data":[]
}
另一边:
{"code":0,"msg":null,"success":true,"result":[]
}
4.10提交到Git的代码不能编译通过
我们写完代码之后,把代码提交到gitlab上,也有一些讲究。
最最忌讳的是代码还没有写完,因为粗心大意导致代码只上传了一部分,例如:
void test() {String userName="苏三";String password=
}
这段代码中的password变量都没有定义好,项目一运行起来必定报错。
这种错误的代码提交方式,一般是新手会犯。但还有另一种情况,就是在多个分支merge代码的时候,有时候会出问题,merge之后的代码不能正常运行,就被提交了。
好的习惯是:用git提交代码之前,一定要在本地运行一下,确保项目能正常启动才能提交。宁可不提交代码到远程仓库,切勿因为一时赶时间,提交了不完整的代码,导致团队的队友们项目都启动不了。
4.11不处理没用的代码
有时候我们在代码开发测试中添加了很多调试手段,部分代码已经不需要用到了但是我们任然保留着。
例如:
std::string message = buildSsoMsg(mLabel, authType, loginType, userName, passWord);emit sendData(QString::fromStdString(message));// 发送登录消息后,设置登录按钮不使能,防止多次点击// setLoginBtnEnable(false);
}
4.12从不写单元测试
因为项目时间实在太紧了,系统功能都开发不完,更何况是单元测试呢?
大部分人不写单元测试的原因,可能也是这个吧。
那么,我们为什么要写单元测试呢?
我们写的代码大多数是可维护的代码,很有可能在未来的某一天需要被重构。试想一下,如果有些业务逻辑非常复杂,你敢轻易重构不?如果有单元测试就不一样了,每次重构完,跑一次单元测试,就知道新写的代码有没有问题。
我们新写的对外接口,测试同学不可能完全知道逻辑,只有开发自己最清楚。不像页面功能,可以在页面上操作。他们在测试接口时,很有可能覆盖不到位,很多bug测不出来。
建议由于项目时间非常紧张,在开发时确实没有写单元测试,但在项目后期的空闲时间也建议补上。
4.13 魔数和字符串
4.13.1魔数
for (int i = 1; i <= 52; i++) {...
}
i为什么是1?53?看不懂…
4.13.2字符串
if (userPasswordIsValid($user,"6yP4cZ",password)) {...
6yP4cZ是什么?似乎非常随意...
}
4.14释放指针未判断
4.14.1释放之前未判断
{json_value_free(root_value);return bRet;
}
4.14.2释放之后未置空
改为:
{if(root_value){json_value_free(root_value);root_value = NULL;}return bRet;
}
4.15出现大量重复代码
void test1() {addLog("test1");}void addLog(String info) {if (log.isInfoEnabled()) {log.info("info:{}", info);}}
void test2() {addLog("test2");}void addLog(String info) {if (log.isInfoEnabled()) {log.info("info:{}", info);}}
void test3() {addLog("test3");}void addLog(String info) {if (log.isInfoEnabled()) {log.info("info:{}", info);}}
三个函数中均使用了addLog(),为何不把这种功能的代码提取出来,放到某个工具类中呢?
4.16源数据未使用const
当我们不想改变源数据时,要使用coonst修饰
例如:
static std::string buildMsg(const std::string &Str, int authType) {...
}
void test2() {addLog("test2");}void addLog(String info) {if (log.isInfoEnabled()) {log.info("info:{}", info);}}
4.17代码中过多的ifelse判断
if (status == 1) {// 逻辑1} else if (status == 2) {// 逻辑2} else if (status == 3) {// 逻辑3} else if (status == 4) {// 逻辑4} else if (status == 5) {// 逻辑5} else {// 逻辑6}
这段代码有什么问题呢?试想一下,如果需要判断的条件越来越多,比如:又加了新的判断逻辑、增加新的else…if判断,判断多了就会导致逻辑越来越多?
很明显,这里违法了设计模式六大原则的:开闭原则 和 单一职责原则。
开闭原则:对扩展开放,对修改关闭。就是说增加新功能要尽量少改动已有代码。
单一职责原则:顾名思义,要求逻辑尽量单一,不要太复杂,便于复用。
那么,如何优化if…else判断呢?
4.17.1switch优化
switch (status) {case 1:// 逻辑1breakcase 2:case 3:// 逻辑3、2 两个相同的可以写一起breakcase 4:// 逻辑4breakcase 5:// 逻辑5breakdefault:// 逻辑6break
}
4.17.2策略模式(多态)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class WeaponStrategy
{public:virtual void UseWeapon() = 0;};class Knife:public WeaponStrategy
{public:virtual void UseWeapon(){cout<<"使用匕首!"<<endl;}
};
class AK47:public WeaponStrategy
{public:virtual void UseWeapon(){cout<<"使用AK47"<<endl;}
};class Charcter
{public:void setWeapon(WeaponStrategy* weapon){this->pWeapon = weapon;}void ThrowWeapon(){this->pWeapon->UseWeapon();}WeaponStrategy* pWeapon;
};
int main()
{{//创建角色Charcter* t_charater = new Charcter;//武器策略WeaponStrategy* t_knife = new Knife;WeaponStrategy* t_ak47 = new AK47;t_charater->setWeapon(t_knife);t_charater->ThrowWeapon();t_charater->setWeapon(t_ak47);t_charater->ThrowWeapon();delete t_knife;delete t_ak47;delete t_charater;t_ak47 = nullptr;t_charater = nullptr;t_knife = nullptr;}system("pause");return 0;
}
总结
细节决定成败
所以基础很重要,俗话说:千里之行始于足下!
【编码错误】新手程序员常见的编码错误相关推荐
- 微信小程序新手容易犯的错误_新手程序员的错误以及如何避免它们
微信小程序新手容易犯的错误 To become a Senior Java Developer, I've been learning Java for many years and still I' ...
- 如何让程序员喜欢上编码
如何让程序员喜欢上编码 奇葩图片网(www.78tp.com) 多少人是因为兴趣而选择编码的,既然做程序员,为什么不选择喜欢编码呢?商业内幕最近发表了一篇文章说做程序员压力山大,很多人都快疯了. ...
- 程序猿误区:程序员只负责编码
程序猿误区:程序员只负责编码 误区一:飞鸽传书 软件开发以文档和图为驱动,程序员只负责编码.错. 在软件开发过程中,大多数认为开发过程是以文档和图为驱动,应该大多数人还是这么认为的吧.准确说项目开发不 ...
- 给新手程序员的16个工作必备小妙招,省下时间去LOL吧!
写在前面: 这个文章核心并不是程序优化的具体技巧,而是拿到一个问题如何思考和利用工具的通用方法.比如即使我们不知道 profiler 这个东西,通过搜索"代码 每一行 时间"也可以 ...
- 新手程序员基础都掌握了,动手敲代码就一脸懵逼?教你解决办法!
相信很多初学编程的朋友都有这样的苦恼:为什么我感觉自己基础都掌握了,也看过很多视频和资料了,但就是自己动手敲代码的时候就开始懵逼了! 通常新手程序员会以不同的方式来表达这个疑问,比如: "我 ...
- 编程老手的哪些特点,是值得新手程序员学习的?
作为一个经验丰富的程序员,有哪些事情是你希望在一开始编程的时候就知道的?或者换个方式来说,你认为每个新手程序员应该做或者学什么才能让自己的编程水平更好? 下面是一位 CTO Ken Mazaika 的 ...
- 程序员常见700单词
程序员常见700单词 快捷键 Ctrl+F 进行搜索查找 1. password /ˈpæswɜ:rd/ n. 密码 2. grep /'grep/ n. 检索目标行命令 3. tre ...
- 有哪些新手程序员不知道的小技巧?
提到新手程序员,大家想到的第一个词可能就是:刷题.尤其是通过LeetCode刷题,想必新手程序员们都经历过这一步,甚至不少人认为只要在LeetCode上刷的题目够多,就一定能够进阶为大神. 但是,不难 ...
- 师妹问我:有哪些新手程序员不知道的小技巧?
阅读本文大概需要5分钟. 一个师妹问:洋哥,我今年应届毕业,刚开始写代码,不知道有没有一些新手需要注意的地方. 给了师妹一些建议之后,感觉这是个好问题!不光是新手程序员,很多小技巧小秘密恐怕老手也未必 ...
最新文章
- 【剑指offer-Java版】34丑数
- 零基础带你一步步搭建Nacos高可用集群(史上最详细,赛过教科书!)为此我准备了三台云服务器+云数据库
- 基于nodejs实现本地网页服务器-实现手机测试电脑开发的移动端网页
- python中的多线程、多进程
- 广联达2018模板算量步骤_广联达gtj2021实操案例,新增6大板块,快速提高算量效率...
- 数据库高级知识——索引优化分析(二)
- 惠普暗影精灵3清灰_如何评价惠普笔记本这几年的表现?尤其是暗影精灵系列。...
- java 反射创建对象并赋值_[原创] Java JDBC连接数据库,反射创建实体类对象并赋值数据库行记录(支持存储过程)...
- linux下补丁制作及打补丁实例
- rabbitmq实战指南_太香了这份架构解密:从分布式到微服务(第二版),神仙进阶指南...
- java Web开发环境配置
- 【音视频】WIN8|WIN10的桌面采集技术-DXGI(一)
- [转载]Spring zuul日志配置
- 友善串口助手使用教程_友善串口调试助手基本功能怎么使用-友善串口调试助手使用教程...
- VS中fseek.cpp引发断点——将一个无效参数传递给了将无效参数视为严重错误的函数
- 西门子840d高级编程手册_斯沃系统手册--西门子高级编程手册_840D_810Di_810D_FM_NC高级篇.pdf...
- 【原创】2009.6.22犀浦记
- android 向上滑动home,滑动Home键
- linux ssh服务状态,查看linux ssh服务信息及运行状态方法
- 1+3+5+....+99的和为