编写高质量代码 代码质量评判标准 面向对象 设计原则 规范与重构 以上脑图来自极客时间
关于我 我的博客:https://yezihack.github.io
欢迎关注我的微信公众号【空树之空】,共同学习,一起进步~基于 linxu centos 7
查看防火墙 iptables 命令大小写敏感
iptables -nL 添加一条规则 添加一条开放 9090 端口的规则
# 插入最前面 iptables -I INPUT -p tcp --dport 9090 -j ACCEPT # 追加最后面 iptables -A INPUT -p tcp --dport 9090 -j ACCEPT # 插入某指定位置 iptables -I INPUT 3 -p tcp --dport 9090 -j ACCEPT 关于我 我的博客:https://yezihack.github.io
欢迎关注我的微信公众号【空树之空】,共同学习,一起进步~为什么要编程规范 构建一个大型项目,往往是很多人一起参与,堆砌的代码行数都是成千上万行。如何保证代码的健壮性?编程规范必不可少。
命名 命名能力体现了一个程序员的基本编程素养。
让你的名字承载更多的信息,把信息装到名字里。
命名的关键是能准确达意,对于不同作用域的命名,我们可以适当地选择不同的长度。 利用上下文简化命名。 命名要可读,可搜索。如 get, select, set等等。 用具体的名字代替抽象的名字。 检测服务是否可以监听某个给定的TCP/IP端口。 ServerCanStart() 换成 CanListenOnPort() tip: 可以到 github 上找一些相关的项目,看看别人是如何命名的。
注释 命名很重要,注释跟命名同等重要。注释就是对代码的有力解释。
注释的内容主要包括三个方面:做什么(what),为什么(why),怎么做(how)。
为什么要写注释呢?
注释比代码承载的信息更多。 注释起到总结性作用,文档的作用。通过注释大概了解代码的实现思路,阅读起来更加容易。 一些总结性注释能让代码结构更清晰。 对于类和函数一定要写注释,尽量写全面,详细。对于函数内部,可以少写一些。
代码行数 函数的行数最好不要超过一屏幕。大约在50~80行。
写长函数时,需要拆分主干逻辑和次要逻辑。抽取公共且独立的处理逻辑。
一行代码 一行代码最好不要超过IDE显示的宽度。大约在80~100个字符。
如果超出行数导致换行会影响代码的整洁,不利用阅读。
空行分割单元块 对于那些影响逻辑的长函数,无法拆分的长函数,为了让逻辑更加清晰,可以使用空行来分割各个代码块。
代码缩进 Go 语言,使用 gofmt 或 goimports 自动缩进。
目前有使用两格缩进和四格缩进。主要看你使用的语言业内,主流如何使用。
如 php 用四格缩进,JAVA 用两格缩进。
大括号是否另起一行 Go 语言强制使用与函数名同一行。
目前有使用与函数名同一行或单独占一行。
主要看你使用的语言业内,主流如何使用。
如 php 喜欢使用单独占一行。JAVA 喜欢使用与函数名同一行。
排列顺序 Go 语言,使用 gofmt 或 goimports 自动排序。
依赖类,按照字母序从小到大排列。 在类中,成员变量排在函数前面。 在函数中,成员排在最上面。 作用域从大到小排列。public > protected > private。 把代码分割成更小的单元块 为什么要分割更小的单元块:解耦为何如此重要 解耦是保证代码的松耦合,高内聚。防止代码质量腐化到不可救药地步的有效手段。
代码”高内聚,松耦合“也就意味着,代码结构清晰,分层和模块化合理,依赖关系简单,模块或类之间的耦合小,代码质量自然就高。
代码是否需要解耦 判断代码是否符合”高内聚,松耦合”,可以从如下方法判断。
看修改代码会不会牵一发而动全身。 把模块与模块之间,类与类之间的依赖关系画出来。根据依赖关系图的复杂性判断是否需要解耦重构。 如何给代码解耦 1.封装与抽象 封装和抽象可以有效地隐藏实现的复杂性,隔离实现的易变性,给依赖的模块提供稳定且易用的抽象接口。
2.中间层 引入中间层能简化模块或类之间的依赖关系。
我们在进行重构的时候,引入中间层可以起到过渡的作用,能够让开发和重构同步进行,不互相干扰。
分四个阶段完成接口的修改:
引入一个中间层,包裹老的接口,提供新的接口定义。 新开发的代码依赖中间层提供的新接口。 将依赖老接口的代码改为调用新接口。 确保所有代码都调用新接口之后,删除掉老的接口。 3.模块化 模块化是构建复杂系统常用的手段。
将大而复杂的系统拆分成各个独立的模块,让不同人负责不同的模块。
每个模块之间耦合很小,每个小团队聚集于一个独立的高内聚模块来开发。
最终像搭积木一样将各个模块组装起来,构建成一个超级复杂的系统。
4.设计思想和原则 单一职责原则 基于接口而非实现编程 依赖注入 多用组合少用继承 迪米特法则 关于我 我的博客:https://yezihack.github.io
欢迎关注我的微信公众号【空树之空】,共同学习,一起进步~什么是单元测试 单元测试是代码层面的测试,由研发自己来编写,用于测试“自己”编写的代码逻辑的正确性。
单元测试主要测试范围:
类 函数 单元测试有别于集成测试。
集成测试主要测试范围:
模块 系统 功能块 tip: 单元测试是粒度小的测试。考验程序员思维的缜密程度。
为什么要写单元测试 单元测试能有效地帮你发现代码中的BUG 写代码的最高境界就是 bug free 的状态。 避免低级 bug 的出现。 保证每一行代码运行良好,逻辑正确。 写单元测试能帮你发现代码设计上的问题 如果我很难为其编写单元测试,或者单元测试写起来很吃力,那往往就意味着代码设计得不够合理。 如没有使用依赖注入,大量使用静态函数,全局变量,代码调试耦合等情况。 单元测试是对集成测试的有力补充 集成测试无法覆盖得很全面,复杂系统往往很多模块。需要单元测试加持。 如果我们能保证每个类,每个函数能按照我们的预期来执行,底层bug少了。组装起来的整个系统,bug也相应减少。 写单元测试的过程本身就是代码重构的过程 单元测试实际上就是落地执行持续重构的一个有效途径。 编写单元测试就相当于对代码的一次自我Code Review。 阅读单元测试能帮助你快速熟悉代码 单元测试用例就是用户用例,反映了代码的功能和如何使用。 单元测试是TDD可落地执行的改进方案 单元测试正好是对TDD测试驱动开发的一种改进方案。 如何编写单元测试 每个语言都有不同的写法。如 Golang 只需要以下划线加 test 命名,函数以 Test 开头就是单元测试。
func TestFunc(t *testing.T) { // todo } 还可以使用第三方提供的单元测试框架。如 GoConvey 。
写单元测试真的是件很耗时的事情。单元测试代码量一般是被测代码本身的1~2倍 单元测试不会在生产上运行,而且每个类的测试代码比较独立,基本不互相依赖。 单元测试覆盖率做到 60 ~ 70% 之间算合格。GoConvey 也有提供覆盖率的报告。 单元测试不依赖被测试函数的具体实现逻辑,它只关心被测函数实现了什么功能。 tip: 对于函数写不写单元测试,工程师要有足够的主人翁意识(ownership)。 也是拉开与其它人差距的“杀手锏“。
测试不友好的代码 代码中包含未决行为逻辑 滥用可变全局变量 滥用静态方法 使用复杂的继承关系 高度耦合的代码 关于我 我的博客:https://yezihack.纲要 3W1H
why 为什么重构 what 重构什么 when 什么时候重构 how 如何重构 重构的定义 软件设计大师 Martin Fowler 这样定义重构:
“重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。”
重构的目的:为什么要重构 (why) 首先,重构是时刻保证代码质量的一个极其有效的手段,不至于让代码腐化到无可救药的地步。
其次,优秀的代码或架构不是一开始就能完全设计好的。是一个迭代,不断演进的过程。
最后,重构是避免过度设计的有效手段。
tip: 初级工程师在维护代码,高级工程师在设计代码,资深工程师在重构代码。
重构的对象:到底重构什么(what) 根据重构的规模,我们可以笼统地分为大规模高层次重构(大重构)和小规模低层次重构(小重构)。
大重构:
重构的范围 系统 模块 代码结构 类与类之间的关系 重构手段 分层 模块化 解耦 抽象可复用组件 重构工具 设计思想 设计原则 设计模式 小重构:
重构范围 类 函数 变量 重构手段 规范命名 规范注释 消除超大类或函数 提取重复代码 tip:我们重构的对象是软件重个生命周期。
重构的时机:什么时候重构(when) 重构可以是一刀切,也可以分阶段。我们提倡的策略是持续重构。
把重构作为我们开发的一部分,见到不符合编码规范,不好的设计,超长函数都可以随时重构一下。成为一种开发习惯,对项目对自己都会很有好处。
tip: 持续重构意识很重要
重构的方法:又该如何重构(how) 对于大重构难度比较大,需要有组织,有计划地进行,分阶段地小步快跑,时刻让代码处于一个可运行的状态。
对于小重构难度相对小,因为影响范围小,改动耗时短,所以只要你愿意并且有时间,随时随地都可以重构。
tip: 不管大还是小重构,都要保证代码可运行,逻辑正确的状态。
关于我 我的博客:https://yezihack.github.io
欢迎关注我的微信公众号【空树之空】,共同学习,一起进步~《小狗钱钱》是一本让孩子和家长共同成长的金钱童话,非常有趣,故事性很强,也很容易读。
本书的副标题:从此拥有财富,开启富足快乐的人生。
大纲 正视金钱 我们总是有种这样的感觉,我们与财富无关,既然这么想,内心就会对金钱有抵触,觉得自己不可能会变得富有。
如果我们正视金钱,认为追求生活无忧本就是我们与生俱来的权利。有了足够的金钱,我们能更有尊严地生活,更好地对待自己和他人。如果你听说金钱是万恶之源的话,这是一个大错特错的说法。金钱本身是中性的,主要是看金钱在谁的手里。
我们要正视金钱,什么都不能阻挡你享有与生俱来的权利,让自己变得富裕。
一句话: 追求金钱是我们与生惧来的权利。
明确方向 要想成事,我们必须有目标,否则就是无头苍蝇。而且目标越明确,越容易实现。
老子说:天下难事,必作于易。天下大事,必做于细。
首先写出10个你想变得富有的理由,即十个愿望清单。然后仔细看看这张清单,选出最重要的三个愿望。
人往往想要的太多,能做的太少。三个愿望是让你专注,聚集。
我们必须明确自己内心的愿望,知道它是什么,才有可能得到它。
不是写完就完事了,而是每天要读一读你的清单,你的愿望,这样才能把它们真正放在心上,然后你就要开始密切关注和寻找帮助你实现愿望的机会。
一句话:专注自己的目标方向
梦想相册 明确了自己的愿望,然后就是制作相册。因为图片比文字更具体,这样会让你想象你实现你的梦想是多么开心的事,多么有成就的事,值得为之奋斗。
这本书已经出版20年啦,如今我们可以借用自己手机相册,制作同样效果的相册。
书中提到一些小技巧
做某事,我们不要说尝试一下,而是直接去做 。因为“尝试”只不过是为失败提前找借口,为自己找退路。 学习新的思想,新的观念。如果一个人总是用同样的方式思考,他永远只能得出同样的结论。 精力集中在哪儿,哪儿就会开花结果。 只有去寻找,才能发现。只有拥有强烈的渴望,才会去寻找。而只有不断地去想象,才会拥有强烈的渴望。 一句话: 智慧的海鸥:在你展翅飞翔之前,你就必须相信自己一定能到达目的地。
梦想储蓄罐 为你想要实现的愿望准备一个梦想储蓄罐,在梦想储蓄罐上写上你的愿望,把照片贴在储蓄罐上。每月向储蓄罐存入钱。这种方法其实就是视觉法。
当然我们可以使用手机APP来代替。
这个方法,更加具象,更加立体,时刻提醒自己,不要忘记自己的梦想。
一句话:梦想储蓄罐是让自己紧盯目标,经常提醒自己。
成功日记 成功日记主要是建立自信,因为自信决定着你是否敢去做某事。也是实现梦想的基石。
坚持写成功日记,就会不断更深入地思考自己,思考世界,思考成功的规律。
现在行动吧。每天记录5条成果,任何小事都可以。
那如何才能让自己有更多的成功的事记录呢?答案就是:做自己擅长的事。
要把精力始终集中在你知道的,能做到的和拥有的东西上。
更直白的说就是要始终去帮别人解决问题,才能挣到钱。
那些不知道,不擅长的事,交给别人去做。
一句话: 成功日记是让你发现更多挣钱的机会,专注自己能做好的事。
致富经 没有现成的发财路等着我们,但随时随地都能挣到钱,你只要到处看看就能发现机会。
先从你自己喜欢做的事情上思考,想想如何通过这些事来挣到钱。当然想法别太多,而要集中精力做一件事,会出现神奇的作用。
一句话:不要总是想那些做不成的事情,而是要多想想什么能做成。
做重要的事 人们总是十万火急的去做某事,却没有时间考虑真正重要的问题。这是一种悲剧。
只有你的梦想清单上的事才是重要的事,千万别忘记啦。
生活虽不易,但三件重要的事必须做:
即使遇到困难和问题,我们也得实施自己的计划。 只有在出现真正问题时,谁强谁弱才能见分晓。 当一切进展顺利,你也应当坚持做下去。 高兴过头,把自己的计划抛之脑后。实属愚蠢。 72法则。 决定做一件事时,必须在72小时之内开始行动,否则就很有可能再也不会做了。 一句话: 幸运只不过是充分准备加上努力工作的结果。决定做不做一件事,72法则见分晓
摆脱债务 如果你遇到债务危机的话,尝试以下方法。
注销所有的信用卡 每个月尽可以少地偿还贷款 除了生活支出,剩下的存起来 这真的有必要吗? 这句话贴在你的手机上,每次消费时问一问自己。 一句话: 绝不去借债,应该学会如何赚钱,如何理财,做金钱的主人,而不是奴隶。
金蛋的鹅 我们应该养一只会下金蛋的鹅,为我们下更多更多的金蛋。针对非业务通用框架开发,需要做到尽量通用,适合百变的场景,做到良好的扩展。
需求分析 功能性需求分析 满足使用者的需求,尽量通用。 借助设计产品线框图工具来罗列需求点。 把最终的数据显示样式画出来,一目了然。 非功能性需求分析 一个通用系统,需要做好良好的兼容性。
易用性
框架是否易集成,易插拔,跟业务代码是否松耦合,提供的接口是否够灵活。 性能
当集成到业务系统的框架里,不会影响业务性能。 做到低延时,内存消耗低。 扩展性
做到不修改框架源码进行扩展。 做到给框架开发插件一样扩展。 容错性
非常重要,不能因为框架本身异常导致接口请求错误。
对外暴露的接口抛出的所有运行时,非运行时异常都要进行捕获处理。
通用性
能够灵活应用到各种场景中。 多思考一下,除了当前需求场景,还适合其它哪些场景中。 框架设计 借鉴TDD(测试驱动开发)和 Prototype (最小原型)的思想
先聚集一个简单的应用场景。 设计实现一个简单的原型。 尽管功能不完善,但它能够看得见,摸得着,比较具体,不抽象,能够很有效地帮助自己缕清更复杂的设计思路,是迭代设计的基础。 在原型系统的代码实现中,我们可以把所有代码都塞到一个类中,暂时不用考虑任何代码质量,线程安全,性能,扩展性等等问题,怎么简单怎么来就行。 最小原型的代码实现虽然简陋,但它帮我们将思路理顺很多。 我们现在就基于它做最终的框架设计。 关于我 我的博客:https://yezihack.github.io
欢迎关注我的微信公众号【空树之空】,共同学习,一起进步~纲要 完整的系统流程包括:
前期的需求沟通分析 中期的代码设计实现 后期的系统上线维护 需求分析 做为技术人员不仅仅是等着产品设计文档,线框图,照着实现就可以。应该参与到产品设计中。具有产品思维,前期应该去市场上调研,参考,借鉴已成熟的产品。充分了解自己公司的产品后,然后再将其糅合到自己的产品中,并做适当的微创新。
调研产品 充分了解自家产品 微创新 tip: 技术人也要有一些产品思维
系统设计 合理地将功能划分到不同模块 合理地划分代码可以实现代码的高内聚,低耦合,类与类之间的交互简单清晰,代码整体结构一目了然。
设计模块与模块之间的交互关系
同步接口调用 适合上下层之间的关系 异步接口调用 适合同级间的关系 设计模块的接口,数据库,业务模型
代码实现 前提 数据库和接口设计非常重要,一旦设计好并投入使用之后,这两部门都不能轻易改动。
改动数据库表结构,需要涉及数据的迁移和适配。 改动接口,需要推动接口的使用都作相应的代码修改。 一定要多花点心思和时间,切不可过于随意。
业务逻辑代码侧重内部实现,不涉及外部依赖的接口,也不包括持久化的数据,所以对改动的容忍性更大。
MVC Controller 层负责接口暴露 Repository 层负责数据读写 Service 层负责核心业务逻辑 两种开发模式
充血 DDD 开发模式 贫血 OOP 开发模式 为什么使用MVC开发 分层能起到代码复用的作用 同一个 Repository 可能会被多个 Service 来调用。 同一个 Service 可能会被多个 Controller 调用。 分层能起到隔离变化的作用 Repository 层封装了对数据库访问的操作,提供了抽象的数据访问接口。 基于接口而非实现编程的设计思想,Service 层使用 Repository 层提供的接口,并不关心底层依赖是哪种具体的数据库。 如果需要替换不同的数据库,只需要修改 Repository 层,Service 层的代码完全不需要修改。 三层的稳定程序也不同。越底层越应该稳定。 分层能起到隔离关注点的作用 Repository 层只关注数据的读写。 Service 层只关注业务逻辑,不关注数据的来源。 Controller 层只关注与外界打交道,数据校验,封装,格式转换,并不关心业务逻辑。 三层之间的关注点不同,分层之后,职责分明,更加符合单一职责原则,代码的内聚性更好。 分层能提高代码可测试性 使用依赖注入方式,采用 mock 数据替代真实数据。 分层能应对系统的复杂性 水平方向基于业务来做拆分,就是模块化。 垂直方向基于流程来做拆分,就是分层。 tip: 对于工作不满意,应该我花点时间在技术上;对于当前工作很满意则多花时间在业务上。设置GIT代理 // 查看当前代理设置 git config --global http.proxy git config --global https.proxy // 设置当前代理为 http://127.0.0.1:1080 或 socket5://127.0.0.1:1080 git config --global http.proxy 'http://127.0.0.1:1080' git config --global https.proxy 'http://127.0.0.1:1080' git config --global http.proxy 'socks5://127.0.0.1:1080' git config --global https.proxy 'socks5://127.0.0.1:1080' // 删除 proxy git config --global --unset http.proxy git config --global --unset https.proxy