许世伟老师架构课笔记分享
桌面开发的未来——让一个八岁刚刚上学没多久的小学生去做生产级的应用
代码即文档。如果能够用代码约束的事情,最好不要在文档中来约束
架构分解的评判标准
功能的使用界面(或者叫接口),应尽可能符合业务需求对它的自然预期;
功能的实现要高内聚,功能与功能之间的耦合尽可能低。
功能实现准则-高内聚低耦合
对底层基础模块或者组件的低耦合标准
对底层业务的依赖是 “通用” 的,尽量不要出现让底层业务模块专门为我定制接口
依赖的业务接口的个数少,调用频次低。
前后端关注的重点和衡量指标
桌面开发(大前端)的代码量大,代码变更又很频繁,所以它对程序员的第一要求,不是质量,而是数量上的需求极大。起点门槛低,天花板高
服务端开发并不是一上来就有的,是互联网出现后产生的新分工。它并不负责用户交互,所以在需求提炼时可以做到极强的可预测性。因而服务端的第一挑战往往不是快速响应,而是性能和稳定性等质量需求。
是在网络层(IP 层)做负载均衡
LVS 支持三种调度模式
VS/NAT:通过网络地址转换(NAT)技术做调度。请求和响应都会经过调度器中转,性能最差
VS/TUN:把请求报文通过 IP 隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。这种做法性能比 VS/NAT 好很多
VS/DR:通过改写请求报文的 MAC 地址,将请求发送到真实服务器,真实服务器将响应直接返回给客户。这种做法相比 VS/TUN 少了 IP 隧道的开销,性能最好
授权
一种是基于 Token,一种是基于 AK/SK
Token 授权和 Session 授权的差别只是应用场景不同,一个用于 API 层,一个用于 Web。而这也导致承载它们的机制有些不同,Token 授权基于 HTTP 的 Authorization 头,而 Session 授权则基于 Cookie
详细设计的产物
现状与需求
现在在哪里,遇到了什么问题,要作何改进。
需求满足方式
要做成啥样?交付物的规格,或者说使用界面(接口)。
怎么做到?交付物的实现原理。
编程哲学,叫 “速错(Fail Fast)”,它的核心逻辑是,一旦发生非预期的错误时,应该立刻退出程序,而不要尝试为该错误去写防御代码。存储不要做速错
书籍推荐
Brian W. Kernighan 写的《Go 程序设计语言》
服务治理
发布
少量发布、频繁发布
重视质量,尊重流程
监控系统的 4 个黄金指标。
延迟
流量
错误
饱和度
故障域与故障预案
怎么才能避免这类需要达到某些特定的条件才能爆发的问题?严谨的白盒代码审查和全面的测试覆盖率提升,才有可能消除此类风险,自适应节流算法至少理论上是这样。
负载均衡实例的 IP 从 DNS 解析中去除,就可以消除掉这个故障。这理论上可行,但是我们实际很少会这么做,原因和前面说的 DNS 解析的生效时间过长有关。我们不能够接受长达 1 小时的入口级故障。比较好的做法是,所有负载均衡实例的 IP 是 VIP,即基于虚 IP 技术。关于 VIP 技术的介绍
故障排查过程
对一个经常需要进行排除故障的人来说,让他去解释 “如何” 去进行故障排查是一件很难的事情
新手们常常不能有效地进行故障排查,是因为要做到高效排查的门槛比较高。理想情况下我们需要同时具备两个条件:
对通用的故障排查过程的理解
对发生故障的系统的足够了解
我们将故障排查过程定义定义为反复采用“假设 - 验证排除”手段的过程,针对某系统的一些观察结果和对该系统运行机制的理论认知,我们不断提出一个造成系统问题的假设,进而针对这些假设进行测试和排除
服务过载保护
自适应节流算法
max(0,(requests-k*accepts)/requests+1)
默认 K=2,只让服务端处理 50%的请求。k=1.1 即服务端处理 90%的请求
架构思维
架构设计的基本准则
KISS:简单比复杂好;
Modularity:着眼于模块而不是框架;
Testable:保证可测试性;
Orthogonal Decomposition:正交分解。
架构师的修炼之道
从实悟虚,从虚就实,运用得当方得升华
好的架构师具备化腐朽为神奇的能力
需求分析需要有更强的空杯心态,去认同别人
架构的本质是业务的正交分解
开闭原则
模块的业务要稳定,模块的业务遵循只读设计
模块的业务变化点,通过回调或者接口开放出去,交给其他业务模块
它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。
我们博览群书,为的就是不拘于一隅,串联我们自身的知识体系,形成我们的认知框架
架构规则重要。规则可能会因为环境变化而发生变化,会过时。但是架构思维的内核不会过时。
重构,不只是一个架构的合理性问题。它包含了架构合理性的考量,因为我们需要知道未来在哪里,我们迭代方向在哪里
依赖优化整体上做的是代码的搬运工
局部重构不应该很盲目,而应依赖于基于 “伤害值” 的客观判断。习惯于在不理解的情况下就重构,这实在不太好。认同他人是很重要的能力修炼。况且作为架构师,事情优先级的排列是第一位的,有太多重要的事情值得去做
文本内容的处理范式
词法分析(Lex)
语法分析(Parser)
正则表达式(Regular Expression)。
在简单场景下,正则表达式是比较方便的,但是它的缺点也比较明显,可伸缩性和可读性都不强
数据是软件的灵魂,文件是软件最重要的资产
软件工程
管理学本身的目的之一就是要抑制不确定性,产生确定性
软件项目的管理又期望达到确定性。软件工程本身是快速变化的,是不确定的。这就是软件工程本身的矛盾。我们的目标是在大量的不确定性中找到确定性,这其实就是软件工程最核心的点。
团队的共识管理
人是愿景型动物,需要看到未来。越高级的人才越在乎团队存在的意义。所以高科技公司的人才通常只能去影响,而不是像一些人心中理解的那样,认为管理是去控制
通过同步足够充分的信息,通过共创而非传达决策的方式让结论自然产生
概要设计阶段最好的状态并不是只有设计文档,为了降低风险,系统设计阶段也应该有代码产出
代码即文档。代码是理解一致性更强的文档
设计文档
一个模块对外提供的访问接口无非是:
常规 DOM API,即正常的模块功能调用;
事件(Event)的发送与监听;
插件(Plugin)的注册
如何阅读别人的代码
编译过程是有损的
大部分编译器在编译时会同时生成符号文件。它主要用于 debug 用途
有产出的学习过程,才是最好的学习方式 。构建这个程序的思路,也就是架构设计
代码即文档,代码是理解一致性更强的文档;阅读代码的结果,有时不一定仅仅是架构设计文档的补充与完善。我们有时也会顺手修改几行代码
代码修改原则
不做大的改动,比如限定单个函数内的改动不能超过 10 行
确保改动前后的语义完全一致,包含所有 corner case 的语义
要有单元测试
质量管理
变量只读,以提高内心对确定性的预期。我并没有去用严谨的方式实证过变量只读的收益究竟有多大,但它的确成为了很重要的一种编程流派,即函数式编程
软件工程的核心在于如何在高度的不确定性中找到确定性
拥抱开源
每天我们几乎不会遇到工作方式上的问题,不是别的原因,是开源给予我们的礼物
版本发布规划
从 0 到 1 阶段,我们验证的是用户使用姿势,性能并不是第一位的
进入从 1 到 100 的扩张阶段,版本迭代的关注点反而切换到了用户看不见的地方
产品竞争力就是关键指标,这时候我们迭代的是用户价值最大的,也是用户真正最在乎的那部分
遇到会对产品产生巨大冲击的需求,头脑别发热,谨慎处理。回到从 0 到 1 阶段的方法论,在少量客户上先做灰度
总结
能够维持架构设计的持续优异,这绝非某个人的技术能力可以做到的事情,而是要靠团队共同的坚持
新人融入效率看,更非技术能力所能够简单囊括,而是仰仗团队对业务传承的坚持
有的团体像一盘散沙,充其量可以叫团伙。有的团体则有极强的凝聚力,整个团队上下同心,拧成一股绳,这种团体才是高效率组织,是真正意义上的团队
严谨并非创新的对立面,而是创新的重要基础。每个人都有灵光乍现的时刻,但是唯有那些拥有严谨的科学态度的人才能抓住它,把它变成现实
“一个个业务只读、接口稳定、易于组合的模块 + 组合的方法论”,它们才是架构师真正的武器库
架构师绝对不是要把自己打造为全才。架构师掌控全局的核心思想是打通经络,让自己的内力在全身自然流通,浑然一体。在不影响理解的情况下,你需要放弃很多实现细节的专研,但有一天你需要细节的时候,你能够知道存在这些细节,并且快速钻研进去。
一个人的能力决定他的上限,圈子决定了他的下限
孙子兵法
明道
庙算
感知
法度
“将听吾计,用之必胜,留之。将不听吾计,用之必败,去之。”
要建立适应自身、对手和战争形态的管理架构和组织体系,以及有效的规章和奖惩体系
辩证
水因地而制流,兵因敌而制胜。所有策略必须依据时机、环境、对手、人心变化而变化
评论