技术(加强)
编码能力,数据结构,算法
系统结构,操作系统,计算机网络,分布式系统
产品
对业务的理解,交互设计,产品数据统计,产品/业务运营
项目管理
研究和创新
Research && Development
一个系统工程师的培养需要至少8至10年的时间
在Coding的过程中,需要掌握:
把握问题的能力
建立模型的能力
沟通协作的能力
编码执行的能力
写代码,要先建立起品味,知道什么是好代码?好的代码时从哪来的呢?
首先,写代码时,严格要求自己的代码质量
然后,从好的开源项目中,看看好的代码是如何写的
一流代码的特性
鲁棒性
高效 fast
简结 simple 逻辑简单易懂
简短 small
可测试 testable
可重用 portable
可移植
可监控
可运维
可扩展
总结起来就是:
正确和性能
可读和可维护
可重用
运维和运营
写好代码的是个秘诀 林斌
可监控/可观测
可运维
可扩展(Scalable & Extensible) 前者是水平可扩展,后者是功能上可扩展
坏代码的味道
函数命名
变量命名
无注释
函数不是单一目的(多目的的代码,未来难以维护)
不好的排版(需合理使用空格和空行)
软件代码无法测试
好代码从哪里来呢?
代码不只是写出来的(需要前期的调研、思考、系统设计、模块设计)
编码前(经常被忽视或忽视的环节)
需求分析,系统设计(需完善)
编码中
编写代码,单元测试(需完善)
编码后
集成测试,上线部署,持续运营/迭代改进
需求分析和系统设计
前期多投入,收益更大。
修改代码和修改文档,那个成本更高?
需求分析:做什么 what
系统设计:怎么做,为什么这么做?
需求分析
怎么用寥寥数语勾勒出一个系统的功能?
???
误区1:需求分析是产品经理的事情,和RD有关系?
深入到产品需求评审,激起做产品的激情。
误区2:在需求分析时,大量考虑系统实现的细节
忽略需求分析,直奔系统设计,甚至代码实现细节
危害:
阻碍 需求分析 的聚焦
实现决定需求
需求分析的重要性
导弹 vs 炸弹
需求分析的地位:导弹中的导航模块
现实情况:有太多的炸药(开发资源)在爆炸在了错误的地方
系统设计
系统架构,模块设计,接口定义,数据定义
关键算法,设计思路(why)
设计文档的分类:
1、总体设计文档
2、子系统设计文档
3、接口定义文档
4、关键算法说明文档
5、数据库表设计文档
......等等
每个设计文档都有自己的聚焦和读者,不同需求的读者仅读各自的文档即可。
系统架构
静:系统如何组成,功能在这些组成部分之间如何划分?
动:各子系统如何联动,如何完成任务/流程?
细:更详细的刻画出系统的全貌
大致可分为两种:
总体设计:大系统的架构
模块设计:子系统的架构
系统设计的方法
每个组件(子系统/模块)的功能都必须足够的专注和单一
功能的单一是复用和扩展的基础
子系统/模块之间的关系应该简单而清晰
软件中最复杂的是耦合(为什么全局变量要极力避免?)
系统设计的约束
资源的限制:计算,网络,存储,IO
比如拿时间换空间,计算资源来换取存储,存储不够用压缩来解决。
需求是系统设计决策的来源
在设计中,经常需要做trade-off
需求是决定的重要依据
模型/抽象的思维能力
思考的重点:概念,模型,数据结构,算法
脱离开代码的细节:语言 and 函数
扩展阅读:
google三大系统经典论文
GFS
BigTable
Map Reduce
重点看一下:
怎么描述问题和出发点
怎么描述模型
怎么描述系统架构
关于接口(interface)
系统对外的接口,比系统实现的本身还要更重要。
合理的设计对外api接口,是本学问。
这个问题被多数人忽略!!!
why?
接口定义了功能:如果功能不正确,系统就没有用,更不会有人使用这个功能。
接口决定了外部关系:相对于内部,外部关系确定后非常难以修改,大点的软件会有ABI测试(接口兼容性)(越被人广泛使用的软件,越难以修改接口)
哪些是接口
模块对外的函数接口
平台对外的api
系统间通信的协议
系统间存在的依赖的数据
设计和修改接口,需要注意什么?
合理好用
修改时尽量向前兼容
代码也是一种表达方式
代码主要是写给人看的
编程规范(遵守公司的编程规范,一些语言相关的注意事项)
模块(module)
模块:数据,函数,类
c py go 一个文件就是一个模块
模块需要有明确的功能
高内聚,松耦合(经常提起,要铭记)
怎么切分模块,是一个需要谨慎考虑的事情
数据类的模块
过程类的模块
模块的重要性
好的模块划分是软件架构稳定的基础
模块划分的好,日后的修改成本很小,和房屋内部装修差不多,否则就要推倒了重新改房子。
减少模块间的耦合-》降低软件复杂性
清晰的模块有利于代码的复用
模块切分的误区
误区1:所有的代码放在一个模块中,因为规模太小
切分模块的原则和代码规模没关系
程序的规模在早期无法预估
误区2:将所有附加功能都放到utils中
在utils中,也要根据功能来进行细分
误区3:从过程的角度出发考虑模块的划分
应该首先从“数据”的角度出发考虑
类和函数
推荐:和类的成员变量无关的函数,可作为一个独立的函数,便于未来复用。
函数
函数描述的3要素
功能描述:函数做什么的
传入参数描述:含义,限制条件
返回值描述:各种可能性
函数的规模
要足够的短小
写好程序的一个秘诀,把函数写的简短一点(除非性能考虑)
bug往往出现在那些非常长的函数中
函数的返回值
True,False
逻辑判断型函数,表示“真”或“假”
is_white_cat
OK,ERROR
操作型的函数,表示成功或失败
如data_delete
Data,None
获取数据型的函数,表示“有数据”或“无数据”
如int get_data(void** data)
glang的返回值形式:(data,error)
函数:单入口单出口
多线程下数据表的实现:
可使用一个内部函数来实现“单入口单出口”
代码块
讨论范围:一个函数内的代码实现
思路:把代码的段落分清楚
形式的背后是逻辑(划分、层次)
注释不是补出来的
我习惯先写注释,然后再写代码
备注:一个在代码表达不好的同学,在其他表达上一般也存在问题,如文档,email,ppt,口头表达
怎么修炼成优秀的软件工程师?
学习-》思考-》实践
知识-》方法-》精神
基础是治学之根本
有了足够的时间以后,必须把身体和技术好好磨练下。