读源码时,我们到底在读什么?
2016-06-24 14:59
447 查看
村上春村有本关于跑步的书:当我谈跑步时我谈些什么
而我们软件工程师,经常会提到读源代码,读优秀开源作品的源代码。我们谈起读源码时,到底是读什么呢?
读者可能会说,你这不是装X,明知故问嘛,读源码,当然就是读源码了。
当然,源码是我们阅读的对象,我前面的文章也提到了一些源代码阅读相关的内容。我今天想谈的是,我认为源码阅读除了提高设计能力外,也是学习相应实现语方语法与最佳实践的好例子,以及简洁代码、类/方法/变量等命名、注释编写等方面的榜样。
代码是写给人看的。这句话在许多编程的书里面都提到过。我们每次的代码写好后的刹那,以后的漫长岁月里,可能要无数次的阅读它,修改它,或者交给其他人来填坑,来重构。而写代码时的一点点追求,一个变量的命名,一段注释的描述,可以为后来的填坑侠争取来不少做好梦的夜晚。
而读优秀源码,就是学习其编写Clean code的过程,就是和作者交流的过程。各种代码的组织,小函数的封装,行前注释的解释,甚至某一小段代码的增加是为了解决某个Bug,对应bug系统中的bug号都能更清楚的让你理解它。
留意代码阅读中,对当前阅读主线不直接相关但语法不明所以然的地方,这些是学习实现语言语法以及相关背景知识的一个不错的方式。
例如,在读源码时,可能会发现,在阅读主线之外,有类似于日期格式化这样的工具类源代码调用。也许代码类似下面的样子:
public static final String RFC1123_DATE =
"EEE, dd MMM yyyy HH:mm:ss zzz";
private static final SimpleDateFormat format =
new SimpleDateFormat(RFC1123_DATE, Locale.US);
/**
* Get the current date in HTTP format.
*/
public static final String getCurrentDate() {
long now = System.currentTimeMillis();
if ((now - currentDateGenerated) > 1000) {
synchronized (format) { //
注意这里
if ((now - currentDateGenerated) > 1000) {
currentDate = format.format(new Date(now));
currentDateGenerated = now;
}
}
}
return currentDate;
}
如果之前不曾详细了解过SimpleDateFormat,你不禁会想,此处为什么会使用synchronized进行同步加锁呢,那一定是它不是线程安全的。为了在多线程环境进行日期格式化,还有哪些方式呢。了解了之后就不会在多线程环境中依然使用一个全局的dateFormat进行格式化了,从而避免了以后的问题。
此处,对于某些教科书或XX天掌握XX这种书中较少深入讲解的内容,在出现时,可以以此为契机深入了解。
例如某段代码中,出现了类似于下面的内容
private
volatile boolean stopAwait = false; //
注意这里
// Loop waiting for a connection and a valid command
while (!stopAwait) {
ServerSocket serverSocket = awaitSocket;
if (serverSocket == null) {
break;
}
此时,就需要了解volatile的作用,如果不标识为volatile,会对程序的执行有哪些影响。而在了解的过程中,除了了解到其对指令重排序的影响外,顺便内存的可见性、Java的内存模型等一系列内容就深入你的脑海,「只是因为在代码中多看了你一眼啊」。
同时,优秀的源代码,都会有许多的单元测试,顺着这些例子,可以学习到测试的组织方式;
会使用到不同的依赖管理工具,构建工具,也许你熟悉Ant、但源代码默认提供的是Maven/Gradle,就顺手了解了另一种工具;
也许你常用的Xml解析库是使用Dom4j/Jdom这些工具,而源代码中是使用JAXB的实现,在阅读的时候,你就会了解到另一种选择。
而这些内容,是你在读源码学架构,学设计模式,学原理之外,看似无意义的东西。
也许,就像当年乔布斯在里德学院学习衬线体和非衬线体一样,看似无用的东西,在他后来设计Macintosh的时候,「It all came back to me」。而我们现在主线之外的阅读,我想也会无心插柳,但在不经意的时候柳树成荫,让你炎热的时候好乘凉。
而我们软件工程师,经常会提到读源代码,读优秀开源作品的源代码。我们谈起读源码时,到底是读什么呢?
读者可能会说,你这不是装X,明知故问嘛,读源码,当然就是读源码了。
当然,源码是我们阅读的对象,我前面的文章也提到了一些源代码阅读相关的内容。我今天想谈的是,我认为源码阅读除了提高设计能力外,也是学习相应实现语方语法与最佳实践的好例子,以及简洁代码、类/方法/变量等命名、注释编写等方面的榜样。
代码是写给人看的。这句话在许多编程的书里面都提到过。我们每次的代码写好后的刹那,以后的漫长岁月里,可能要无数次的阅读它,修改它,或者交给其他人来填坑,来重构。而写代码时的一点点追求,一个变量的命名,一段注释的描述,可以为后来的填坑侠争取来不少做好梦的夜晚。
而读优秀源码,就是学习其编写Clean code的过程,就是和作者交流的过程。各种代码的组织,小函数的封装,行前注释的解释,甚至某一小段代码的增加是为了解决某个Bug,对应bug系统中的bug号都能更清楚的让你理解它。
留意代码阅读中,对当前阅读主线不直接相关但语法不明所以然的地方,这些是学习实现语言语法以及相关背景知识的一个不错的方式。
例如,在读源码时,可能会发现,在阅读主线之外,有类似于日期格式化这样的工具类源代码调用。也许代码类似下面的样子:
public static final String RFC1123_DATE =
"EEE, dd MMM yyyy HH:mm:ss zzz";
private static final SimpleDateFormat format =
new SimpleDateFormat(RFC1123_DATE, Locale.US);
/**
* Get the current date in HTTP format.
*/
public static final String getCurrentDate() {
long now = System.currentTimeMillis();
if ((now - currentDateGenerated) > 1000) {
synchronized (format) { //
注意这里
if ((now - currentDateGenerated) > 1000) {
currentDate = format.format(new Date(now));
currentDateGenerated = now;
}
}
}
return currentDate;
}
如果之前不曾详细了解过SimpleDateFormat,你不禁会想,此处为什么会使用synchronized进行同步加锁呢,那一定是它不是线程安全的。为了在多线程环境进行日期格式化,还有哪些方式呢。了解了之后就不会在多线程环境中依然使用一个全局的dateFormat进行格式化了,从而避免了以后的问题。
此处,对于某些教科书或XX天掌握XX这种书中较少深入讲解的内容,在出现时,可以以此为契机深入了解。
例如某段代码中,出现了类似于下面的内容
private
volatile boolean stopAwait = false; //
注意这里
// Loop waiting for a connection and a valid command
while (!stopAwait) {
ServerSocket serverSocket = awaitSocket;
if (serverSocket == null) {
break;
}
此时,就需要了解volatile的作用,如果不标识为volatile,会对程序的执行有哪些影响。而在了解的过程中,除了了解到其对指令重排序的影响外,顺便内存的可见性、Java的内存模型等一系列内容就深入你的脑海,「只是因为在代码中多看了你一眼啊」。
同时,优秀的源代码,都会有许多的单元测试,顺着这些例子,可以学习到测试的组织方式;
会使用到不同的依赖管理工具,构建工具,也许你熟悉Ant、但源代码默认提供的是Maven/Gradle,就顺手了解了另一种工具;
也许你常用的Xml解析库是使用Dom4j/Jdom这些工具,而源代码中是使用JAXB的实现,在阅读的时候,你就会了解到另一种选择。
而这些内容,是你在读源码学架构,学设计模式,学原理之外,看似无意义的东西。
也许,就像当年乔布斯在里德学院学习衬线体和非衬线体一样,看似无用的东西,在他后来设计Macintosh的时候,「It all came back to me」。而我们现在主线之外的阅读,我想也会无心插柳,但在不经意的时候柳树成荫,让你炎热的时候好乘凉。
相关文章推荐
- 老司机谈APK瘦身套路-图片资源篇
- 构造函数与析构函数
- $.ajax()方法详解
- MAVEN 私有仓库库迁移
- PHP判断一天打卡的第一个时间和最后的时间
- MAVEN 私有仓库库迁移
- StringUtils常用方法+StringUtils详细介绍
- Android的基本问题及答案
- Python Paramiko模块
- MAVEN 私有仓库库迁移
- ios 基本技术点
- MAVEN 私有仓库库迁移
- MAVEN 私有仓库库迁移
- 深入解析Python编程中super关键字的用法
- MAVEN 私有仓库库迁移
- linux下文件比较工具,文件夹比较工具
- [FAQ04776]如何默认打开user版本 debug 选项, 默认打开adb 连接
- Android 屏幕dp px换算
- 实现一个不被干掉的Service
- Linux下文件的三种时间属性