前言
以下记录程序员生涯中的一些摘抄及感悟
如何了解自己的技术水平
借用知乎上某位哥们的话,程序员的水平主要分为三个境界:
- 入门程序员在别人的帮助下解决问题;
- 中级程序员自己独立解决问题;
- 高级程序员帮助别人解决问题。
如何更好的学习一门技术
借用忘记了名字的一位大牛的话,大意是:“即便一门语言已经过时了,学习它仍然十分必要,这样你可以看到解决同一个问题的不同思路”,进而理解“什么是变的,什么是不变的”。
我觉得我们学习任何技术都应该如此。
搞好基础vs学习新技术
新技术的出现总是眼花缭乱,很想尝尝鲜。搞好基础(比如看看linux源码)却通常很枯燥。
初入行的程序猿,无论搞好基础还是学习新技术,我觉得都有必要学习几个基本实现:
- 如何写一个服务器,可以参看tomcat和redis等的源码。既要监听服务又要组织业务,网络通信、数据模型和分层架构等等,非常通用,很有意思。
- 如何写一个客户端,可以看看redis client和mysql driver的jar,如何将一个请求转化为send/receive数据等,涉及到连接池、线程池和异步通信等等。再细节的一点,比如客户端监听的实现。
- 客户端与服务端,涉及到通信协议的设计等。
搞业务可以让你思考,如何将代码写的更精炼、更易懂。学框架,可以学习在更高层次上组织代码的艺术。顺序代码、多线程代码、网络编程代码如何糅合。将代码进行横向和纵向划分,在哪些维度上解决哪些问题
不停地重构
笔者常见的工作情况是,完成a项目,开始b项目,产品经理给a项目或更早的项目加需求,因为此时重心在b项目上,所以简单的需求简单加点代码,如此推进,a项目代码逐渐有点复杂,并偏离原先设计的一些构想。因此,要时时留意重构,如何重构?参见《重构,改善既有代码的设计》
时间与空间的矛盾
这个是编程的一个基本矛盾:
-
“程序 = 数据结构 + 算法”,如果数据结构保存了较多的信息(都是必要的,没有直接的冗余),就可以减轻算法的复杂度(直观说,就是方法的行数)。反之,xxx。
-
如果数据不管用于不用,都随时待命,那么程序的响应速度会很快。如果数据在用的时候才加载,会节省内存,但会延长响应时间。
为什么我们要了解底层机理
我是大四下学期开始熟悉linux的使用,当时觉得linux完全是一个落后的产品,“一个命令那么多的参数,谁能记得清楚。删除一个文件夹为什么不是del一下就可以?”,即便后来能够较为熟练地操作,对linux也是心存芥蒂。直到看了《linux内核设计的艺术》,才知道windows其实误导了我们对很多事情的认识,比如“任何操作系统必须有一个“c”盘“。
图形化界面习惯了之后,我很长时间无法深刻理解maven相对于eclipse有什么了不起的优势(除了自动解决依赖)。最近在看《程序员的自我修养》,主要讲链接、装载和库的,让我释然了很多疑惑。然而一个在图形化界面开发c和c++的程序员,由源代码直接看到执行结果,很难有欲望去看看中间发生了什么。
“不知道中间发生了什么”带来的后果是,我们被迫记忆很多“规则”,比如“一个大的结构体最好不要作为c函数的返回值,函数内局部变量只在函数范围内有效”。记规则有很多危害,它会让你束手束脚。
比如:一个女孩子说不喜欢吃麻辣豆腐,可以有以下引申:
- 不喜欢吃麻辣豆腐,但喜欢xxx
- 不喜欢吃豆腐,但喜欢xxx
- 不喜欢吃麻的,但喜欢xxx
- 不喜欢吃辣的,但可以吃一点xxx
- 家里“来亲戚”了
可能的排列组合多了去了,但因为我们对这个女孩子不了解,我们最终只知道一条“她不喜欢吃麻辣豆腐”,知道这个远远不足以了解她的饮食风格。如果我们知道背后的机理,那么就好处理多了。
国内的技术书籍大多如此,因为不了解底层,往往很厚,一上来就将读者带入繁杂的细节中,我们在规则中战战兢兢,这样的“知识”难学且易忘。
有一个异曲同工的点,“最简单的需求分析,是将需求抽象成函数,比如findMax(),findMin()。好的需求分析,是将需求抽象成参数,比如findData(int sortIndex)”
编译器优化
现在的编译器越来越聪明了,比如java,为了提高程序的并行能力,程序代码的执行顺序和其实际的指令执行顺序可能并不一样,这样的优化发生在临界区时,就会出现超乎预料的后果。
go语言中则有其他问题,譬如“当函数返回对象指针时,必然在堆上分配。如果该函数被内联,那么这个指针就不会跨栈帧使用,就有可能在栈上分配,以实现代码优化的目的。”
如何分析一个框架
脉络1,分析主要接口类
- 找到核心的几个接口或父类
- 核心的接口或类之间的交互过程和依赖关系
- 每个接口或父类找一个最简单的实现类分析一下
一个类或接口,通常已经定义好了所有功能,其子类的扩展主要有两个方向:
- 扩展功能,但一般最终还是为了实现接口的定义的“主功能”
- 差异化底层实现。比如ArrayList和LinkedList,其功能没什么区别,只是操作的数据结构不同。
观察一个类的成员变量,就知道这个类能做什么。有的类的功能是自己实现的,有的类的功能是调用成员变量实现的(其本身只起到聚合作用)
脉络2,分析运行流程
更多时候,是两者同时使用。
分清重点,有些细节很多很复杂,但搞清楚它们对你理解整个框架最核心的功能意义不大,那就放弃。比如,你正在学习一个分布式配置中心框架,那么学习其中的连接池的原理,就是不太必要的。