第一章:行业地图
特质:简单务实,极致创新
软件工程师不是只会搬砖的码农,而是一群简单务实的人,他们通常专注于自己喜欢的事情,很少关注外在的东西,So,衬衫、牛仔裤和背包是你常见他们的着装;他们是一群严谨的人,他们倾向持续改进追求极致,在他们的眼里,满分的位置是不断上调的;他们是一群热衷于创新的人,这是写在他们职业的基因里的,同时还是一群非常好奇、讲究逻辑、热爱分享的一群人;总结一句话:“普世低调的创新精神,理想主义的工匠精神”
软件工程师的薪酬|底层|选择
软件工程师是我国城镇人口中平均薪资最高的群体,稳定地保持在所有行业的前列,同时在全世界范围看,软件工程师都是高薪职业。软件工程师是一个成就感驱动的行业他们通常关心的是,自己做的事是不是能对社会产生真正的影响,是不是真的改变了这个社会,改变了人们的生活。一线和一线城市,有着软件工程师难以割舍的巨大机会,这里有更高的就业机会、有更高的学历溢价和工作经验溢价。
现实:为什么会有996?
996是中国软件工程师特有的现象,在国际上并不是这样,原因有二,1.在国内,互联网正处于原始积累阶段,或者叫圈地运动阶段,这其实是一种低维度的竞争,导致大家拼命扩军,讲究唯快不破,而国外同行他们比的不是谁更快,而是谁能拿下技术制高点;2.中国很多公司的组织管理能力不足,组织效率低下,导致软件工程师白天不停地被打断,杂事一大堆,只能晚上加班。
进阶:软件工程师的四大台阶。
新手阶段强调执行力,按照方法一步步去做,保质保量完成就可以了;进阶阶段强调设计能力,你需要自己把具体的问题抽象、拆解,并独立设计解决方案,还要向内精进,不断搭建自己的知识体系;高手阶段需要融会贯通的能力,你需要把技术的演进、需求的变化、系统的发展等多个维度综合起来考虑,大神阶段需要沉淀方法论,这个方法论不只适用于当前的领域,还可以解决另外的问题。
周期:是否存在35岁的坎儿?
这个行业不存在真正年龄的坎儿,只存在能力的坎儿。其实所有的行业都是如此,只是软件工程师这一行的容错率比较低,你可能到岁数就干不下去了,而在别的行业还能混下去。对于35岁左右的人来说,行家阶段的能力已经比较底层了,大家要想接好社会交过来的重担,大概得到贡献者这个级别才行。(行家-贡献者-创始人或合伙人)
挑战:持续学习是刚性要求。
软件工程师工种大致分为六个方向:交互、系统、算法、数据分析、测试、运维。软件工程师这个职业工种多而且新工种频繁出现,知识积累促进技术进步,技术进步又不断催生新的工种。(在最后推荐的一部分书籍清单非常多)在未来,可能各行各业都会有软件开发部门,软件会成为各行各业的基础设施,软件工程师也会成为各行各业的基本人才配置,还有一个大胆的预测,一两代后,孩子们从小就很熟悉编程,软件行业会消失,因为所有人都会做,想想打字员这个行业。
第二章:新手上路
入行前
基本储备:入门比学的语言和工具。
入门推荐语言:Python、JavaScript ,入门比学工具:操作系统Windows、编程工具:Visual Studio Code ,正式入门语言:Java.此外,程序当中的归纳、递归、逻辑等都跟数学分不开、数学建模、图论、抽象代数、拓扑学、运筹学、博弈论等这些都是机器学习、AI的基础,另外,学好英语是你编程技术提升的关键。
选择平台:去面向未来、技术驱动的公司。
高速成长的公司正需要人才,它需要解决的问题也是新的,你会跟着公司一起去解决这些问题,你的能力会越来越强;同时生涯初期,软件工程师最需要先充电,把自己的基础打好,培养起扎实的编程能力和良好的职业素养,所以选择一家技术驱动、以技术文化为主导的公司最好。
认识自己:找到适合自己的路线。
了解自己的才能找到适合的路线,“特长-兴趣-方法-勤奋”这几个路线中,先从特长、兴趣、方法一层层筛选、挖掘的方法。如果前三者你都没有,还能做的事是勤奋,勤奋注定比较劳累,也可能被淘汰出局,因为随着你的年纪越来越大,你的勤奋也会变得越来越不值钱,因为年轻人会比你更勤奋、比你斗志更强、比你要钱更少,但只要你勤奋,至少能够自食其力。
编程
公司差异:即使没有规范,也得自我要求。
国内外每家公司都有大量的团队协作场景,因此大家共同遵守规范是非常重要的。作为新人,在编码之前先熟悉这些规范,开发时严格遵守就好了,没必要逆着规范做事。一般来说,一套完整的规范包括编码规范、设计规范、生产规范。你要么花时间在写代码上,把代码质量提上去,要么花时间在后期修理上,靠运维去修补代码质量差的问题。
优质代码:好代码没有止境
优质代码分三个等级:初级为可读,命名要好、布局清晰、注释明确、代码不重复不要有反逻辑等基本功;中级为可扩展,意思是可维护,不必因为未来的修改大动干戈,甚至不改主干代码就可以实现修改;高级为可重用,优质的代码写出来可用在很多场景。以上为专业术语,新人阶段不一定能理解并掌握,放这里是希望你明确精进的方向。
整洁代码不是写出来的,而是读出来的。
也就是说,不是写代码的人说自己的代码整洁就整洁,而是读的人觉得整洁才算整洁。核心在于,你心里要装着将来要阅读这段代码的人,从方便阅读的角度去布局、设计,而且考虑得尽量全面一些,最好是不仅考虑当下可能会遇到哪些问题,还能预想到明年会有什么需求,并给后来得人一个大致的方向,为将来的可扩展性预留空间。
编程原则:教科书没有告诉你的“为什么”。
1.避免重复原则。这样可以降低程序的复杂度,又能减少维护的工作量。很多问题你只有把它抽象成数据模型才好解。用一种方法解决多种问题,是避免重复原则的精髓,所以写代码写到高级阶段,其实是做数学建模。而代码操作员从来都是case-by-case(逐个解决)的方式,通过使蛮力来完成工作。
2.单一职责原则。即一个类或者模块应该有且只有一个职责,各司其职。可以把复杂的问题简单化、模块化,从而降低问题的复杂度,让你更容易实现和驾驭,还可以不断复用的原则,让你像搭积木一样拼装出整个世界。
3.高内聚、低耦合原则。让每个模块做到独立,做到精益求精,同时把模块的耦合降到最低,不会因为动了一个模块,而导致其他模块出问题。
4.关闭原则。通过一种通讯协议来解决我们互不往来,但是可以共同连接到一个协议上
测试
全面思考:做测试比写代码难。
做测试比写代码难多了,因为做测试考验的是一个人全面思考的能力。一般来说程序测试包括单元测试、功能测试、集成测试、非功能测试、回归测试。
单元测试一般是白盒测试,单元测试是离问题最近的地方(家庭);功能测试一般是黑盒测试,测一测各个模块合在一起能否正常运转(社区);集成测试像城市,有点像测一测整个城市的交互。非功能测试,用户不直接关心,确实开发者要关心的部分,比如性能测试、稳定性测试、健壮性测试、破坏性测试、可用性测试、灵活性测试等;回归测试是把以前做过的测试以及犯过的错误在测一回。
程序测试:对软件工程师的基本要求。
测试要自己做,尤其不能让用户成为你的测试工程师;除了测试基本输入意外还要努力构想更多的边界条件;测试接口定义的程序语意,而不是当前实现的具体行为;对重要模块,编写的时候要做到基本性能测试;对程序交付以后出现的问题和Bug,要构建相应的测试程序并提交代码库,保证以后回归测试可以自动运行这个测试。
改Bug
执行任务:从改Bug开始
实际工作中遇到的Bug比学生时代遇到的复杂度多。不要小看改Bug,你只有在海量的数据里找到Bug,学会修补,避免出错,才能知道代码的真实环境里是怎么运行的,才能找到一名软件工程师的工作体感。
定位Bug:像侦探一样发现问题
Bug可以分为“好的”Bug和“糟糕的”Bug,所谓“好的”Bug指容易复现的Bug,只有局部的逻辑错误;“糟糕的”Bug是根本不知道问题处在哪儿的Bug,容易出现在多线程程序、并发程序、随机算法、分布式程序里,且不容易复现。方法有:模拟Bug场景、二分法、测试工具、极限测试......
修复Bug:务必小心谨慎
重构时的方法:看整体、改细节、review之前的review。你要思考怎么做才能吸取经验教训,将来在类似的问题上不再栽跟斗,以及采用的方法、使用的工具是否还有可以改进的方法。
成长论
拆分任务:动手工作前,先做任务分解。
假设你要写一个程序,1.抓住重点,找到任务主干;2.按照单一职责原则对任务进行拆解,罗列功能点;3.每个功能点对应一个下程序或小模块,写出模块,最后把他们拼装起来。
阅读代码:重要的不是写代码,而是读代码。(对新人来说)
在阅读别人写的代码时,不要眉毛胡子一把抓,积累以下代码值得重点关注:被反复使用的代码;2.穿越时间的代码;3.好调试的代码。
找到捷径:通读牛人代码
牛人的代码会让你明白什么才是真正好的代码。1.牛人的代码会非常清晰、明确、易用,自带使用说明,代码考验的是逻辑,先有清晰的逻辑才能有正确的实现。2.牛人的代码非常高效;3.牛人代码的通用性很高,可扩展;4.牛人的代码都是自带风格的。
追本溯源:多读文档,多读书。
书和文档是人对人说的话,代码是人对机器说的话,所以如果你想知道人为什么要这么写,你就应该去看书、看文档,书和文档会告诉你为什么,告诉你背后的原理。
重在过程:学习牛人的方法,别抄答案
问题总在变,技术也会变,但优秀的解题思路不变。1.在高手帮你review代码的过程中学习。2.跟高手一起解决难题,因为只有遇到难题的时候,高手才会把最好的水平拿出来,他会使出浑身解数,最厉害的东西全部展现在你的面前。和非常厉害的同事在一起工作,你会在进阶的路上走得非常快。
天下程序员一家亲,在所有职业里,软件工程师是一群特别爱分享的人。
第三章:进阶通道
设计程序
需求分析1:避免X-Y问题
这个世界有太多X-Y问题。做需求分析,首先要解决的就是找出X问题,有时候X问题已经被层层包裹了,所以,你要仔细地追问需求方,了解他们真实需求和初衷。
需求分析2:明确模糊不清的问题
方法一:明确问题的边界条件。例如:“金额大一点的时候,就需要人审批”,你要追问,什么叫大?3000叫大吗?还是5000元,还是10000元。只有把边界条件明确地说出来定义出其中的规则和决策方式,软件工程师才能写出程序来。
方法二:关注不可预测案例。过程中你会遇到很多稀奇古怪的问题,遇到这些问题,你必须一一明确下来,让整个程序都跑通,是一个非常重要的能力。
设计程序:学会谋篇布局
软件工程师设计程序更多需要的是谋篇布局的能力、思考总结的能力。别人只给你一个问题,你要给出合理的、科学的解决方案。
高度抽象:设计需要抽象能力
音符、字母、数学就代表了最高级的抽象。在众多的实例、案例中归纳总结出通用的方法和规则,是抽象的核心思想。抽象是简化事物,抓住事务本质的过程。软件开发本身就是一个不断抽象的过程,我们把业务需求抽象成数据类型、数据模型、模块、服务和系统。对软件抽象来说方法有过程抽象和数据抽象。
设计师分为原型设计和架构设计。
原型设计1:从最难的做起。
原型设计:面向用户,相当于提前打个样,比如可以演示一个订餐系统里的界面长什么样,优惠券在哪等。先做最难的部分,既能提早发现问题,又能节省开发时间。(原型设计2:原型设计的关键是接口-略)
架构设计1:分而治之,理清思路。
做架构分析很考验一个软件工程师的功力。现实中有些软件工程师连流程图都不会画,就是因为根本没想明白自己想做什么。
架构设计2:考虑异常情况和极限情况。
例如考虑断电了怎么办,光纤被挖断了怎么办,测试极限比如阿里每年双十一高峰能否承受住。
技术调研:寻求最优解决方案
调研做的好不好,和阅读代码的能力高度相关。分析优缺点,结合场景才有效,因为优缺点只有在场景下才成立,如果缺少场景,那么只有特点没有优缺点。
项目管理
软件工程:不同的开发模式
项目管理很多行业都有设计,无外乎项目排期、资源分配、节点把控、风险管理等内容。
不同的开发模式对应不同的管理方法。一般有瀑布式开发模式、敏捷开发模式、班车模式、分布式微服务开发模式。互联网公司常用班车模式,就是我的发布每周一次,如果你能赶上就跟着一起发,如果赶不上就等下一班车。
流程管控:用火车头模式避免研发延期
火车头模式:通常以三周为一个周期规划需求,一个需求从提出开始,三周后必须上线。同时每一周都会有一个版本发出去,这周发的车,实现的是三周前的需求,以此类推,需求是并行着实现。目的是保证火车不会延期,不会以为某些需求没有做好、没有完善,就延期所有的需求。
验证效果:做A/B test,用数据说话
比如APP要从2.5版本更新到2.6版本,一开始不会让所有人都更新,而是只开放20%的更新权限,里面可能会有一半完成更新,然后对这些用户作为对象进行观察。通过数据判断新版本的留存会不会涨,如果涨就很放心,可以按照流程正式发版。
监控打磨:上线前做好监控和压测
设计在测试环境跑起来之后,你的监控会有各种各样的指标,发现问题时会自动报Bug,报出的Bug就进入Bug系统。工程师可以修改Bug,再提交到监测环境不断迭代到修好。监控之后做压力测试,一般可以上10倍压力,经得住说明系统没问题才能正式发布。
团结合作
外部沟通:知道怎么“规训”业务
你要告诉业务,不要把技术仅仅当作需求解决方;你要告诉业务,不要直接将需求丢给技术,而是要告诉技术真正想解决的核心问题是什么;你要告诉业务,今天我们面临的所有问题都不是单纯的技术问题,大家一起努力,才能从根本上解决问题。
内部协作:平衡前台团队和中后台团队
离业务近的同学觉得离业务远的同学做的东西没有用,离业务远的同学觉得离业务近的同学做的东西太短视,这其实是一个长期目标和短期目标平衡的问题。前台团队是1,中后台团队是后面的0,因此中后台团队需要围绕着1去建设,去创造价值,去解决前台的需求和痛点,甚至在前台团队还没有看到之前就遇见一些可能发生的问题,从而给前台团队提供有价值的服务,这样双方都能达到一个比较好的平衡。
学习进阶
直击内核:打牢基础,以不变应万变
过去20年来大家都说技术日新月异,但其实原理都没变,变的只是形式,核心还是这些内容。是否掌握这些原理直接影响你能飞多高,因为懂原理的人和不懂原理的人能解决的问题完全是两个层级。
搭建体系:用知识树系统学习
用好知识树:任何知识,只在点上学是不够的,你需要在面上学,这叫系统地学。
探索知识缘由:能够知其然,知其所以然,才能把一个知识掌握牢固;掌握方法套路,学习的目的就是为了掌握更为高级的方法和解题思路。
主动学习:提高你的学习效率。比如讨论、实践、教授给他人。