这就是软件工程师
一行业地图
特质:简单务实,极致创新
在国内,互联网行业正处于原始积累阶段,或者叫圈地运动阶段。国内绝大多数公司是流量驱动型的,大家都在玩营销、抢流量。就像人类历史上的蛮荒时代一样,各大公司都在不停地圈地、占领领土,它们占领领土的方式是你有什么,我也要有什么。这是一种低纬度的竞争
在国外,它们不以圈地运动的方式生存、竞争,因为它们的危机感并不来源于流量的缺失,而是来源于技术的不领先。这样公司会回归底层,更精耕细作一些。相信,当国内的原始积累差不多了,接下来也该走向精耕细作的阶段了,该从劳动密集型走向知识密集型。
996原因之一——(组织管理能力)会议太多且时间长。注:会议不是解决问题的,因为争论太多问题难以解决,并且浪费时间。会议是用来发现问题,跟进问题的;要求在开会前一定要有一定的议题和议案。
几乎所有人都会混淆行动与进展,混淆忙碌与多产。 ——《代码大全》
软件工程师金字塔的四大台阶:
新手阶段:执行力进阶阶段:设计能力 (将一个抽象的问题,拆解,并独立完成解决方案)
高手阶段:融汇贯通的能力 (架构师 外在需求,内在技术, 未来方向的预判)
行业大神阶段:沉淀方法论和开创新领域的能力
如果工作 10 年还达不到一个资深工程师 的水平,某种意义上被淘汰也是不可避免的。
公司核心成员分为以下几种类型,和他们需要具备的能力
创始人/合伙人——①做出贡献 , ②带动团队 ,③创新优化, ④前瞻能力 ,⑤捉重点,简化,标准化
贡献者——①探路能力 ②贡献方法 ③解决难题 ④提高标准
行家——①降低成本 ② 提高效率 ③防火能力
选择平台时——这家公司是否面对未来,是否受技术驱动
计算机和互联网的发展都太快,如果要选择,一定优先选走在未来航道上的那些快速发展的公司。
认识自己:找到适合自己的路线——特长 兴趣 方法 勤奋
程序——需求分析 设计 编码 测试
规范——编码规范 设计规范 生产规范
优质代码的三个等级
初级:可读
中级:可扩展
高级:可复用
所谓复杂度,一般由业务逻辑、控制逻辑和数据逻辑组成,一旦把三者揉在一起,程序一定会乱,并且复杂度急速上升,业务逻辑决定了复杂度的下限,控制逻辑决定了复杂度的上限,两者如果缠绕在一起,复杂度就呈现级数攀升。
整洁代码的建议
遵守公司的编程规范
写出干净的接口
编程中的注释更像是一个说明书,会明确代码的使用位置,在某个地方是否可用
在程序的世界里,抽象是很重要的事。除了对于技术本身(包括数据类型、数据结构、算法、并发模式等)的抽象外,还有对业务的抽象,比如对业务流程的抽象、对业务模型的抽象、对业务数据的抽象。这是真正的软件工程师与“代码操作员”最大的不一样。
为什么一直坚持编程原则:
避免重复原则 用一种方式解决多种问题
单一职责原则 ——各司其职,分工
高内聚,低耦合——减少依赖
开闭原则——对于修改是关闭的,对于扩展是开放的
编程的原则是解决问题,所以对于上面的原则我们需要了解,但是在解决问题的时候选择最能解决问题的编程思想,不必坚持教条原则。
对于代码的测试
单元测试,一般是白盒测试 对于内部零件的测试
功能测试,一般是黑盒测试,对于整体的测试
集成测试 模块和模块,系统和系统之间的测试
非功能测试 性能,安全,稳定性等 这是开发者比较关心的
回归测试 把之前的错误或者测试在进行一边 ,目的是为了确保代码或者配置的修改,回归测试成本较大
关于测试的一些小建议:
做测试最好的方式不是用人工,而是写代码
想要做好测试,先训练自己全面思考的能力。
Bug
好的Bug 容易复现的Bug
糟糕的Bug根本不知道问题出在哪里的Bug 这种Bug容易出现在多线程程序,并发程序。随机算法,分布式程序里,并且不容易复现。
定位Bug 操作
模拟Bug场景
二分法
调试工具
极限测试 不同条件下进行测试
小黄鸭测试 对代码进行逐行解释
修复Bug
梳理整体设计、理解代码,在梳理时可以对老的代码跟不上需求的代码进行重构。重构(看整体,改细节,回顾修复过程)
读代码
读代码时,值得关注的重点代码
被反复使用的代码
穿越时间的代码
好调试的代码
“Code Tells You How, Comments Tell You Why" (代 码告诉你怎么做,文档告诉你为什么)——杰夫·阿特伍德
根据目的决定读书还是读代码
1.读书
当你想要了解一种思想、一种方法、一种原理、一种思路、一种经验,读书和读文档会更有效率一些,因为其中应该会有作者的思路的描述。
2.读代码
如果想要了解的就是具体的细节,比如某协程的实现、某个模块的性能、某个算法的实现。
新手阶段的工作重点是执行任务,进阶阶段重点就是你要独立完成一个工作模块、独立设计程序,需要自己找到解决问题的方法。
第三部分进阶通道
程序设计:
需求分析中,避免X-Y问题,及双方信息沟通不当导致的问题。
在需求分析中,需要明确问题的边界条件。只有把边界条件明确地说清楚,定义出其中的规则和决策方式,软件工程师才能写出程序来。
关注不可预期案例
设计需要抽象能力
从众多的实例、案例中归纳总结出通用的方法和规则,是抽象的核心思想。
抽象的分类
过程抽象
所谓过程抽象,就是把要解决的问题分解为一个个小的子问题,然后用一个个独立的代码模块来完成,再把这些代码模块组织起来构建成一个复杂的系统。
数据抽象
而所谓数据抽象,就是将复杂数据的使用和它的构造分离开来,数据结构用于定义数据的构造,数据接口用于定义数据的使用。通过隐藏数据对象的内部特征,定义数据的外部使用,大大降低系统的复杂度。
原型设计
先做最难的部分,既能提早发现问题,又能节省开发时间。
原型设计最根本的哲学不是实现功能,而是要注重接口。
架构设计:把需求进行抽象和分解
做架构设计之所以要分而治之,并采用“高内聚,低耦合”原则,主要有两方面的好处,
有利于将清思路,让设计变得清晰
有利于团队分工,让每个人做自己擅长的事情,各自负责不同的模块,不用相互扯皮
架构设计是将需求开发和设计开发连接在一起的环节,架构设计的好坏直接决定软件开发项目的成败。
架构设计需要考虑
考虑系统没回复异常情况
考虑系统的极限情况
在设计需求时遇到自己之前没有做过的需求时,需要进行技术调研:
技术调研的心得体会
调研做得好不好,和阅读代码的能力高度相关
分析优缺点,结合场景才有效
项目管理:无外乎项目排期、 资源分配、节点把控、风险管理等内容
项目管理的管理方式:
瀑布式开发模式 :一层一层的开发
敏捷开发模式 :将项目进行拆分,然后进行开发
班车模式 :类似更新迭代
分布式微服务开发模式:也就是把代码库、数据库全部分开,每个服务都由一个全功能的小团队(前端、后端、开发、测试、运维、产品)来负责,这样就可以把个大部门拆分成多代码更容易维护和上线
验证效果:做A/B test 用数据说话
A/B test是我们发App时测试新增需求效果好坏的一个利器。我们会用增加了新需求的版本A,和没有增加新需求的版本B,测试用户的不同反应。
测试需要观察的内容:
(1)新增需求会不会损害既有流程,比如会不会导致崩溃、内存泄漏等
(2)如果不会损害流程,是否存在其他问题,比如新增功能本身不好用等
监控打磨:上线前,做好监控与压测
外部沟通:知道怎么“规训”业务
你要告诉业务,不要把技术仅仅当作需求解决方
你要告诉业务,不要直接将需求丢给技术,而是要告诉技术真正想解决的核心问题是什么
你要告诉业务,今天我们面临的所有问题都不是单纯的技术问题,大家一起努力,才能从根本上解决问题
内部协作:平衡前台团队和中后台团队
长期目标和短期目标平衡的问题
中后台团队一般都希望把系统尽可能做大做深。
前台团队的目标主要是怎么尽快给业务交付功能。目标不一致,两个团队的诉求不一样,就很容易发生矛盾。
学习进阶
直击内核:打牢基础,以不变应万变
变化都是表面的东西,内在的东西其实变化不大
搭建体系
用好知识树
探索知识缘由
掌握学习套路
主动学习
被动学习:浅度学习 听讲 ,阅读,视听, 演示
主动学习:深度学习 讨论,实践,销售
高手修养
上升通道:技术路线和管理路线
技术路线指的是在特定的技术领域做深入的探索和研究,不涉及管理工作
管理路线更侧重统筹团队完成一个个研发项目,离技术研究工作比较远
两种不同组织结构的软件公司
小商品工厂:这种公司是不需要技术路线的,项目经理拿钱更多,因为这种公司就是做项目的,它希望项目经理能够带得动大家
电影工作组:是做产品的,它们做产品就像拍电影一样,有导演、编剧、演员…所有人都可能成为leader,都有自己的晋升通道,这种公司里有管理通道,也有技术通道
业务上的精进
前瞻能力:前瞻能力不仅要求软件工程师看到系统的演进,还要看到未来的趋势,对未来有预判,根据预判对技术选型做一些决策
如何拥有前瞻能力:
知识的广度
多做跨行业的交流,跳出自己的圈子
权衡利弊:取舍能力:自己要做什么,不做什么
做好取舍的关键:
明确目标
学会预测
面对技术难题:
考虑行业及公司发展方向
与自己工作相关但是不是很懂的问题,需要继续学习的领域
技术难题之所以难,是因为情况复杂,没有通用的解决办法
关键决策:技术选型的六大要素
技术选型:选择一种技术座位项目的实现方式
宏观因素:
看这项技术解决的是不是大问题
看这项技术解决问题的方式是否让人有想象空间
微观因素:
看有没有大公司撑腰
看有没有很好的技术社区 ——技术要有人捧
看有没有杀手级应用——具有颠覆性的技术
看有没有经历十年以上的时间——成熟的技术
代码评审需要关注的问题
设计:代码是否经过精心设计并适合系统?
功能:代码是否符合开发者意图?代码对用户是否友好?
复杂性:代码是否可以更简洁?未来其他开发人员接手时,是否易于理解与易用?.
测试:代码是否经过正确且设计良好的自动化测试?
命名:开发人员是否为变量、类、方法等选择了明确的名称?
注释:注释是否清晰有效?
风格:代码是否遵循了谷歌的代码风格?
文档:开发人员是否同步更新了相关文档?
代码评审:包括可读性,可维护性,可重用性,程序逻辑以及对需求和设计的实现等
管理者的工作不外乎三件事:
在专业上给下属指导
对任务进行拆解,组织团队完成目标
日常的组织、管理工作
管理者需要关注长期目标
判断哪些事情需要长期投入,做了之后能够产生规模效应
管理者要坚定地投入到长期目标中
行业大神
丹尼斯·里奇——C语言之父 (保持简洁)
——UNIX 系统的联合发明人
如果说乔布斯是可视化产品中的国王,那么里奇就是不可见王国中的君主。乔布斯的天才之处在于,他能创造出让人们深深喜爱的产品,然而,却是里奇先生为这些产品提供了最核心的基础设施,人们看不到这些基础设施,却每天都在使用着。
——麻省理工学院计算机系的马丁教授
林纳斯·托瓦兹——Linux之父
——开源运动的发起人
——发明了Git版本控制器 (每个软件工程师都知道的GitHub,就是基于Git构建的)
吉多·范罗苏姆——Python之父 (允许不完美、保持开放)
衍生出来的设计原则:
(1)不必太担心性能,必要时再来优化
(2)别追求完美,“足够好”就是完美
(3)有时可以抄近道,尤其是在你之后能改正的情况下
Python 设计原则
(1) Python不能被某个平台绑定,有些功能在一些平台上没法用可以接受,但核心功能必须跨平台
(2)支持并鼓励用户写出跨平台的代码,但也不拒绝某个平台的特有能力或资源--这一点与Java形成鲜明对比;这就是软件工程师
(3)一个大型复杂系统,应该在不同层级都支持扩展,使不论是老手还是新手都尽可能地发挥自主性
玛格丽特·汉密尔顿——拯救人类登月计划
希望给予做软件的人们以尊重,让大家与做硬件的人一样,在这个宏大的工程里各司其职 ——玛格丽特·汉密尔顿
杰夫·迪恩:开创分布式系统
有效解决大量数据的存储问题
今天我们看到的整个云服务运用的分布式存储、分布式计算,以及一些硬件、网络技术,都是基于迪恩的这个方向产生、蓬勃发展的
法布里斯·贝拉:一个人就是一支队伍
从数字信号处理到处理器仿真再到数学创新,以及之间的一切。他创造了一系列大家耳熟能详的开源软件
QEMU(一款可执行硬件虚拟化的开源托管虚拟机)
FFmpeg (一个包打天下的视频解码器和转换器,可以把任意格式的视频转换成其他格式,没有这个项目,就没有今天被大家广为使用的腾讯视频、YouTube等,它的诞生让计算机视频和音频有了大幅度的进步)