代码荣辱观-以运用风格为荣,以随意编码为耻
编写代码的八荣八耻
1. 产品命名:以简单有趣为荣,以平庸难记为耻。
2. 单个函数:以短小精悍为荣,以冗长费神为耻。
3. 代码维护:以持续重构为荣,以停滞不前为耻。
4. 编程风格:以运用风格为荣,以随意编码为耻。
5. 程序设计:以开关上线为荣,以自信编码为耻。
6. 接口定义:以用户易用为荣,以复杂歧义为耻。
7. 断言分支:以实时报警为荣,以忽略分支为耻。
8. 监控报警:以定时调整为荣,以放弃维护为耻。
5Why分析
(一)
Q: 谁需要学习编写代码的八荣八耻?
A: 项目中的开发人员、项目经理、架构师
(二)
Q: 为什么学习编写代码的八荣八耻?
A: 可以作为实际代码编写和review(复查)的指导规范
(三)
Q: 什么人什么时候需要review代码?
A:
对开发人员来说,需要在时间允许的条件下定期的review自己和别人的代码,加深对项目的整体理解。对自己的成长做总结。如果过了一段时间,还看到自己之前的代码,觉得写的很好的话,就需要质疑自己的成长,更努力的学习了。
对于项目经理和架构师来说,鼓励所有上线的功能都每周抽出时间来做个组内review。或者定期抽取一些模块做review。鼓励大家重构代码。在review过程中,作为领导者需要对大家有输出,对代码怎么写是更好的有一些理论基础。这时候就需要使用编写代码的八荣八耻作为review的指导规范。
(四)
Q: 怎么用作review的指导规范?
A: 八荣八耻中不但介绍了每个条目的意义,而且有通俗易懂的代码实例便于和实际中的代码在头脑中做对比。文中明确的指出了哪些写法是鼓励的、哪些是不鼓励的,是基于什么理由不鼓励这样做。
(五)
Q: 编写代码的八荣八耻对于高可用有什么意义?
A: 我利用美团的内部运维平台对自己参与过的项目可用性做过统计。将影响可用性的case(具体事件)分成:开发因素和设计因素。开发因素包括系统bug、开发不规范、上线不规范、监控报警不及时(影响可用性的恢复时长)等由于具体开发者在设计阶段覆盖不到的阶段发生的。设计因素包括机器故障、网络中断、异常流量、中间件故障等可以通过设计做容灾的。结果95%以上的可用性问题都是开发因素造成的。编写代码的八荣八耻是对避免开发因素产生可用性问题的指导规范。
编程风格:以运用风格为荣,以随意编码为耻
引子
在工作中,经常发现有些程序员用面向对象的语言写出了面向过程的代码而自己并没有感觉到:
前面提到有个java软件工程师,叫Margaret。她对工作有三个要求:钱多、有趣、离家近。HR想针对这些要求和她具体沟通,问她最低标准是什么。每一项最低要求回复一个星级。
星级 |
钱多 |
有趣 |
离家近 |
|
☆ |
1 |
年薪10万 |
出差+旅游占工时1% |
40公里 |
☆☆ |
2 |
年薪20万 |
出差+旅游占工时10% |
20公里 |
☆☆☆ |
3 |
年薪50万 |
出差+旅游占工时20% |
10公里 |
☆☆☆☆ |
4 |
年薪100万 |
出差+旅游占工时50% |
2公里 |
☆☆☆☆☆ |
5 |
年薪500万 |
出差+旅游占工时80% |
1公里 |
Margaret在外地,所以用了一个常用的数据交换格式json给HR回复如下:
{"moreMoney”:4,"moreFun”:2,"closerToHome”:3}
拿到这个回复时面向过程的解析方式是这样写的:
Map json = (HashMap) JSONUtils.parse("{\"moreMoney\":4,\"moreFun\":2,\"closerToHome\":3}");
int moreMoney = (int)json.get("moreMoney");
int moreFun = (int)json.get("moreFun");
int closerToHome = (int)json.get("closerToHome");
接收方将接收到的数据转成了json,代码里一堆get完成了功能。为什么说这是面向过程的呢?map是一种数据结构,没有直接的业务意义。功能实现了,表达的意义却不清晰。
这段代码更好的一个实现方式是将接收的数据结构定义成一个对象,在java里可以使用jackson等工具直接将json转成有业务含义的对象。
ObjectMapper objectMapper = new ObjectMapper();
Requirement requirement = objectMapper.readValue("{\"moreMoney\":4,\"moreFun\":2,\"closerToHome\":3}",JavaSoftwareEngineerMargaretRequirement.class);
这样做,HR拿到的requirement不是一列列数字,需要自己对核对每一项都是什么意思。而是一个有完整语义的对象,利于理解。而以这种思路来进行编写的代码我经常称他们叫面向对象风格的代码。
WHY
来看一段写赤壁山旅行的文章:
今天有幸登上赤壁山,看到这山上的景物,不禁想起了当前战场上厮杀的场面。想起当年要不是周瑜运气好,大冬天刮起了东风,恐怕吴国就被曹操灭了。
再来看唐代诗人杜牧经过赤壁山这个著名的古战场,有感于三国时代的英雄成败而写下的《赤壁》:
折戟沉沙铁未销,自将磨洗认前朝。
东风不与周郎便,铜雀春深锁二乔。
前两句意思是在沙子底下找到一只断戟,磨洗之后发现“made in 赤壁”。读者读了这两句不禁会联想起当前战场上厮杀的场面吧。
后两句意思是要不是周瑜运气好,大冬天刮起了东风。那孙权的老婆大乔和周瑜的老婆小乔这两位绝世美女都要被曹操这个色老头关进铜雀台了。因为曹操久仰大小乔的美貌,提前为二人修筑铜雀台,作为打败吴国的战利品。
杜牧只字未提战场和如果没有东风的运气,将会亡国的下场。但是读者却能心领神会,印象深刻。这是因为杜牧采用了以小见大的风格手法。
代码与代码的区别如同文章与文章的区别。能否让读者以更短的时间、更轻松的读懂?代码是给人整体感还是恶心感?这些都决定了代码的可维护性。而它和系统可用性、稳定性的最直接关系在工作中非常常见:“爷爷的!这是谁写的代码这么烂?忍不了了,老子不干了。”而这个代码的作者之所以离职也是因为忍受不了自己的烂代码。频繁的人员更替,新接手人员要有学习的成本。成本就包括要踩坑来加深对系统的理解。
HOW
除了开头提到的面向对象的风格,编写java代码时下面三种风格也很常见。
1.fluent风格
fluent风格的代码常以Builder结尾。比如StringBuilder就是典型的fluent风格。定义一个人的对象,这个对象使用fluent风格代码这么写:
public class Person {
private String name;
private int armCount=2;//胳膊数默认为2
private int legCount=2;//腿数默认为2
public static Person builder() {
return new Person.Builder();
}
public Person setName(String name) {
this.name = name;
return this;
}
public Person armCount(int armCount) {
this.armCount = armCount;
return this;
}
public void legCount(int legCount) {
this.legCount = legCount;
}
}
如上,就是每次给对象赋属性的时候同时返回对象本身。这样调用的时候:
Person.builder().name("Jane").armCount(2).legCount(2);
这样写的好处是比每个属性都用一句set简洁。在属性多的时候,用构造函数。调用时容易表达不清楚属性的含义。方法名起到了解释的作用。现在流行的做法是代码即注释,注释不用在每个方法都写。这时候能表达自身意义的代码就更加重要。注意:我们也可以保留setXXX、getXXX的命名规范,因为jackson等序列化反序列化的组件会根据set、get方法对参数赋值,上面的明明风格在序列化时会有问题。
当然,这个类也可以直接用lombok注解得到。
@Data
@Buildr
public class Person {
private String name;
private int armCount=2;//胳膊数默认为2
private int legCount=2;//腿数默认为2
}
2.lambda函数式编程风格
lambda函数式编程比传统的命令式编程更加简洁。比如:现在有一群人。
List<Person> personList = Lists.newArrayList();
personList.add(Person.builder().name("Jane"));
personList.add(Person.builder().name("Joe").armCount(1));
personList.add(Person.builder().name("Stark").legCount(1));
要找出所有的残疾人:
List<Person> disabledPersonList = Lists.newArrayList();
for(Person person : personList) {
if(person.legCount()!=2 || person.armCount()!=2) {
disabledPersonList.add(person);
}
}
或者使用lambda函数式编程:
List<Person> disabledPersonList = personList.stream().filter(person -> person.legCount()!=2 || person.armCount()!=2).collect(Collectors.toList());
3.设计模式风格
1995年,GoF(Gang of Four,四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,共收录了23中设计模式,人称“GoF设计模式”。这23种设计模式的本质是面向对象设计原则的实际运用,是一种最佳实践。
在各种java源码中,经常看到以设计模式命名的类名和方法名。在我们日常编码中,设计模式也非常实用。设计模式风格的例子请参考:平时代码中用不到设计模式?Are you kidding me?
总结
写有技术追求的代码
相关阅读
编写代码的「八荣八耻」- 以用户易用为荣,以复杂歧义为耻
编写代码的「八荣八耻」- 以开关上线为荣,以自信编码为耻
编写代码的「八荣八耻」(上篇)
转载于:https://www.cnblogs.com/xiexj/p/11075551.html
代码荣辱观-以运用风格为荣,以随意编码为耻相关推荐
- SetWindowLong代码设置窗体borderStyle风格 TOOLWINDOW
//SetWindowLong代码设置窗体borderStyle风格 TOOLWINDOW SetWindowLong(self.Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW ...
- html网站一行代码改变灰黑色哀悼日风格
html网站一行代码改变灰黑色哀悼日风格 html { filter: grayscale(100%); -webkit-filter: grayscale(100%); ...
- [转载]Object-C 声明属性为什么用下划线,代码规范和编程风格_s芃成_新浪博客...
原文地址:Object-C 声明属性为什么用下划线,代码规范和编程风格 作者:贞娃儿 在阅读和书写关于iPhone编程的代码的时候,发现有很多这样的情况: 看到很多源代码里面,使用前面带下划线变量,然 ...
- python说句心里话e代码_万恶之源 - Python运算符与编码
格式化输出 现在有个需要我们录入我们身边好友的信息,格式如下: ------------ info of Alex Li ---------- Name : Alex Li Age : 22 job ...
- 修改IDEA中Java代码的默认注释风格
如果什么都不设置,对代码按Ctrl + / 生成的注释比较难看,如下: 斜杠顶格,中间有很大的空格,可以按如下设置: 1和2的对勾去掉,至于3,可以打上也可以不打上,选上3,生成的注释会和代码之间加一 ...
- 给wordpress代码块添加MAC风格
下载Pure-Highlightjs.zip安装插件 在设置那边点击Pure Highlightjs进入选择主题dark然后保存 然后写文章添加文本-经典然后点击插入代码 print("he ...
- pycharm代码注释支持google风格
在设置中找到 Tools > Python Integrated Tools 选择Docstring format为Google
- php编码代码工具,php制作unicode解码工具(unicode编码转换器)代码分享
代码如下: function unicode_encode($name) { $name = iconv('UTF-8', 'UCS-2', $name); $len = strlen($name); ...
- php编码代码工具,php制作unicode解码工具(unicode编码转换器)代码分享_PHP教程
复制代码 代码如下: //将UNICODE编码后的内容进行解码 function unicode_decode($name) { //转换编码,将Unicode编码转换成可以浏览的utf-8编码 $p ...
最新文章
- Ubuntu14.04更新源
- ilpimage to bitmap
- apache常用的配置指令:ServerRoot
- java反码_Java:二进制(原码、反码、补码)与位运算
- 昆虫繁殖(信息学奥赛一本通-T1312)
- [bzoj1700]: [Usaco2007 Jan]Problem Solving 解题
- 怎么测试本地网页在不同分辨率下电脑显示效果_4K商用超值利器 飞利浦272P7VPTKEB显示器评测...
- GO超详细基础语法黑点
- jsZip上传,jsZip压缩文件并上传到服务器
- 报错:【pip Error】ERROR: Cannot determine archive format of C:\Users\YDD\AppData\Local\Temp\pip-req-buil
- MongoDB——聚合管道之$group操作
- java的动物打一生肖,吉祥的动物是什么生肖 指哪个生肖 打一生肖
- 透明与不透明物体共存
- 2017湖湘杯Writeup
- 单片机(3)跑马灯,按钮控制的跑马灯(2种编程)
- 操作系统中的概念详解
- 如何引流中老年粉?中老年人群怎么引流?中老年粉如何变现?
- 0基础学python培训班_[长文] 学Python不用培训班,一篇文章带你入门
- may have been in progress in another thread when fork() was called.
- HTML基础学习记录
热门文章
- l3fwd 是什么_服务器DPDK l3fwd性能测试
- php 变成 25,2020-09-25 PHP变量介绍
- 简易嵌入式管理平台 C 实现
- C 回顾 volatile 和 register 修饰符
- 打开git命令窗口_用动图的形式打开 10 大 Git 命令?
- jsp中如何运行java_从上帝视角看Java如何运行
- matlab--常微分方程的数值解(ODE-s)
- android高德地图显示多点标记,高德地图多点标记自定义地图
- php controller 间调用,php – 在CodeIgniter中的另一个Controller中调用Controller函数
- 初识Tcl(一):Tcl 命令