规范
命名
代码整洁之道中内容很多, 不过这里单单只有命名一节. 被提醒过几次命名不合适, 这部分就着重整理出来, 每次命名的时候都思考思考. 能立刻改善自然最好, 不能立刻也要逐步前进.
名副其实、避免误导、使用读的出来的名称、避免可爱(要实用)
看到名字就知道这个变量是个什么东西,theList就不知道是个什么东西,studentList就好一些。
不能变量描述的是A,实际是B。比如给Map类型起名List
做有意义的区分
a1,a2,a3这些就没啥意义,x,y,z就有了
book和theBook也没区别
使用可以搜索的名称
找7就非常难找,但是找DAY_PEER_WEEK就好找了
避免思维映射
不要起只有自己能理解的取巧的名称,其他人可能是理解不了的
方法名使用动词或者动词短语
get、set、is
每个概念对应一个词
tower是地图中编码里塔的名称,瞭望塔最好起名watchTower不要和其他冲突了。
添加有意义的语境
name是名字的意思,petName?playerName?无法区分
firstName,lastName,street,city,state,这些放一起能看出来是地址,但是单单一个state就看不出来了,不如addrState,或者使用Address类
命名统一
命名要统一,多个人合作的时候要提前商量好,复制粘贴代码后也要注意代码的命名。
可以直接用机制来命名
比如模数余数这些名词
避免无意义修饰
阶段是阶段 等级是等级,不要用阶段等级这种东西
GPT
多用用GPT,这个起名字真的好用, 很有参考价值
break和nullptr
switch-case丢失break, 指针没有判空, 写全新模块的时候基本遇不到, 重灾区是在原有位置加代码.
注释
命名的章节混进来一点点注释, 我感觉问题不大.
- 复杂的功能描述下, 不然只有天才能立刻知道这一坨代码是干啥的
- 其他人或者连自己看起来都很怪的实现, 要说明下原因.
函数-写故事-反复打磨
book
短小
避免嵌套太多层
只做一件事情,做好一件事情
编写函数是为了将大一些的概念(函数名称),拆分成另一个抽象层上的一系列步骤。
- 函数名下都是同一个抽象层的步骤,实际还是做了一件事。
检查函数是否只做了一件事,可以看看函数是否可以再拆出一个函数
- 函数不仅仅是单纯的重新全是代码,必须要改变抽象层级
使用描述性的名称
长的具有描述性的名称,比短的令人费解的名称要好。
IDE中改名很容易,可以多次修改找到一个最具描述性的名称
函数参数
限制传入bool参数,bool参数表明了,可能存在两个分支,为true一个为false一个,可以考虑拆成函数。
给函数取个名字,用来解释函数的意图、参数和顺序和意图
assertEqual改成assertExpectedEqualsActual(Expected,actual),能够减少记忆参数顺序的负担。
无副作用
函数承诺只做一件事情(函数名描述),但是还会做其他被藏起来的事情(函数名没有描述的),这个就是函数会有的副作用。有人轻信了函数的名称,就会有这些藏起来的事情导致的风险。
减少重复
结构化编程
尽量保证函数只有一个出口,break,continue等语句限制使用。这些在短小函数中影响不是很大,但是在长函数中影响很大。
反复打磨
一步到位写出完美的代码是很难的,开始应该注重功能的实现,后面可以进行打磨(拆解函数、消除重复、修改名称)
经验
- 向其他函数增加代码时,如果时独立代码,抽出函数
注释
book
最好是使用代码本身当作注释,当一行或者一块代码需要注释的时候,可以考虑简化这些代码。
注释不能美化代码
通过增加变量来进行注释
错误的注释
- 注释可能会误导使用者,错误的注释比起没有注释更麻烦。
- 随着代码更新,只改代码不改注释,注释可能无法再与代码对应上
- 真正起作用的是代码,不是注释。所以可能出现注释和功能对应不上的问题
需要注释的地方
- 反直觉的代码,这些代码由于某些特殊原因,以反直觉的方式出现
- TODO
- 警示作用,某些代码可能具有破坏力
- 针对复杂的返回值进行说明(更好的方式是简化返回值)
经验
- 部分特殊的机制要加说明,不然就只有天才能立刻知道这里是什么意思了
杂项
- const能加的就加上吧
- 代码还是统一一些
- 判断是不是0 用==0或者if统一一点
- 空指针这种错误都犯了
- 改一个位置的时候,尤其要注意使用的所有参数,这些参数可能在外面并没有校验
- 改代码比新写代码更容易出现
- switch语句中丢失break
- 注意可能发生死循环代码的兜底
- 服务器更新脚本中就遇到了,重复的更新服务器。
记录总结
屎山
指针判空
使用指针时,一定要注意进行判空
break
switch中增加case的时候, 注意补齐break
全新屎山-设计
需求设计
- 看需求文档的时候 根据文档先定协议
- 需求理解一定要正确, 仔仔细细逐句逐句的看需求点. 需求点找出来之后,判断好是哪个服务器来做。防止开发重复的事项。
- 一些需要多个服务器共同实现的功能,要协商好处理方式。
- 查看策划的文档的时候,还是有想当然的内容
- 次数每天1天,上限5次。第1天想当然为5次,结果跟策划确认了是1次,而不是5次。
- 写代码之前先在vscode进行下预期设计, 比直接撸起袖子写代码好很多.
- 看看需求的特殊要求, 比如退盟之后是否重置, 这个影响到了数据记录到哪里.
- 考虑下客户端或者其他模块是否能如自己预期提供支持
- 可能预期的内容, 客户端根本没法做, 还是得服务器来做.
- 考虑下实现的复杂程度, 可能预期很简单, 但是因为牵扯过多或者不支持导致变得复杂.
- A场景下不用处理, 不代表B场景下不用处理
- 方案设计应该把框架性的描述到位
- 这次的跨天代码,文档中描述了,但是没有完整描述放到哪里。结果放到了Ext中,后面又改成了Role中。
- 反复想了很多次 感觉没有问题,然后就没有测试
- 结果还是出了问题,跟预期的一样,把leader和member的标记清掉了
加了新的子类型后没有适配
- 看到报错后 也没有去看原因
- 加了子类型也没看原有城郊BOSS的特殊处理
- 加了子类型也没通知客户端,应该是更改协议之后都要通知
方案可能可以用,但是对于目前还能用的代码,这种改动就需要考量下了。
现有的敌我判断,只需要在IsEnemy中加几行代码就可以了,大刀阔斧的去改成方案中的设计,可能会遇到很多的问题。
改动的时候应该考虑下改动小的方式?而不是去整一套新的方案。
复杂的方案为了通用性,后面维护起来也是很麻烦的。
时间评估
涉及增加Module + 协议 代码量200~300行 略微修改其他地方 1.5D
- 需求拆解和方案评估
- 不能是单单的将需求点列出来,需要对应到具体的改动是啥,这样评估时间才准确。
- 注意某些重要的异常情况处理和兜底处理
全新屎山-制作
通用的机制应该尽可能能够复用
- 在ext中新加了一个跨天的功能,但是这个功能其他ext可能也要用,应该放到上一级方便所有ext使用
- 终于把之前想过的时间触发器抽了个Module出来, 后面就可以复用了
一些临时的内容应该加足注释
比如明明可能有很多配置,按理来说应该是用参数索引,但是写死了,应该说明原因。
// 目前只有1条配置,先写死id为1
const auto *config = GetResFactory().FindResStrongpointRewardCfg(1);
一定要处理好不兼容变更的兜底,如果影响到太多人,容易出问题还是要加上兜底
预估时间后无法完成 没有及时通知
应该及时通知,否则认为完成了,后面会出现各种问题。这次就是配置全换掉了 导致半成品的怪物组被启用了
日志加的不够
- 查问题的时候比预期难太多了,后面补了两个主要位置的日志
- 选举队长的位置 增加了旧队长和新队长的状态
- 创建怪物组的时候会打印 玩家ID 怪物组ID 怪物组的配置 这样发现问题的时候能够快速定位到创建位置,之后就能看到问题野怪的ID
统一的工具仓库
以后写工具应该注意,一个工具放两个代码库维护是容易出问题的,能统一尽量统一,统一不了应该只在一个里面修改.
需求中途变更
代码设计初期一般会留有一些考虑能够应对需求变化,但是需求变化后可能会导致实现可以简化,这个时候继续服用复杂的代码还是简化代码就需要考虑了
尽量一步成型代码,后续修改容易顾此失彼,修改了这里忘了其他敌方
避免设计无用的东西
给堡垒加了adaptor,然而是一个函数能搞定的判断,多余了
数值类配置化or计算化
- 数值类的最好不要写死
- 如果是配置中的值,配置变了,写死的数值就会导致问题
- 还可能导致本来热更就能搞定的,需要重新编译服务器
- 尽量不要写死参数, 配置或者计算得来, 否则后面还需要同步修改.
减少通用错误码的使用
如果错误码一对一能够及时发现问题, 如果是多个地方使用的, 只能靠日志+看代码路径了.
客户端参数校验
没想到出现了非联盟成员拆联盟建筑的问题。
状态校验放错了位置. 写的时候还是没考虑好运行路径
全新屎山-装饰
GM工具
- 开发的时候可以考虑好后续可能用到的GM工具,虽然会略微增加开发时间,但是后续用到的时候是真的方便
- GM工具好多都是有使用场景的,非使用场景使用会出现问题,所以还是要标注清楚
旧屎山-修改
确定修改后果, 注意一个函数都有哪些作用
最大等级的BUG去掉InitModuleDependency中的广播后,确实去掉了开启时候的广播,但导致ClientConfig中的内容也没有被填写上。
且由于满阶段nextCheckInterval为0时添加的定时器 又掩盖了这个问题的及时发现 导致后面发现后改的挺急的
没有调用OnIdle出现的问题,结果加上OnIdle调用后影响到了回城
把表现正确的当BUG修了
这种还是要确认好,不然浪费双倍的时间
删除代码时应该注意 删除原位置无用的内容
新位置因为需要保证运行,所以一般不会出现问题,但是原位置的多余内容,一般不影响运行,不便于发现。
查问题的时候 用物体的事件经过查问题挺方便的
遇到BUG还是感觉留下现场,比重启解决问题更加重要
问题可以后面解决,复现问题可能再也没有机会了
BUG修复关联BUG单
之前删掉了一段代码,导致城郊出现问题,忘记为啥删除的了,后面修BUG还是带上BUG单的链接把
抽取函数注意不要影响到原区域功能
抽函数后加东西, 导致相对于原有增加了一些功能, 这种是很危险的抽函数.
简单方式解决问题
如果解决一个小bug, 完美的方式改动很多的话, 感觉不如简单的处理下
长久来说, 还是要考虑下解决这个问题, 算是一个优化点?
测试
测试好了再转单,可能确实把当前问题修了,但导致其他问题出现
改了BUG不好好验证, 而是急着去查下一个BUG.
全面测试, 不留空缺
战斗无法打起来
因为战斗无法打起来,好多地方开发的时候都没有测试到,结果反而这里才是问题所在
A通过B通过不等于A+B通过
一个功能还是完整的测试吧,A功能虽然等于B+C功能,但B和C功能分别正确 不一定B+C就是正确的
自动化测试
pyclient这个还是很方便的
心态
问题的优先级安排
下午差城郊防守建筑的BUG查上头了,虽然查出来了但导致了开战距离BUG的延迟了,进而导致了赏金联调的滞后。下午的时候防守建筑的BUG实际可以延后的
充分关注自己的工作
赏金都开始联调了,我的功能还没发上去
不懂就问
- 之前一直不知道转测时候填的内容有什么用,导致填的比较随意,导致后面还有同学来提醒,最开始填的时候也确实没有问过。
- 还是多问问那个sql语句是啥,原来是描述用的。。。
重视不起眼的小问题,可能背后的原因是非常离谱的
- dev环境选州Logic崩溃,竟然是由于Logic代码写错的原因(为啥外网没有遇到呢?)
- 测试反馈添加的主城全部报错30000,结果是因为roleId循环的,已经添加主城的roleId再次添加主城,由于兜底机制+指定roleId主城存在就会将roleId顺延,顺延之后的就是空roleid,后面就拿不到离线时间的数据
- 转表提交报错, 原因是空白行没有被标记占用, 导致新加字段写到了注释行上.
特殊处理
- 野怪最大等级改了获取位置,写代码的将等级为0认为是错误,直接返回了
- 然而赏金这里有特殊处理,等级是0则按1级
预期下当前所做是不是可以解决最终问题, 而不是当前某一步
- 压缩了个超大包, 确实解决了压缩的问题, 但是传输麻烦死了
去看看别人负责的模块, 不要只顾自己的模块
- 接触了下战斗服和逻辑服的代码, 把相关环境也搭建好了, 后续也确实看过几次对应的代码.
遇到问题即使下意识感觉问题就是那里, 也一定要确认下. 可能并不是那样
沟通和协作
他人回复的内容一定要仔细理解,不要含主观臆断
- X场景下,……………………………(省略),这个功能就不需要了。(非X场景是需要的,不能直接删掉这个功能)
- 今天晚上就合入版本了(几点?能不能在全量发布服务器前完成,而不是晚上这种模糊时间)
后台开发代表全部后台, 前台开发代表全部前台
- 后台有多个服务器,每个服务器不同的人负责,前台可能认为后台是一个整体,所以找你沟通的时候最好不要只考虑本服务器的事情。
- 我这里完成了 前台认为所有服务器完成了
- 对方代码还没合入的时候,你说对面完成了,结果实际没完成
不兼容变更时做好兜底
- 当时在众多人说自己无法进入游戏的时候,都没有去考虑补上兜底方案
- 因为当时考虑到这些都是异常情况,正常情况玩家地图上是不会有自己的主城,只要是正常环境就没有问题
- 然而遇到了Logic崩溃了,Logic没有记录选州成功,此时大地图已经选州了,玩家游戏直接卡死,之后才把兜底补上。这次就不是异常情况了,是正常情况下可能会出现的问题了。
- 重新编译的问题,没想到还学到了不少。
- tars文件重新生成的问题
- 先用md5比对写了一版
- 结果还是直接用CMake写最好,几行的事情
- CMake和Make的基本原理
- 依赖分析,编译加速?
- tars文件重新生成的问题
帮忙
帮忙处理东西的时候,一定要搞清楚,问清楚。自己也要看清楚,不能只是不带脑子的执行
不要将问题带到线上,这样处理起来非常的麻烦,而且会增加不靠谱
- 异常情况处理
- 兜底
该找运维的找运维(对应的时间给对应的人去做)
- 最后日志传输工作给了运维来搞
有的功能大地图并不知道有没有, 还是说下不知道之类的吧, 最后接下来了发现是别人的工作
技巧
CR发起前可以自己整一个临时CR看看代码
测试代码在最终CR的时候要及时去掉 使用TODO 名字方便检索
不建议手动操作自动化代码
- 流水线异常的时候手动操作了报错部分,然而报错导致后续操作也被中断了,但是忘记了操作后续部分,只操作了报错部分
- 流水线都现成的了 直接用吧 别手动操作了
自动化操作没有监管人
新版服务器未更新到目标服务器 出了N个乌龙BUG单
压测和扩容
- 压测
- 压测场景和实际场景不匹配
- 出现问题之后,都能发现问题,关键是出现问题前发现限制点
- 压测场景和实际场景不匹配
- 扩容
- 寻路服爆炸了,然而没有办法扩容,没有机器。
发现问题比解决问题更重要
- 性能优化感觉难点是发现性能问题, 包括编译加速. (20%的问题造成了80%的负面影响, 如果去处理另外80%的问题收益就很低)
指定时间点触发的循环定时器, 每轮都计算下时间相比固定时间的更加稳定
主城周围搜索物体, 采用涡旋状搜索, 类似蚊香
尽量统一函数对统一内容进行清除, 比如标志位, 这样方便发现错误清理的地方
测试东西或者搞新东西的时候, 注意不要影响到旧的东西, 该开测试空间的开测试空间
这次自动提单提了2K+, 如果不是提到了临时空间 估计直接爆炸了.
充电
- 输入
- 代码
- CR
- 方案拆解和评估
- KM文章
- 开源项目
123
- 有输入相比自己死磕能够成长的更快
- 看看其他人的方案拆解
- 不能同一帧将所有点位检查这种情况,才想到要延时进行刷新。
- 不能是单单的将需求点列出来,需要对应到具体的改动是啥,这样评估时间才准确。
- 注意下时间评估这里,目前我评估的时间还是非常的不准确的
- 看看其他人的cr,不然自己没有负责过的模块 是一点都不清楚
- 同时看了之后还有和其他人PK的机会
- 看看其他人的设计,学一学自己将来才可能遇到,不然都是在自己思维下兜圈子
- 看看别人的CR和方案,这里为什么这么设计,自己想的话如何设计,一下对比就出来了。进行后续沟通还能了解到更多。
- 看看其他人的方案拆解
- 之前看到帝国觉醒只是想到了战斗服需要在压力场景下减少发包
- 但是大地图是不是需要呢?完全没有考虑过,大地图是否需要
- 大地图实际是不需要的,至少目前的同步机制是够用的
- 战斗服可能是需要的,不过后面就没跟进了解了
- 但是大地图是不是需要呢?完全没有考虑过,大地图是否需要
- 千人测试的时候,重启城郊会导致战斗服也需要重启的问题
- 千人测试的时候,Logic崩溃导致事件完成了任务没有完成