程序员修炼之道–从小工到专家
职业素养
###1.我的源码让猫吃了 && 3.石头汤和煮青蛙
-
在所有弱点中,最大的弱点就是暴漏弱点
-
坦诚我们的无知、错误
-
要承担责任,但是尽量让风险处于可控的状态
-
问别人问题前,要把谈话预演一遍
-
面对问题,少找借口
-
让别人瞥见未来,就能获取更多资源
-
要持续的观察周围发生变化,而不是局限在自己的小范围内
####个人理解
-
实事求是,勇于承认自己的不足、缺点、错误
-
三思而后行,不说不经大脑思考的话
-
勇于承担责任,但是要把风险控制放到自己可控制的范围内,自己给业务方、产品、后端做出答复的时候,要经过仔细评估,表现出可靠、专业
-
互联网行业速度太重要,首先出现一个简易版本,然后不断迭代升级
-
不能局限与技术,要很好地了解业务,尤其是前端开发人员,对数据的流动要虚心向后端请教,这样才能更好的服务用户
###6.交流
-
没有好的交流,一个好想法就只是一个无人关心的孤儿
-
确切地弄清楚你想要说什么
-
了解听众:他们的需求、兴趣、能力
-
交流的时机也很重要
-
针对不同人群选择不同交流风格
-
让听众参与进来,获取他们的反馈
-
及时回复别人的提问
-
说什么和怎么说同样重要
-
邮件是非常正式的形式,检查确认后再send
####个人理解
-
工作以来,不喜欢开会,跟业务方、PM、后端沟通不够充分,对业务、需求的把握上较为欠缺,以后需要调整
-
到什么山头唱什么歌,为了更有效的交流,要学会用对方的语言来交流,例如跟PM就不能老说DOM、event、渲染这些专业性很强的概念
-
要及时回复别人,这块也做得不好,工作的时候总是喜欢关闭通信工具,不能及时反馈别人的问题,一方面不尊重别人,另一方面也会错过一些重要信息
-
交流的时候要注意交流的方式,顾忌别人的尊严和感受,不能贪图嘴快
###16.编辑器 && 17.源码控制
-
用好一种编辑器,充分利用快捷键、插件等内容
-
团队开发离不开版本控制软件
个人理解
- 高级程序员均擅长使用工具,包括编辑器、版本控制软件、自动化工具等等,通过工具解放人,让程序员做更加有价值的事情
36.需求之坑 && 37.解开不可能解开的谜题
-
不要搜集需求,挖掘它们
-
细节内容不要过多,元数据进行配置
-
找出用户需要做事情的原因,而不是他们目前做这件事情的方式
-
与用户一同工作,像用户一样思考
-
为别人构建的工具必须具有可适应性
-
好的需求文档要保持抽象,不能过于具体
-
抽象比细节活得更长久
-
开发中要制止需求的增长
-
有些约束是绝对的,有些则是先入之见,所以要确定真正的约束
-
对问题的重新诠释能让整个问题全部消失
38.等你准备好
-
启动新项目可能会让人身心交瘁
-
构建原型可以作为调研下一步是否合适的方法
-
项目拖延的原因有两种:一是无法下手;二是懒惰
39.规范陷阱 && 40.圆圈与箭头
-
需要制定规范,但是规范不能过细,这样会增加实现成本
-
要把技术纳入到开发实践和能力的语境中
-
需求分析方式是必要的,但是不能成为这些方法的奴隶
软件开发的特点
###2. 软件的熵 && 4.足够好的软件
-
破窗理论:不要纵容代码中小的问题,否则会加快代码的腐烂过程
-
不存在完美的软件
-
不能无限制的添加、修饰需求,在一定范围内,时间大于质量
####个人理解
-
遇到编码不合理的地方,在时间允许的情况下,对代码进行重构
-
对不合理、性价比低的业务需要,要拒绝
###7.重复的危害
-
DRY:Don’t Repeat Yourself,也不要重复别人
-
不可信任的注释比完全没有注释更糟
-
访问代码是互惠的,不能还别别人查看、指正自己的代码
####个人理解
- 尽量少造轮子,避免重复,前端开发中,模块化的作用之一就是可以做到代码的复用,将业务中的共性问题提炼出来,封装到一个模块中,做到统一管理和使用
###8.正交性 && 9.可撤销性 && 10.曳光弹 && 11.原型与便签
-
提高代码的正交性就是减少依赖或耦合性,提高生产效率和降低风险
-
模块化、组件化、封装的目的均是降低代码的耦合性
-
面向方面编程(AOP)是正交性的一个体现
-
在做决策的时候,要考虑到后期的拓展性
-
代码中不要存在硬编码
-
快速开发出代码的骨架,可以对系统有直观的认识
-
原型的价值不在于所生产的代码,而在于所学到的经验教训
####个人理解
-
低耦合高内聚一直是软件开发的努力方向,尽量做到一个模块只干一件事情,一个函数只完成一个动作,然后再将其聚合起来实现特定功能,就像lodash比underscore好的一个方面就是,每个对象可以单独引用,同时又可以轻松地组合起来
-
关于AOP已经有很多应用,例如spring、单元测试beforeEach、githook、npm run script等
-
在业务开发中,需要考虑后期的迭代升级,方便后期的开发,例如:事件绑定时,做到事件和相应回调函数的分离,不要用匿名函数的形式
1
2
3
4
5
6
7
8
9
10
//不好的写法
ele.on(type, function () {
...
})
//function可以复用的方式
ele.on(type, fn);
var fn = function () {
...
}
###12.领域语言 && 13.估算
-
语言的界限就是一个人的世界的界限
-
计算机语言会影响思考问题的方式,以及看待交流的方式
-
靠近问题领域编程
-
学会估算,是工作中非常重要的一件事情
19. 调试
-
调试就是解决问题
-
面对问题不要恐慌,尽量让问题重现,充分利用调试工具,做到代码的追踪
-
面对bug的时候,不要假定,要去证明,也就假定的内容本身就是错误的
41.注重实效的团队
-
质量是一个团队的问题,不是个人人的事情
-
交流环节要使用统一的术语
-
在项目启动的时候给项目取一个名字,创立品牌
-
抵抗不断画下去的诱惑,防止需求的不断扩大
42.无处不在的自动化
-
只有自动化才能保证项目的一致性和可重复性
-
记忆是随着年龄的增长而减弱的东西
-
让计算机去做重复、庸常的事情
44.全都是写
-
把英语当成又一种编程语言
-
注释不能太少、太多、无意义、误导人,要说明代码存在的原因、参数、返回结果
-
对待文档要像对待代码一样用心
45.极大的期望
-
温和地超出用户的期望
-
通过交流可以让用户的期望达到合理
-
额外的一些小事情,增加不了多少工作量,却可以给使用人员带来很大方便
个人理解
-
用户的理解、知识、阅历相差较大,对结果的期望也不太一样,有些需求在现有条件下是无法做到的,这就需要提交告诉使用方,否则他们就会觉得开发人员在偷懒、在敷衍他们,需要告诉他们不能实现的原因,技术问题他们可能不知道,但是其中的逻辑还是理解的,也体现对业务方的尊重。
-
还有就是开发时,多站在使用人员的角度考虑问题,例如给常用功能添加快捷键、切换页面背景色等功能,虽然很小,但是却可以给使用人员带来很大帮助,超出他们的期望,得到好的反馈。
46.傲慢与偏见
-
不要担心别人查看自己的代码
-
你要别人怎么对你,你就怎么对人
学习成长
###5.你的知识资产
-
知识和经验是程序员的职业财富,她们是有时效性的
-
把学习作为一个习惯,阅读技术、非技术书籍,满足人的需要
-
多元化:不要仅仅局限于一个方向,例如新语言、新操作系统
-
不断评估自己的技术和努力方向
-
积极参与社区、外界活动,拓宽视野
-
批判性接收,最好用实际行动检验自己学到的新内容
####个人理解
-
不断学习是互联网行业的特点,程序员更要如此
-
不要给自己设限,勇于打破自己的圈子,前端要敢于向服务器端靠拢,不一定成为全端,但起码要知道前后端工作的流程,这也是facebook招人的要求
-
积极了解业内的发展动态,多参加些分享会,这点自己做得不太好,需要改进
14.纯文本的威力 && 15.shell游戏
-
工具可以增加人的才能,延伸人的才能
-
纯文本存储可以增加可读性,数据可以手工处理,也可以程序处理
-
GUI环境通常受限于设计者提供的功能,shell命令可以组合出强大功能,可以构建命令序列,使日常事情自动化
####个人理解
-
要学会使用工具,使用前期可能比较痛苦,但是慢慢地就可以体会到工具的好处,例如用git命令行进行版本控制时,初期总会出现各种问题,但是后期命令行的好处就会体现出来,这是图形工具所不能达到的
-
要学会制造工具,将繁琐的事情封装成一个工具,不仅提升效率,而且避免出错,例如现在使用browserify + React + Flux进行开发,环境搭建就比较耗时,那么是否可以写一个脚手架,实现环境搭建自动化
##测试
34.易于测试的代码
-
向硬件开发学习,从一开始就把可测试性纳入软件开发中
-
单元测试时,边界条件是需要重点考虑的问题
-
单元测试的目录结构需要清晰明确,便于其他人查看
-
测试用例给其他开发人员的好处:a.说明如何使用模块的功能;b.用于回归测试,代码修改后迅速知道是否正确
-
一个测试框架需要具备的功能: a. setup、cleanup设置 b. 拥有可用的测试方法 c. 分析出输出是否符合预期 d. 标准化的故障报告
-
测试应该是可以组合的
-
测试集不可能找出所有的bug,所以日志文件就是跟踪错误的一种机制
-
测试是一种技术,更是一种文化
-
test your software, or your users will
####个人理解
-
在开发初期,接口的设计就需要考虑可测试性,也就是说测试会影响代码的结构
-
单元测试的数据需要考虑边界条件、特殊条件,例如 a >= 0,那再测试的时候就要可写三个assert(a=10、a=0、a = -12)
-
测试框架的最基本工作原理:
// 借鉴jasmine的风格 function describe (text, fn) { try { fn.apply(...); } catch(e) { assert(text) } } function fn () { while (...) { beforeEach(); it(text, function () { assert(); }); afterEach(); } } function assert (expect, actual) { if (expect not equla actual ) { throw new Error(); } }
-
测试用例的编写需要考虑到成本、可控,因此mock就非常必要
-
要养成写测试的习惯,推动影响身边的人
43.无情的测试
-
Test Early, Test Often, Test Automatically.
-
编一点,测一点。bug被发现越早,进行修复的成本就越低
-
好的项目拥有的测试代码 > 产品代码
-
测试的种类:单元测试、集成测试、验证和校验、资源耗尽、性能测试、可用性测试
-
怎么测试:回归测试、测试数据、演练GUI测试、对测试进行测试、彻底测试
-
大多数测试应该自动完成,也就是对测试结果也进行自动解释
-
Find Bugs Once. 不断修复测试代码
####个人理解
-
不是专业的测试人员,加上互联网行业需求多、变化大,不可能每个需求都写测试用例,但是以下情况需要写测试:
a. 业务逻辑复杂、迭代频繁的需求—单元测试
b. 前端组件—单元测试、功能测试
-
目前在测试方向并没太多经验,现阶段还是边开发,边写测试用例
-
对测试结果的描述很重要,需要准确描述测试的作用,否则时间久、人员更换等因素,测试用例的作用就大大折扣
- 现阶段测试重点在单元测试、功能测试,尤其是对spy、mock、webdriver上还比较欠缺
编程技巧
22.死程序不说谎 && 23.断言式编程 && 24.何时使用异常
-
switch case分支中需要添加default分支,这样可以预测出现的问题
-
程序崩溃好于错误的代码
-
断言检查的是绝不应该发生的事情
25.怎么配平资源 && 26.解耦与得墨忒耳法则
-
资源使用后要及时回收,避免内存泄漏
-
使模块之间的耦合性降至最少,可以便于代码的维护
27.元程序设计 && 28.时间耦合 && 29.它只是视图
-
通过元数据配置和驱动应用,将细节放进元数据
-
元数据可以使代码具有适应性与灵活性
-
时间有两方面很重要:并发(同时发生)、次序(事情发生的次序)
-
弄清楚worlflow中的并行与串行环节
-
在设计的时候需要考虑到并发性
-
发布/订阅者模式可以降低代码的耦合性
-
MVC,使视图与模型尽量的分离
30.黑板
-
将系统的输入输出罗列出来,确定其中的工作流
-
对条件进行分区,降低不同区域的耦合性
个人理解
- 分区,在前端这块就相当于模块化开发,将一个大规模的需求划分为多个模块,每个模块尽量保持独立,这样整个系统代码的组织就非常有条理和可读性。
31.巧合编程 && 35.邪恶的向导
-
对于写出的代码要充分理解工作原理,否则编程就是在碰运气
-
不要只是测试你的代码,还要测试你的假定
-
IDE给我们带来好处的同时,也会造成我们懒于思考,自动生成的代码成为黑盒
-
不要使用不理解的向导代码
32.算法的速度
-
计算过程中,需要考虑算法的时间复杂度和空间复杂度
-
复杂度的计算只是数量级的计算,并不是精确地分析
-
最好的算法并非是总是最好,需要考虑面对问题的数量级
33.重构
-
代码需要演化,其不是静态的事物
-
早重构,常重构
-
重构的时候不要添加新功能,同时确保拥有良好的测试作保证,采取短小、深思熟虑的步骤