转:Eric Lippert:阅读代码真的很难

时间:2023-01-16 14:47:01

转自:http://blog.jobbole.com/438/

相关文章

编者按:原文作者 Eric Lippert 是微软一名资深软件设计工程师,从1996年起一直在微软开发部门任职,协助设计并实现VBScript、JScript、JScript .NET、Windows Script Host、Visual Studio Tools for Office 和 C#。

Escalation的工程师JeremyK在他博客中问到:

你是怎么教人们快速深入挖掘不熟悉的代码(不是自己所写的)?我学习如何编程的方法很传统 —— 自己动手编码。但我现在很纠结:到底是集中精神阅读源码,还是自己编写。对我而言,似乎唯一有效的方法就是自己写过。

不是和Jeremy开玩笑,写代码的确没有读代码难。

首先,我同意你的看法,几乎很少有人能读代码但不会写代码。这不像自然书面语或口语,理解他人的意思并不需要去理解他们为什么要那样说。比如,如果我说:

“写代码有两种方式:一种严格且详细,另一种模糊且草率。前者生成简洁分层的婚礼蛋糕,后者却是意大利面条。”

上面这句话产生一个平衡且幽默的效果,但即使听众和读者不理解我使用“零照应”和“并列句”这样的文字技巧,也会理解我要说的意思。但是说到代码,既要从代码本身中理解代码作者的意图,又要理解代码产生的预计效果,这两者都极为重要。

转:Eric Lippert:阅读代码真的很难

Eric Lippert

因此,我又回到那个问题了,有些人需要快速切入代码,但不需要动手写代码,那我们如何编写适合这些人的代码?

下面是我在编写代码时,尽力去做的事,目的就是使其他人能轻松阅读:

1. 使代码遵从工具。Object Browsers和Intellisense虽然很好,但我告诉你,我是守旧派。如果找不到我想要的,我会不高兴。什么使得代码成为可查询的呢?

●像”i”这样的变量名不好。如果没有明确的错误提示,你就无法轻易查找代码。

●避免使用是其他名字前缀的名字。比如,在代码中有个“perfExecuteManifest”,如果再有一个“perfExecuteManifestInitialize”,这就会让我抓狂,因为每次在源码中查询前者时,我不得不费力地过滤掉后者所有的实例。

●“临时传递数据”(tramp data)应使用相同的名字。所谓“临时传递数据”(tramp data),就是指那些传递给方法A的变量,还要传给方法B的变量。这两类变量实际上是相同的,所以如果它们有着相同的名字,则更好。

●别用宏来重命名东西。如果有个方法叫get_MousePosition,那别这样GETTER(MousePosition)来声明该方法。因为我会找不到实际的方法名。

●Shadowing会引起很多问题,请不要用它。

2. 坚持使用一种命名模式。如果你打算用匈牙利命名法,那就坚持并广泛使用,否则将适得其反。使用匈牙利命名法来记录数据,而不是存储类型;记录普遍事实,而不是临时条件。

3. 使用断言来记录先决条件(preconditions)和后置条件(postconditions)。

4. 别缩写英文单词。确切来说,别缩写成稀奇古怪的形式。在脚本引擎中,有个变量名叫“NME”,这让我非常抓狂!它应当叫“VariableName”。

5. C语言标准运行时库的设计不是很优秀。别去效仿它。

6. 别写“聪明”的代码;当代码出现问题,维护代码的程序员没时间去理解你的聪慧。(编注:这条建议即为:编写可维护的代码,详情可参见《明星软件工程师的10种特质》中的第8点。)

7. 理解编程语言特性的设计初衷,使用这些特性去做它们适合完成的工作,而不是它们能做到的工作。例如:别把异常当做一般的流控制机制来使用(即便你能做到),而应该用它们来报告错误。别强制把接口指针转换成类指针,即便你知道这样没问题。

8. 按功能单元划分源码树,而不是按组织结构。比如:我目前所在团队中,有2个根子目录的名字是“Frameworks”和“Integration”,这是两个团队的名字。不巧的是,Frameworks团队名下有一个叫“Adaptor”的子目录,而“Adaptor”却是Integration的子目录,这就非常令人迷惑。同理,(如果)有着相同子目录的不同的子树,有些是客户端的组件,有些是服务端的组件;有些是管理组件,有些是非管理组件;有些是处理型组件,有些是非处理型组件;有些是零售组件,有些内部测试工具。这就会乱七八糟的。

当然,我实际上根本没有回答Jeremy的问题——如何调试不是我写的代码?

这取决于我的目的。如果我只是因为一个bug,而深挖一段具体的代码,我会在调试器中逐步跟踪所有代码,写下我“走过”的调用分支,记录下哪些方法是特定数据结构的“生产者”,哪些方法是“消费者”;我也会仔细盯着输出窗口,查看出现的有用信息;还要打开异常捕捉器,因为异常通常是问题所在。设置断点;我会记录所有和我上面建议相反的地方,因为这些东西很可能误导了我。

如果我想在理解一段代码后修改它,我通常是从代码头部开始,或者先查找公共方法。我要知道类是如何实现的,它是如何扩展的,它的作用,它是如何嵌入整个代码中的?我会尽力理解这些东西后,才去了解这些特定部分(代码)是如何实现的。这耗时虽更长些,但如果你准备改动复杂代码,你应当那样做。

转:Eric Lippert:阅读代码真的很难的更多相关文章

  1. JVM 真的很难学么?不、只是你“不敢学”而已

    JVM 真的很难学么?不.只是你"不敢学"而已        许多招聘的信息上面都说,要了解jvm.多线程什么的对于 java 程序员来说,这是工作好多年的程序员都不一定能掌握的东 ...

  2. What?废柴, 模拟登陆,代码控制滑动验证真的很难吗?Are you kidding???

    1.简介 在前边的python接口自动化的时候,我们由于博客园的登录机制的改变,没有用博客园的登录测试接口.那么博客园现在变成了滑动验证登录,而且现在绝大多数的登录都变成这种滑动验证和验证码的登录验证 ...

  3. HDU 3038 How Many Answers Are Wrong(带权并查集,真的很难想到是个并查集!!!)

    How Many Answers Are Wrong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  4. 如果你不了解Java的JVM,那真的很难进BAT一线大厂!

    前言 对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug.同时,JVM也是面试环节的中重灾区.我们不能为了面试而面试,但是学习会这些核心知识你必定会成为面试 ...

  5. 如何在MAC下安装Myeclipse2015真的很虐心!!!!!!!!!!

    最近笔者换了一个新的笔记本,mac pro 因为同学说大公司的web开发都是写在Linux操作系统下的,所以我决定搞一个,但是装软件就是很困难啊!找了大量资料发现都不全,最后,终于搞好了,分享给同样虐 ...

  6. js混淆加密,通过混淆Js代码让别人(很难)无法还原

    js混淆加密,通过混淆Js代码让别人(很难)无法还原   使用js的混淆加密,其目的是为了保护我们的前端代码逻辑,对应一些搞技术吃饭的公司来说,为了防止被竞争对手抓取或使用自己的代码,就会考虑如何加密 ...

  7. ReSharper的功能真的很强大主要是针对代码规范和优化,园子里介绍的也不少,如果你没有安装,那我只能表示你们会相见恨晚

    二.ReSHarper 代码规范.单元测试.... ReSharper的功能真的很强大,主要是针对代码规范和优化,园子里介绍的也不少,如果你没有安装,那我只能表示你们会相见恨晚! 1.像命名不规范,f ...

  8. MySQL开发篇,存储引擎的选择真的很重要吗?

    前言 谁说MySQL查询千万级别的数据很拉跨?我今天就要好好的和你拉拉家常,畅谈到深夜,一起过除夕!这篇文章也是年前的最后一篇,希望能带给大家些许收获,不知不觉查找文档和参考实体书籍就写了这么多,自己 ...

  9. 函数式编程很难,这正是你要学习它的原因 | 外刊IT评论网

    函数式编程很难,这正是你要学习它的原因 | 外刊IT评论网 函数式编程很难,这正是你要学习它的原因 156 次分享 新浪微博 腾讯微博 Tweet 人人网 QQ空间 很奇怪不是,很少有人每天都使用函数 ...

随机推荐

  1. WPF弹出带蒙板的消息框

    效果图 思路 拿到父级窗体的内容,放入一个容器里,再在容器里放入一个半透明层.将整个容器赋给父级窗体的内容. 关闭时反向操作. 代码 消息窗弹出时 /// <summary> /// 弹出 ...

  2. ObjC宏定义-预编译小功能

    以前看来#号,好像只是预编译,原来它还可以有跟Swift中"\( )"的拼接功能 例如: #define string(x) #x 意思就是 string(x) = "x ...

  3. PotPlayer 1&period;6&period;52965 美化版&vert;视频播放器

    Potplayer播放器,基本上可以解析大部分的视频格式.作为单机版的视频播放器很不错的选择! Potplayer,只为播放而生! exp: 点击下载

  4. java Scanner与BufferedReader读取键盘输入性能比较

    java  Scanner与BufferedReader读取键盘输入性能比较            1.Scanner和BufferedReader 性能比较 在java中常见的从键盘获取输入的方式有 ...

  5. kNN&lpar;K-Nearest Neighbor&rpar;最近的分类规则

    KNN最近的规则,主要的应用领域是未知的鉴定,这一推断未知的哪一类,这样做是为了推断.基于欧几里得定理,已知推断未知什么样的特点和最亲密的事情特性: K最近的邻居(k-Nearest Neighbor ...

  6. Android安全开发之启动私有组件漏洞浅谈

    0x00 私有组件浅谈 android应用中,如果某个组件对外导出,那么这个组件就是一个攻击面.很有可能就存在很多问题,因为攻击者可以以各种方式对该组件进行测试攻击.但是开发者不一定所有的安全问题都能 ...

  7. Ubuntu环境下Anaconda安装TensorFlow并配置Jupyter远程访问

    本文主要讲解在Ubuntu系统中,如何在Anaconda下安装TensorFlow以及配置Jupyter Notebook远程访问的过程. 在官方文档中提到,TensorFlow的安装主要有以下五种形 ...

  8. android程序崩溃后重启

    有时候由于测试不充分或者程序潜在的问题而导致程序异常崩溃,这个是令人无法接受的,在android中怎样捕获程序的异常崩溃,然后进行一些必要的处理或重新启动 应用这个问题困恼了我很久,今天终于解决了该问 ...

  9. RN 时间戳

    let curTime = Date.now(); 获取到当前时间 curTime: 1555120690696 是指从1970.1.1到现在的毫秒(ms)数 cxk() { //之前时间 let p ...

  10. ubuntu中文版man

    man默认是英文的,但ubuntu的源里也有中文版的.以下是配置方法: 1)  终端输入sudo apt-get install manpages-zh 2)  安装后修改配置文件sudo gedit ...