北京尚学堂|程序员的智慧

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

版权声明:本文为北京尚学堂原创文章,未经允许不得转载。

 

编程是一种创造性的工作,是一门艺术。精通任何一门艺术,都需要很多的练习和领悟,所以这里提出的“智慧”,并不是号称一天瘦十斤的减肥药,它并不能代替你自己的勤奋。然而由于软件行业喜欢标新立异,喜欢把简单的事情搞复杂,我希望这些文字能给迷惑中的人们指出一些正确的方向,让他们少走一些弯路,基本做到一分耕耘一分收获。

反复推敲代码

既然“天才是百分之一的灵感,百分之九十九的汗水”,那我先来谈谈这汗水的部分吧。有人问我,提高编程水平最有效的办法是什么?我想了很久,终于发现最有效的办法,其实是反反复复地修改和推敲代码。

在IU的时候,由于Dan Friedman的严格教导,我们以写出冗长复杂的代码为耻。如果你代码多写了几行,这老顽童就会大笑,说:“当年我解决这个问题,只写了5行代码,你回去再想想吧……” 当然,有时候他只是夸张一下,故意刺激你的,其实没有人能只用5行代码完成。然而这种提炼代码,减少冗余的习惯,却由此深入了我的骨髓。

有些人喜欢炫耀自己写了多少多少万行的代码,仿佛代码的数量是衡量编程水平的标准。然而,如果你总是匆匆写出代码,却从来不回头去推敲,修改和提炼,其实是不可能提高编程水平的。你会制造出越来越多平庸甚至糟糕的代码。在这种意义上,很多人所谓的“工作经验”,跟他代码的质量,其实不一定成正比。如果有几十年的工作经验,却从来不回头去提炼和反思自己的代码,那么他也许还不如一个只有一两年经验,却喜欢反复推敲,仔细领悟的人。

有位文豪说得好:“看一个作家的水平,不是看他发表了多少文字,而要看他的废纸篓里扔掉了多少。” 我觉得同样的理论适用于编程。好的程序员,他们删掉的代码,比留下来的还要多很多。如果你看见一个人写了很多代码,却没有删掉多少,那他的代码一定有很多垃圾。

就像文学作品一样,代码是不可能一蹴而就的。灵感似乎总是零零星星,陆陆续续到来的。任何人都不可能一笔呵成,就算再厉害的程序员,也需要经过一段时间,才能发现最简单优雅的写法。有时候你反复提炼一段代码,觉得到了顶峰,没法再改进了,可是过了几个月再回头来看,又发现好多可以改进和简化的地方。这跟写文章一模一样,回头看几个月或者几年前写的东西,你总能发现一些改进。

所以如果反复提炼代码已经不再有进展,那么你可以暂时把它放下。过几个星期或者几个月再回头来看,也许就有焕然一新的灵感。这样反反复复很多次之后,你就积累起了灵感和智慧,从而能够在遇到新问题的时候直接朝正确,或者接近正确的方向前进。

写优雅的代码

人们都讨厌“面条代码”(spaghetti code),因为它就像面条一样绕来绕去,没法理清头绪。那么优雅的代码一般是什么形状的呢?经过多年的观察,我发现优雅的代码,在形状上有一些明显的特征。

如果我们忽略具体的内容,从大体结构上来看,优雅的代码看起来就像是一些整整齐齐,套在一起的盒子。如果跟整理房间做一个类比,就很容易理解。如果你把所有物品都丢在一个很大的抽屉里,那么它们就会全都混在一起。你就很难整理,很难迅速的找到需要的东西。但是如果你在抽屉里再放几个小盒子,把物品分门别类放进去,那么它们就不会到处乱跑,你就可以比较容易的找到和管理它们。

优雅的代码的另一个特征是,它的逻辑大体上看起来,是枝丫分明的树状结构(tree)。这是因为程序所做的几乎一切事情,都是信息的传递和分支。你可以把代码看成是一个电路,电流经过导线,分流或者汇合。如果你是这样思考的,你的代码里就会比较少出现只有一个分支的if语句,它看起来就会像这个样子:

if (...) {

if (...) {

...

} else {

...

}

} else if (...) {

...

} else {

...

}

注意到了吗?在我的代码里面,if语句几乎总是有两个分支。它们有可能嵌套,有多层的缩进,而且else分支里面有可能出现少量重复的代码。然而这样的结构,逻辑却非常严密和清晰。在后面我会告诉你为什么if语句最好有两个分支。

写模块化的代码

有些人吵着闹着要让程序“模块化”,结果他们的做法是把代码分部到多个文件和目录里面,然后把这些目录或者文件叫做“module”。他们甚至把这些目录分放在不同的VCS repo里面。结果这样的作法并没有带来合作的流畅,而是带来了许多的麻烦。这是因为他们其实并不理解什么叫做“模块”,肤浅的把代码切割开来,分放在不同的位置,其实非但不能达到模块化的目的,而且制造了不必要的麻烦。

真正的模块化,并不是文本意义上的,而是逻辑意义上的。一个模块应该像一个电路芯片,它有定义良好的输入和输出。实际上一种很好的模块化方法早已经存在,它的名字叫做“函数”。每一个函数都有明确的输入(参数)和输出(返回值),同一个文件里可以包含多个函数,所以你其实根本不需要把代码分开在多个文件或者目录里面,同样可以完成代码的模块化。我可以把代码全都写在同一个文件里,却仍然是非常模块化的代码。

想要达到很好的模块化,你需要做到以下几点:

- 避免写太长的函数。如果发现函数太大了,就应该把它拆分成几个更小的。通常我写的函数长度都不超过40行。对比一下,一般笔记本电脑屏幕所能容纳的代码行数是50行。我可以一目了然的看见一个40行的函数,而不需要滚屏。只有40行而不是50行的原因是,我的眼球不转的话,最大的视角只看得到40行代码。

如果我看代码不转眼球的话,我就能把整片代码完整的映射到我的视觉神经里,这样就算忽然闭上眼睛,我也能看得见这段代码。我发现闭上眼睛的时候,大脑能够更加有效地处理代码,你能想象这段代码可以变成什么其它的形状。40行并不是一个很大的限制,因为函数里面比较复杂的部分,往往早就被我提取出去,做成了更小的函数,然后从原来的函数里面调用。

- 制造小的工具函数。如果你仔细观察代码,就会发现其实里面有很多的重复。这些常用的代码,不管它有多短,提取出去做成函数,都可能是会有好处的。有些帮助函数也许就只有两行,然而它们却能大大简化主要函数里面的逻辑。

有些人不喜欢使用小的函数,因为他们想避免函数调用的开销,结果他们写出几百行之大的函数。这是一种过时的观念。现代的编译器都能自动的把小的函数内联(inline)到调用它的地方,所以根本不产生函数调用,也就不会产生任何多余的开销。

写可读的代码

有些人以为写很多注释就可以让代码更加可读,然而却发现事与愿违。注释不但没能让代码变得可读,反而由于大量的注释充斥在代码中间,让程序变得障眼难读。而且代码的逻辑一旦修改,就会有很多的注释变得过时,需要更新。修改注释是相当大的负担,所以大量的注释,反而成为了妨碍改进代码的绊脚石。

实际上,真正优雅可读的代码,是几乎不需要注释的。如果你发现需要写很多注释,那么你的代码肯定是含混晦涩,逻辑不清晰的。其实,程序语言相比自然语言,是更加强大而严谨的,它其实具有自然语言最主要的元素:主语,谓语,宾语,名词,动词,如果,那么,否则,是,不是,…… 所以如果你充分利用了程序语言的表达能力,你完全可以用程序本身来表达它到底在干什么,而不需要自然语言的辅助。

有少数的时候,你也许会为了绕过其他一些代码的设计问题,采用一些违反直觉的作法。这时候你可以使用很短注释,说明为什么要写成那奇怪的样子。这样的情况应该少出现,否则这意味着整个代码的设计都有问题。

写简单的代码

程序语言都喜欢标新立异,提供这样那样的“特性”,然而有些特性其实并不是什么好东西。很多特性都经不起时间的考验,最后带来的麻烦,比解决的问题还多。很多人盲目的追求“短小”和“精悍”,或者为了显示自己头脑聪明,学得快,所以喜欢利用语言里的一些特殊构造,写出过于“聪明”,难以理解的代码。

并不是语言提供什么,你就一定要把它用上的。实际上你只需要其中很小的一部分功能,就能写出优秀的代码。我一向反对“充分利用”程序语言里的所有特性。实际上,我心目中有一套最好的构造。不管语言提供了多么“神奇”的,“新”的特性,我基本都只用经过千锤百炼,我觉得值得信奈的那一套。

现在针对一些有问题的语言特性,我介绍一些我自己使用的代码规范,并且讲解一下为什么它们能让代码更简单。

- 避免使用自增减表达式(i++,++i,i--,--i)。这种自增减操作表达式其实是历史遗留的设计失误。它们含义蹊跷,非常容易弄错。它们把读和写这两种完全不同的操作,混淆缠绕在一起,把语义搞得乌七八糟。含有它们的表达式,结果可能取决于求值顺序,所以它可能在某种编译器下能正确运行,换一个编译器就出现离奇的错误。

其实这两个表达式完全可以分解成两步,把读和写分开:一步更新i的值,另外一步使用i的值。比如,如果你想写foo(i++),你完全可以把它拆成int t = i; i += 1; foo(t);。如果你想写foo(++i),可以拆成i += 1; foo(i); 拆开之后的代码,含义完全一致,却清晰很多。到底更新是在取值之前还是之后,一目了然。

- 有人也许以为i++或者++i的效率比拆开之后要高,这只是一种错觉。这些代码经过基本的编译器优化之后,生成的机器代码是完全没有区别的。自增减表达式只有在两种情况下才可以安全的使用。一种是在for循环的update部分,比如for(int i = 0; i < 5; i++)。另一种情况是写成单独的一行,比如i++;。这两种情况是完全没有歧义的。你需要避免其它的情况,比如用在复杂的表达式里面,比如foo(i++),foo(++i) + foo(i),…… 没有人应该知道,或者去追究这些是什么意思。

- 永远不要省略花括号。很多语言允许你在某种情况下省略掉花括号,比如C,Java都允许你在if语句里面只有一句话的时候省略掉花括号:

if (...)

action1();

- 避免使用continue和break。循环语句(for,while)里面出现return是没问题的,然而如果你使用了continue或者break,就会让循环的逻辑和终止条件变得复杂,难以确保正确。

出现continue或者break的原因,往往是对循环的逻辑没有想清楚。如果你考虑周全了,应该是几乎不需要continue或者break的。如果你的循环里出现了continue或者break,你就应该考虑改写这个循环。

另外一种过度工程的来源,是过度的关心“代码重用”。很多人“可用”的代码还没写出来呢,就在关心“重用”。为了让代码可以重用,最后被自己搞出来的各种框架捆住手脚,最后连可用的代码就没写好。如果可用的代码都写不好,又何谈重用呢?很多一开头就考虑太多重用的工程,到后来被人完全抛弃,没人用了,因为别人发现这些代码太难懂了,自己从头开始写一个,反而省好多事。

过度地关心“测试”,也会引起过度工程。有些人为了测试,把本来很简单的代码改成“方便测试”的形式,结果引入很多复杂性,以至于本来一下就能写对的代码,最后复杂不堪,出现很多bug。

世界上有两种“没有bug”的代码。一种是“没有明显的bug的代码”,另一种是“明显没有bug的代码”。第一种情况,由于代码复杂不堪,加上很多测试,各种coverage,貌似测试都通过了,所以就认为代码是正确的。第二种情况,由于代码简单直接,就算没写很多测试,你一眼看去就知道它不可能有bug。你喜欢哪一种“没有bug”的代码呢?

根据这些,我总结出来的防止过度工程的原则如下:

- 先把眼前的问题解决掉,解决好,再考虑将来的扩展问题。

- 先写出可用的代码,反复推敲,再考虑是否需要重用的问题。

- 先写出可用,简单,明显没有bug的代码,再考虑测试的问题。​

更多Java培训,Java视频,Java教程尽在北京尚学堂,关注北京尚学堂官方微信,获得一手Java最新知识。

更多猛料!欢迎扫描上方二维码关注北京尚学堂官方微信公众号(资料领取验证消息:156)

本文作者北京尚学堂原创。如需转载请联系作者授权,未经授权,转载必究。

 

转载于:https://my.oschina.net/u/2947706/blog/790346

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/397363.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

翼城中学2021高考成绩查询入口,2021年临汾中考分数线查询(4)

临汾2021年中考分数线查询 2021临汾中考录取分数线 19年临汾中考各校录取分数线 临汾各高中录取分数线 临汾2021中考录取线查询 中考信息网提供2021临汾中考分数线查询信息。临汾中考录取分数线预计7月初公布&#xff0c;届时考生可登陆临汾招生考试网官网查看分数线情况。2…

配置Tomcat使用HTTP/2

转自&#xff1a; https://zhuanlan.zhihu.com/p/21349186 前情提要&#xff1a; Tomcat高效响应的秘密(一) Sendfile与Gzip Tomcat高效响应的秘密(二) keep alive 前面高效响应的两篇&#xff0c;我们分析了Sendfile的特性以及HTTP1.1的keep-alive特性&#xff0c;基于这些功…

通过NSNotification来监听键盘弹出和弹回

在通知中心建立一个广播来监听键盘的弹出和弹回&#xff0c;在监听事件中加入触发事件的一些操作。 [[NSNotificationCenter defaultCenter]addObserver:self selector:selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];[[NSNotificatio…

IT综合学习网站收集

最近整理了一下曾经使用过的IT从入门到广泛的综合类基础学习网站&#xff0c;记录下来&#xff0c;以便初学者使用&#xff1a; 1.http://www.w3school.com.cn/ 中文版基础在线学习平台 2.http://www.runoob.com/ 中文版基础在线学习平台&#xff08;和W3类似&#xff09; 3.h…

mac安装gdb及为gdb进行代码签名

1. 安装gdb GDB作为一个强大的c/c调试工具&#xff0c;一直是程序猿们的良好伴侣&#xff0c;但转到Mac os才发现竟然没有默认安装&#xff0c;所幸还有强大的homebrew工具&#xff1a; brew install homebrew/dupes/gdb然后就是漫长的等待编译安装时间了&#xff0c;安装完成后…

Python学习---Django的基础操作180116

Django创建数据库操作 django流程之model实例 settigs.py&#xff1a;更改Django2.0.1的配置&#xff0c;更新为之前的路径配置 DIRS: [os.path.join(BASE_DIR, templates)], # 设置templates的路径为Django以前版本 # DIRS: [], # 注释掉该行&#xff0c;此为Django 2.0…

订阅Jenkins的邮件列表,获取最新的信息

进入https://jenkins.io/content/mailing-lists/ 点击感兴趣的话题 选择【archive】跳转到谷歌讨论组 最后&#xff0c;点击左上角的【Subscribe】即可加入Google Groups 备注&#xff1a;其实谷歌讨论组是一个很好用的东西&#xff0c;每个人都可以上去建&#xff0c;对于集成…

英语四六级和计算机二级是一,大学里最难考证书排名,四六级和计算机根本排不进前三...

大学是我们提高自身技能最好的一个时期&#xff0c;除了平时的课程和一些社团活动之外&#xff0c;还有一件最最必不可少的事情&#xff0c;那就是考证&#xff0c;而这也是为我们以后工作打好基础&#xff0c;为自己多准备一些敲门砖。我国各个行业都有属于自己的证书&#xf…

Fedora 安装后需要做的第一件事

一直以来&#xff0c;Red Hat 系的许多教程&#xff0c;都会建议你关闭 SELinux。确实&#xff0c;启用 SELinux 可能会造成许多莫名其妙的错误。但在实际生产环境&#xff0c;甚至是用户工作站&#xff0c;Red Hat 都建议将 SELinux 设为 enforcing 模式&#xff0c;因为它在关…

html文件怎么导出stl文件,各种3D建模软件导出STL文件的小技巧(一)

很多用户在提交3D模型文件的时候&#xff0c;常常有这样的困惑&#xff1a;什么是STL 格式文件&#xff0c;怎么获取STL 格式文件呢&#xff1f;STL 格式文件是在计算机图形应用系统中&#xff0c;用于表示三角形网格的一种文件格式。它也是3D打印机在执行3D打印程序时&#xf…

angularjs 中的scope继承关系——(2)

转自&#xff1a;http://www.lovelucy.info/understanding-scopes-in-angularjs.html angularjs 中的scope继承关系 ng-include 假设在我们的 controller 中&#xff0c; $scope.myPrimitive 50; $scope.myObject {aNumber: 11}; HTML 为&#xff1a; <script type&quo…

Android界面菜单(4)—快捷菜单

2019独角兽企业重金招聘Python工程师标准>>> 快捷菜单 当用户点击界面上某个元素超过2秒后&#xff0c;将启动注册到该界面的快捷菜单。 步骤&#xff1a; 1.代码动态生成菜单 final static int CONTEXT_MENU_1 Menu.FIRST;final static int CONTEXT_MENU_2 Menu…

Echarts地图编写

1.引入echarts库文件 <script charset"utf-8" type"text/javascript" language"javascript" src"echarts-2.2.7/doc/example/www/js/echarts.js"></script> 2.在页面中新建div用于地图展示 <div id"main" st…

威海职业学院计算机专业宿舍,2021年威海职业学院新生宿舍条件和宿舍环境图片...

每年高考结束后&#xff0c;威海职业学院新生被录取同学们陆续都到校报到~而宿舍作为同学们朝夕相处之场所&#xff0c;如果不懂相处之道&#xff0c;难免会摩擦不断&#xff0c;更有甚者堪比宫斗大戏。所以各位大学新生一定要珍惜室友之间的友情&#xff0c;彼此处好关系。本文…

计算机专业录取分数及大学排名,计算机专业录取分数最高的大学有哪些?附排名前50大学名单...

高考结束之后&#xff0c;不少即将迎接高考的家长对于很多专业的录取情况都抱有很大的兴趣&#xff0c;都比较关心自己的理想专业大概能上哪些大学。今天&#xff0c;小编将为大家以山东高考计算机专业各大学录取分数进行排名&#xff0c;供下一届高考生参考。计算机专业作为近…

letsencrypt 自动续期不关闭nginx

为什么80%的码农都做不了架构师&#xff1f;>>> 已失效 corntab -e 5 0 1 * * /opt/letsencrypt/letsencrypt-auto --config /etc/letsencrypt/webroot.ini -d <domain> certonly && sudo service nginx reload/etc/letsencrypt/webroot.ini rsa-key…

loss低但精确度低_低光照图像增强网络-RetinexNet(model.py解析【2】)

论文地址&#xff1a;https://arxiv.org/pdf/1808.04560.pdf代码地址&#xff1a;https://github.com/weichen582/RetinexNet解析目录&#xff1a;https://zhuanlan.zhihu.com/p/88761829整个模型架构被实现为一个类&#xff1a;class lowlight_enhance(object):其构造函数实现…

添加dubbo xsd的支持

使用dubbo时遇到问题&#xff1a; org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document http://code.alibabatech.com/schema/dubbo/dubbo.xsd, because 1) could not find the document; 2) the document could not be read; 3) the root ele…

byte数组穿换成pcm格式_形象地介绍DSD的编解码原理及和PCM的区别

一直有人不清楚DSD到底是啥原理&#xff0c;和MP3, FLAC, APE, WAV等基于PCM编码技术的音频格式又有啥区别。特意做了两张图说明一下。图一是是由很多黑点构成的蒙娜丽莎头像&#xff0c;点击看大图就知道是没有灰阶只有黑白两色。但是人眼是可以看到有丰富的灰阶的。这和DSD一…

UBUNTU : Destination Host Unreachable

介绍我的系统的搭建的方式: WIN7 64 VMWARE STATION&#xff0c;方式是进行桥接的方式。最近突然出现了问题&#xff0c;Ubuntu ping 外网或者 PING WIN 7 的时候&#xff0c;出现 Destination Host Unreachable 的错误&#xff1b;想着去修改网卡的链接形式&#xff1a; 编辑…