Oct 10, 2018
云服务
#
本质
批发转零售
帮助别人成功而成功
产品型转服务型
优势
轻,方便
全
可计算
现象
外包被淘汰
行业
OS of business
功能
产品功能,样板
开发体验,文档
组件收费,容量收费,节省的成本收费
数据直接做决策
分类
service
# 基础服务
plugins
# 基础服务组合
app
# plugins组合
产业互联网
#
供应链
#
为什么
大厂核心
各节点(库存)周转
是什么
资源 -> 渠道 -> 用户
反馈用户真实需求
上游关注制造业
下游关注erp
批量(精), 个性化(敏)
物流, 资金流(现金流), 信息流
库存管理
应对变化(保质期)
求零库存
供应商
评级
物流, 成本
难点
打通
怎么样
成本、利用率
可靠性, 反应力, 柔性(补错)
感知、预测
赋能
重点
按时制造
难点
协调(协议)
步骤
单品上下游延伸
人工智能
#
优化、预测
拟合函数, 高阶微积分, 梯度下降
元宇宙
#
传媒营销
#
媒体
#
场景控制
3CAD
character
camera
control
art direction
特效
会场散射光束(博物馆)
雾中焦点的竖光(saber的剑)
画线的光点(最终幻想)
密集的星星,远近缩放,光圈(tree.js官网)
水滴带动整个屏幕的亮度(fate stay night)
蓝色光影交错(fate stay night)
秒针声强调时间(fate stay night)
单帧卡动画渲染气氛(fsn)
黑白画面到彩色画面(madlife 集锦[dream on])
黑白画面彩色涟漪(冰果)
地面的雾影(fsn)
音乐重节拍时出现隐形单位/人(fsn)
转动的星空光点线加云(fsn结尾)
沙的立体塑型(秦时明月)
红辣椒的分镜
网站效果
图片向下拉,上面模糊小,下面清晰大,有一种震撼感
Oct 10, 2018
人, 事, 团队
#
人
业内口碑
成分
技能,素质,精神
行动
感性,理性,惯性
发展
上限
下限
成本
低成本召回
事
知原理
是什么,为什么,怎么样,拆解
事与团队
事造就团队,好团队不一定出好成果
团队
存在合理性
有目标,成员能力认可,成员感性认可
小精英团队,才能解决问题
分配事
因特质分配,如稳定,峰值,沟通
成果评价
产出判断
分配利益和荣耀
时间和代码量评价不了程序员的工作, 可以匿名互评(口碑)
团队提升
培训无意义,自觉成长
成员
项目经理
设计
开发
测试人员
运维
系统工程师
设计、实现产品
数据分析师
技术总监
架构师
权衡, 出方案
职工
#
态度
把握分寸
靠谱(事事有交代)
负责(顾全局)
主动
超出预期
负责态度, 提高团队效率,而非自己效率 # 严肃判断
沟通
及早沟通、同步
文档 > 邮件 > im > 电话
# 即时性相反
留响应时间, 同组 -> 跨组 -> 跨部门 -> 跨公司
明确通知人时, 邮件, im特殊指定
文档
周报
文档简单有计划,为节省向别人解释的时间
建设性意见(提选择题)
只交“产品”: 背景清晰, 扼要, 完整, 引入独有经验
工程师
#
本质
解决问题
普遍问题
技能: 工具使用(写工具), 表面学习, 笨办法, 不会读文档, 只会知识迁移
设计: 不知经典设计, 不知设计哲学, 不知目的, 无法反应需求, 没有品位, 读不懂设计
知识更新: 学不动, 基础差(用二手资料), 无认知体系(认为都是新东西), 重复学习无用知识
沟通: 不专业(不用专业名词), 不主动, 不沟通对方, 不抓重点, 思路不连贯, 阅历不足(不会写文档), 不问为什么
能力
特点
知识、经验、技能、协作 # (1+天赋)x知识x工程习惯
犯错(多做多错)
方法
抽象 # 设计就是从升维中拆分和简化
沉淀 # 没有沉淀的学习不好回顾修改, 像没有测试的代码
品位
优点,缺点 # 找潜质, 并非此长彼短,是两个维度,有一定抑制作用
创造力,纪律
勤奋,聪明
稳定,峰值
深度,速度
细节,大局
开发
考虑工作的复用性
加入项目,需要可对所有代码修改
善用工具
自己的事主动跟进
owner
自我负责, 自我驱动, 持续改进
能部署, 能手工排查问题,手工修复数据, 开发调试工具, 数据修复工具
模块职责单一, 明白当前负责和极限性能
能降级, 知道下游调用和降级影响。了解上游依赖和上游降级影响
配好log、监控、告警, 告警及时响应
架构师
#
场景/用例/问题 -> 方案/方案权衡 -> 落地路径
分级
初级
代码
命名:精确性、简单性、一致性、区别性、业务性
逻辑: 缩进、换行
代码体积: 行、方法、类
抽象能力
边界
中级
流量、并发等
高级
理解业务核心价值、业务实现方式
业务技术支撑方式
业务趋势
创始人
#
心态: 平常心
职责: 找到善于解决问题的人,做好善于定义问题的人
艺术家
#
岗位
#
项目经理(pm, project manager)
技术经理(tm, technical manager)
产品设计经理(pdm, product design manager)
运营经理(pom)
测试经理(qam)
客服经理(csm, customer success manager)
开发组长(tl, team leader)
架构师(pa)
开发工程师(de, development engineer)
数据库管理员(dba, database administrator)
系统管理员(sa)
界面设计师(ui, user interface)
用户体验设计师(ue, user experience)
产品运营师(po, product operator)
产品设计师(pd, product designer)
测试工程师(qa, quality assurance)
配置管理员(pcm)
发布员(pb)
软件过程专员(sqa, software quality assurance)
运维工程师(sre, site reliability engineer)
招聘
#
双向选择
精确率&召回率
方面
沟通
喜欢技术,逻辑能力, 编码能力, 设计能力
基本概念, 边界考虑充足, 进阶答案, 衍生问题的解决
是否有自己思考,对自己负责
Oct 10, 2018
要素
#
环境的设计
安全
规模小
改变被动传输为主动接受
交互、提问与思考
团队、竞争、奖励
控制场面
引导
Oct 10, 2018
组织
#
系统划分与组织划分
康威定律
系统架构是公司组织架构的反映
按业务闭环进行系统拆分/组织架构划分,实现闭环/高内聚低耦合,减少沟通成本
沟通出现问题,考虑调整组织架构
在该拆分时拆分
为了简单
开发和运维分离
业务和基础架构分离
无状态和有状态分离
业务间乘法(正交)而非加法 # 升维的特点, 正交叠加
多层抽象, 不断隐去底层(约定大于配置) # 升维的特点, 抽象观察
管理
#
责任
#
提供
问题: 定义, 分解, 什么是问题, 前人如何处理
# 工程为解决问题
思考: 方向, 为了解决问题, 找到关键, 找到应学知识
# 创造性工作要思考
体系: 领域的体系, 领域体系形成原因, 为了高效思考和学习, 有体系的做事
参考: 参考书籍, 如何筛选, 如何搜索, 社区
不提供
知识点, 答案, 规定, 代码
分任务
出问题,写相关文档
砸需求,看弹性
任务列表: 难度, 优先级, 排期, 地平线目标, 现状, wishlist
nice to have给新人
方法
#
人员
TeamLeader -> Owner
需求磨砺核心业务资产(事情成就精英团队,而非精英团队成就事)
问题定义
完成不动点需求
正交、简单(要求想清楚、灵活)
维护概念完整性、一致性(纯洁)
术语不变、不矛盾、不重叠
考虑上下游
代码问题
问题原因:开发的碎片化(重复的代码、由于不知道或怕改错)
解决方法
代码Review,集体评审
持续集成(*lint, CI/CD): 早合并、自动构建、测试
问题管理
需求池
优先级、排期、checklist、周update
文档知识库(Confluence, Notion)
问题追踪(Jira)
迭代(周冲刺, hackson)
产出评估角度
口碑、解决问题。
良心,内驱力
Owner, 鼓励设计、技术自由(开发人员诉求技术,厌倦业务)
效率第一: 加班是能力问题
时间,代码量
犯错问题: 总会犯错,多做多错
不能赶期,不怕delay
制度
#
模型
#
开发模型
#
TDD(test-driven development)
先单元测试
BDD(behavior-driven development)
TDD的变种, 重点描述行为
面向需求
组织上小而全
开发全栈减少沟通
设计上面向领域
迭代模型
#
极限编程(XP) # eXtreme Programming
4大价值
沟通:鼓励口头沟通,提高效率
简单:够用就好
反馈:及时反馈、通知相关人
勇气:拥抱变化,敢于重构
5个原则
快速反馈
简单性假设
逐步修改
提倡更改(小步快跑)
优质工作(质量是前提)
5个工作
阶段性冲刺
冲刺计划会议
每日站立会议
冲刺后review
回顾会议
结对编程
PDCA循环质量管理
Plan, Do, Check, Act
FMEA
分析潜在的失效模式
工程模型
#
历史
程序设计阶段1946-1955 节省空间
软件设计阶段1956-1970 硬件发展,软件危机
软件工程阶段1970-今 组件化
瀑布模型
#
# 每一次执行工作流的深度不同
可行性分析
实现会不会复杂,尽量简单
需求分析
分类
生存点
痒点
兴奋点
# 不会按时交付(只完成主要,然后延期,用户测试)
客户沟通,同类产品比较,行业标准
功能
正确, 可行, 必要, 有序, 明确, 一致
性能
完善, 简短
设计
先出成果再优化
任务分配(进度条)
命名标准
文档
可移植、可维护易扩展
排期
实现
测试
运维
螺旋模型
#
# 边分析边开发边交付(一环一环向目标实现)
敏捷开发
项目面临的问题
人员流动
代码维护
种类
极限编程(xp)
特点
简易、交流、回馈
方法
解耦低速设备,提高响应速度
迭代
迭代周期
一个迭代周期中不新添加需求
一个迭代周期中包含多次迭代
一个阶段的结束称之为里程碑
初始化阶段增量
项目启动
建立业务模型
定义业务问题域
找出主要风险因素
定义项目需求的外延
创建业务问题域的相关说明文档
细代阶段增量
高层的分析与设计
建立项目的基础框架
监督主要的风险因素
制订达成项目目标的创建计划
构建阶段增量
代码及功能的实现
移交阶段增量
向用户发布产品
beta测试(alpha测试是内部测试, beta测试是用户测试)
执行性能调优,用户培训和接收测试
转型
#
流程
(2-4)周实地调研痛点
确定目标
要求: 领先、高效、高品质
列出实际问题
评估
cmmi(敏捷成熟度模型): 代码、架构、工具
实施变化
战略
试点团队(灰部应用于组织): 完成产品指标
工具功能
#
控制面板
项目
分配给我
活动日志
人员
团队
权限
项目
配置
事务
类型
布局 # 列表项,详细项
时间追踪
配置链接关系
优先级
解决方案
工作流 # 对不同项目和事务类型, 配置状态转换图
页面方案 # 对不同项目和事务类型,不同状态转换时,配置字段布局
自定义字段 # 对不同页面
权限
权限
角色、应用程序、组、用户、项目负责人、当前经办人、自定义字段值等
事务(issue)
状态
todo, 正在进行, done
打开, 已重新打开, 已解决, 已关闭
backlog, in review, selected for development, building, build broken
waiting for support, respond to customer, escalate, cancel, canceled, done
waiting for approval, work in progress
[工作流状态]
类别
待办
正在进行
完成
无类别
名称
长篇故事(史诗)
故事
分类: 需求, 设计
验收条件
任务, 子任务, 缺陷, 新增功能, 改进
服务请求, 服务请求审批, 问题, 事件(系统中断)
订单
全局顺序
属性
经办人,报告人
优先级
highest, hign, medium, low, lowest
链接
clones
is cloned by
duplicates
is duplicated by
blocks
is blocked by
causes
is caused by
relates to
csv导入
筛选器
未清, 我发起, 已完成, 最近
活动
评论, 历史, 工作日志
冲刺(sprint)
状态
待办, 进行, 完成
发布
版本
报告(report)
敏捷
燃耗图, 燃尽图, 版本报告, 长篇故事报告, 控制图,长篇故事燃尽图, 发布燃尽图
冲刺报告, 速率表
累积流程图
事务
饼图, 单次分组, 解决时间, 平均周期, 事务持续时间, 已创建已解决对比, 最新创建
预测
版本工作量, 人员工作量, 时间跟踪
其它
工作负荷
服务台(itsm)
分类
对内
对外
途径
邮件, 帮助中心, 小程序
队列
分类
状态workflow
经办人
客户
报告
系统
审计日志
Oct 10, 2018
造型期
#
体态
高低肩
骨盆前倾
体能
心肺
变速有氧:4、6、8各2min, 30min以上
力量
核心训练
健身计划
#
目标
指导
FITT
Frequency: 一周3-5次
Intensity:
有氧
心率: 123-142
无氧
动作
间歇
个数
重量
Time:
60min力量 + 30min有氧
Type:
热身
抗阻力训练
拉伸
阶段
适应期(1-2月)
心肺功能: 功率
核心力量
保护腰:呼吸 + 静态
内脂
力量训练
动作规范
蹲、推、拉、举、旋转
进阶期(2-3月)
消耗 > 摄入
七大肌肉群:胸、肩、背、腹、腿、臀、手臂
三分化、四分化
爆发力
Oct 10, 2018
人类认知原理
#
原理
模拟执行
负担
概念量
封装粒度大
多态、运行时多态、静态多态
临时状态
用工作流, 而非队列
日志(event)搜索/集中/回放
抽出权限层
非轻量级
胶水层厚
无稳定方案, 复用困难
流程长度
最好
单线程 # 不插入行为
上下文集中
this.scene.commit()集中状态转移时间线
单一方式
软件设计原则
#
统一原则
#
观念
KISS(keep it simple stupid)
YAGNI(You Ain’t Gonna Need It)
取好名字占设计一半
约定大于配置
并发的世界,并发的软件
分布式的世界,分布式的软件
不可预测的世界,容错性强的软件
复杂的世界,简单的软件
代码即数据
物体上绑定行为数据
传递代码数据(函数一等公民)
防御性编程
接口前validator
启动时自检断言
异常处理
不可过度
设计
solid原则
单一职则(single responsibility)
一个类负责一个功能
开闭(open/closed)
对扩展开放,对修改关闭,如接口, 如数组扩展结构体状态
里氏替换原则(liskov substitution)
子类继承超类的所有
接口分离(interface segregation)
最小功能隔离
依赖反转(dependency inversion)
低层依赖高层, 具体依赖抽象
非侵入 # non-intrusion
将功能推入代码,而非代码拿到功能
代码实现接口,而非继承类
拆分
边界
正交
unix rules
模块化(modularity) # 模块由精心设计的接口连接
清晰化(clarity) # 可读性、可维护性
组合(composition)
分离(separation)
简单(simplicity)
节俭(parsimony) # 越小越好
透明(transparency) # log, tracing
鲁棒(robustness)
可展示(representation) # 逻辑简单,数据复杂
最小惊吓(least surprise) # 少打破用户预期
安静(silence)
修复(repair) # 产生足够报错
经济(economy) # 减少开发时间
生成(generation) # 避免手写, 用高阶抽象生成代码
优化(optimization) # 优化和收益平衡
分化(diversity) # 一开始设计不限制、优雅开放灵活
扩展(extensibility) # 协议可扩展
优化
需要时再优化,设计时考虑扩展性
dry(don't repeat yourself), 不可过度
找瓶颈
产出
设计清晰
选型简单
代码精炼
抽象优雅
代码风格
#
命名
包名类名为名词, 方法名为动词
参数、方法名称在上下文语义中合理 , 像写文章一样
横向代码单屏内分行
性能
避免嵌套循环,特别是数据库操作
结构
# 高内聚,低耦合
抽取方法
业务逻辑分层
框架无侵入性
技巧
注释驱动写复杂业务
自解释代码
安全
密码二次验证
离机锁屏
用户名、密码、ip、端口不提交
代码安全, 如sql注入, XSS
代码质量
#
代码
功能、结构、资源
非遗留代码
写了测试
改代码
bug
重构
# 只改结构
确定修改点
找出测试点
解依赖
伪/仿对象
接缝
全局函数
提取重写方法
宏预处理
替换连接的代码
对象
# 耦合对象不好初始化
子类化重写方法
接口提取
创建简化接口
创建简化类与对象,引用原对象
暴露静态方法
对象提取公共方法,只测公共方法
传方法参数
写测试
优化
# 只改资源
具体实现原则
#
数据结构
#
状态机解决流程问题
AST解决主义问题
面向对象(Object Oriented)
#
特性
ooad
# Object Oriented Analysis and Design
ooa # analysis
建立针对业务问题域的清晰视图
列出核心任务
针对问题域建立公共词汇表
列出针对问题域的最佳解决方案
ood # design
细化类关系,明确可见性
增加属性
分配职责(方法)
消息驱动系统中消息传递方式
局部应用设计模式
类图时序图
oop # program
抽象: abstract
接口
无实现
可多重继承
抽象类
可以有私有方法变量
实现部分方法
封装: encapsulation
# 数据和方法绑定
继承: inheritance
多态: polymorphism
overload为编译时
override为运行时
关联: association
# has a
双向关联
两个类互相知道对方公共属性和操作
单向关联(大多数)
一个类知道另一个类的公共属性和操作
聚合: aggregation
a包含b, b可以不在a创建时创建
组合: composition
比聚合强,a包含b, b在a创建时创建
内聚与耦合: cohesion & coupling
# 高内聚低耦合
依赖: dependency
# use a
泛化: generalization
# is a
泛型
函数式
#
数组
[1, 1, 3, 5, 5].reduce(function(x, y){ return x + y;})
[1, 4, 9].map(function(num){return num * 2;})
高阶函数(higher-order function)
操作函数的函数, 接收函数作为参数, 返回函数
不完全函数(partial function)
一次调用拆成多次调用,每次调用返回一个函数,如f(1,2)(3,4)(5,6)
# 每次调用叫做不完全调用(partial application)
不变式
循环不变式
用于形式化证明正确性
描述
有循环变量
算法初始、保持、终止时, 某特性不变, 如选择排序中, arr[0,...,j-1]一直有序
类(或数据类型)不变式
并发时, 不变的成员关系
如, 并发临界区(同时只能一个线程占用)
cps(continuation passing style)
传入处理函数, 处理函数中传处理函数
curry
f(1,2,3)改写成f(1).f(2).f(3)
thunk
触发函数, 如 f(){_f(1)}
Oct 10, 2018
介绍
#
介绍
Domain-driven Design
针对传统软件开发流程(分析-设计-编码)各阶段业务割裂问题,一开始定义好领域
目标
维护概念完整性(纯洁),避免语义泄露和腐化
概念
#
领域(Domain)
界限上下文(Bounded Context)
领域模型(Domain Model)
领域通用语言
分层架构
展示层、应用层、领域层、基础设施层
最佳实践
关联尽量少、尽量单项、尽量降低整体复杂度
实体(Entity)
领域中的唯一标识,属性尽量少
值对象(Value Object)
没有唯一标识,属性值不变
领域服务(Domain Service)
协调多个领域对象,只有方法没有状态
应用层服务、领域层服务、基础层服务
聚合、聚合根(Aggregate, Aggregate Root)
聚合定义了一组有内聚关系的对象集合,聚合根是对聚合引用的唯一元素
修改聚合必须在事务级别
70%的聚合只有一个实体, 30%有2到3个实体。
只有一个实体时,实体就是聚合根。多实体时思考哪个对象有独立存在的意义,且可与外部直接交互
工厂(Factory)
工厂模式
仓储(Repository)
持久化到DB,管理对象
只对聚合设计仓储
建模
#
原则
#
简单、容易、清晰
使用不动点
领域专注
聚合内强一致,跨聚合最终一致
内部概念完整一致(unification)
术语不变、不矛盾、不重叠
数据模型(DO)
#
失血
DO和DAO无业务逻辑,纯数据
贫血
持久化逻辑在DAO中
充血
service很薄,持久化的逻辑在DO中,无DAO或与DO双向依赖
肿胀
无service,全部逻辑放DO
分析设计
#
分析模型
#
# 业务领域分析, 不考虑代码
问题
含意不完整,不可图形或文字表达,错误假设
会深入某细节
忽略某细节直到设计或实现, 如持久化、性能
目标
领域模型
架构设计
事件风暴 # 是开发建模,不是用户需求故事
准备
功能确认: 近期milestone
找正确的人: 领域专家, 前后端,架构师
引导者: 准备资料, 排程, 时间, 2/3时间预警
事件风暴
领域事件: 用户可感知状态
分支小组 -> 个人发散 -> 小组一致 -> 整体一致 # 不能一致表示准备不足
逻辑顺序 -> 最终流程
命令风暴 # 为什么, 分色
事件触发原因、方式
用户角色
读模型: 用户前置需求
写模型: 动词
描述
聚合
取名, 分职责
持续探索
领域模型一开始就结合编码设计 # 设计围绕模型, 模型受设计反馈改善
开发时意识到模型变更, 会保持完整性
每个开发在修改前需要了解模型
面向对象更易于建模, 过程化易于流程,如数学
重构
#
要求
设计灵活
使用经过验证的构造
目标
领域理解更深、更清晰
深刻(incisive)、深层(deep)的模型
技术的动机的代码转换
实现
小幅可控
基于测试
突破
新的概念或抽象
隐含的概念被凸显
倾听领域语言
过分复杂是因为关键点被替代
领域文献 # 深层视图
约束 # 表达不变量
过程(process) # 面向对象中的面向过程, 多个过程时用策略
规约 # 测试对象返回布尔值, 重构成对象而非写在application
战略建模
#
# 形成上下文映射图
问题空间
领域 # 与公司组织关联
子域 # 最好对应一个限界上下文
核心域(core domain) # 项目动机, 公司核心竞争力, 尽量小, 最高优先级
通用子域(generic subdomain) # 作用于整个系统的支撑子域
支撑子域 # 重要非核心
集成
合作关系(partnership) # 同时成功失败
共享内核(shared kernel) # 小型内核, 持续集成功能
客户/供应(customer-supplier development) # 上下游
遵从(conformist) # 下游遵从上游
防腐层(anticorruption layer) # 翻译转换领域服务
开放主机服务(open host service) # 公开协议,子系统访问
发布语言(published language) # dsl, 通常与开放主机服务一起
分隔(separate way) # 声明无关联
大泥球(big ball of mud) # 已有纠缠的系统,隔离出来
解决方案空间
通用语言
一个限界上下文一个通用语言
清晰(概念无二义性), 简洁 # 如卖家和买家都叫用户,就是不清晰。如用type标记用户是卖家或买家,就是不简洁。所以直接用两个对象
限界上下文 # 条件的集合
目的
确保术语含义明确
切分规模, 易于保持领域纯洁
设定进化框架而非模块,包含模块
考虑因素
团队组织结构
应用特定部分惯例、物理表现
挑战
团队开发碎片化 # 写重复的代码,由于不知道或怕改错
持续集成
早合并
自动构建测试 # 检测不一致
模块
作用
降低模型规模复杂度
代码高内聚低耦合
设计
通信性内聚(communicational cohesion)
功能性内聚(functional cohesion)
每模块统一接口
名称反映深层理解
灵活性,进化性
上下文映射 # 领域间集成关系
模式
共享内核(shared kernel) # 为减少重复, 共享领域子集,多方测试
客户-供应商(customer-supplier) # 做反馈的需求, 需求测试, 自动化验收
顺从者 # 供应商不做需求, 客户用适配器对接组件
防腐层(anticorruption layer) # 双向领域模型转换器, 保持内部模型纯洁
从前
原始数据(api, db)无模型无语义的处理
实现
对外多门面(facade)
每个门面一个适配器(adapter)
适配器间用转换器(translator)
隔离通道(separate way)
开放主机服务(open host service) # 实现开放服务协议
提炼 # 多次重构后还很大
实现
分离基本概念和普通概念, 提炼核心域和子域
子域
使用第三方服务
外包
修改已有模型
六边形架构
领域模型简洁自治
对外适配器防腐, 保护限界上下文 # 如面向接口
消息, 内存, 数据库
soap, rest
CQRS(command query responsibility segregationg) # 修改只记事件(日志), 查询时计算
查询方式
单数据库/读写分离,查询时计算事件
读写分离, 读库异步计算事件保存冗余, 读库负载均衡
战术建模
#
# 组成限界上下文
领域
实体(entity) # 标识和延续性, 有id, 持续变化。
值对象(value object) # 无id, 只有属性, 最好不可变(可共享)。尽量建模值对象。可包含实体引用或值对象。
生命周期
聚合(aggregate) # 定义对象所有权和边界
简化
关联 # 可导航到的关联
1对1 # 对象引用
1对n # 包含集合
n对n # 删除关联,关系加约束或转换
目的
一致性
强化不变量
实现
聚合根(root) # 聚合根间是最终一致性
是个实体,有id
外部访问的唯一对象
向外传递副本
工厂(factory) # 在领域中没有定义, 但程序需要
目的
并非对象创建对象
对象创建存在自有知识
创建过程原子性
对已有持久化对象重建并修复
问题
外部访问根内对象,需关联不必要的根实体
实现
不用工厂
构造不复杂
不涉及其它对象
客户希望用策略创建
类是具体类型, 无层级
聚合根提供方法
单独工厂 # 违反了封装原则, 但保持了简单
资源库(repository) # 内存假象
目的
不关联根获取对象引用
不暴露细节, 会减少领域专注
防止代码扩散
减少变更修改
维护聚合封装性
容易的基础设施被滥用, 产生除聚合根外导航
实现
封装所有获取对象逻辑
基础设施, 全局可访问
不同对象不同策略访问、存储 # 领域与基础设施解耦
接口是领域模型, 实现像基础设施
参数筛选或规约(specification)筛选(筛选器)
entity
介绍
entity即状态
应用开发即处理entity的表现
主从
主存储(可变) # 关键是选择主存储
多派生一致性好保障
派生表达业务的难易成度
只读派生(representation, 不可变)
多份存储, 一致性
派生, 合并, 转化
类型
东西(可变) # 单据叠加成东西, 东西叠加成东西
单据(可变) # 事件叠加成单据
事件(event, 不可变)
命令(command, 不可变)
视图(view model, 不可变)
子集(subset, 不可变)
视图(aggregation, 不可变)
表单(可变) # 是主存储
物理介质
OLTP(mysql) # 点查询
OLAP(clickHouse) # 范围查询
queue(kafka) # 顺序读, 低延迟
业务服务 # 业务逻辑, 像虚拟的表
分组entity主存储(BC, bounded context)
目的
分解
管理复杂度
系统
组织部门
实现内部一致性
概念, 数据
对主存储进行受控的修改
边界entity # 用于集成,不一定是主存储
形式
授权、binlog、工作流、视图数据、租户作为其它租户user
东西、单据、event
介质
queue, 带权限db, rpc虚拟表
触发
queue, ui, api
触发由worker托管, 输入是queue或rpc socket
粒度
分entity
分步骤
分entity字段
原则
BC尽可能少而大
关系
时间错开
外键关系 # BC挂载到BC, 如后台系统与计费系统的定价, 运营人员与服务系统的配置, 流程节点系统对流程的依赖
rpc, 数据库, 数据复制
报表关系
时效性高
一般做复制 # 所以边界entity是数据变更event
触发关系 # fire and forget
交棒关系
下游给上游command/event, 上游触发
上游实现降级 # 下游不可用时,安慰语
时间同时
accountable/responsible关系 # 负责人与实现人
原则
accountable尽量小
只调度
与responsible的边界entity是rpc虚拟表, 请求command, 返回event
补偿实现一致 # 如超卖
responsible提供自己界面 # accountable不控制
抢资源关系
锁服务
服务(service) # 无法划分对象的动作, 无状态。按功能分组, 多对象的连接点
可在application, domain, infrastructure
最终一致性建模
#
In-Memory
#
聚合根在内存,同步最新状态
事件溯源(Event Sourcing)
#
没有CRUD,只有Append Event。数据不可变
对象最新状态通过事件溯源获得
Actor
#
通过Mailbox取代调用,保证消息线性处理
EDA(Event-driven Architecture)
#
节点只处理逻辑,节点间Event通信
是最终一致性的架构
CQRS
#
介绍
Command Query Responsibility Seperation
CQ接口分离、代码分离,分别设计
概念
项目结构
#
用户接口(user interface)
应用(application) # 尽可能小。数据验证,事务。故事, 表达出操作的事情
application service
unit work
presentation model
领域(domain) # 专注领域。准确定义业务对象
aggregate, entity, value object
domain service, domain event
基础设施(infrastructure) # 辅助层
repository
global support
项目文件
[ui]
mall # 商城api
[saleDomain]
[application]
mall.application # 分模块,讲述故事
CartService
GetCart()
BuyService
Buy()
mall.application.domainEventSubscribers # 订阅domain事件
[domain]
mall.domain # 不大而全,要求刚好满足需求
cartModule
entity
CartItem
aggregate
Cart
valueObject
Product
SellingPriceCart
IDomainServices
IRemoteServices # 访问远程资源接口
IUserService
ISellingPriceService
IRepositories # 仓储接口
ICartRepository
mall.domain.events # 领域事件, 用于实现最终一致性
mall.domainService # 操作domain的无状态方法
ConfirmUserCartExistedDomainService
[sellingPriceDomain] # 与saleDomain合作关系, sale请求sellingPrice定价
[appication]
mall.application.SellingPrice
dto
CalculatedCartDTO
mapper
ValueObjectToDTO
[domain]
[infrastructure]
mall.infrastructure # 通用类库
domainCore # mail.domain base方法
AggregateRoot
Cart
Entity
CartItem
ValueObject
Product
IUnitOfWork # 仓储事务
domainEventCore
DomainEvent
DomainEventBus
DomainEventSubscriber
IDomainEvent
IDomainEventSubscriber
mall.infrastructure.repositories # 仓储
CartSqlServerRepository
mall.infrastructure.translators # 防腐层, 访问远程资源实现
user
UserAdapter # 请求原始结果
UserService
UserTranslator # 转换原始结果
模块结构
api: controller
biz: 特异业务
manager
converter
core: 公用业务
model
entity
bo
service
repository
common
dal
dataobject
do
dao
mapper
service
facade
dto: facade和controller用
service: 服务间api
validate
integration
service
shared
dto: 项目内部公用
Oct 9, 2018
六个原则
#
单一职责原则(SRP, Single Responsibility Principle)
一个类只做一件事,应该只有一个引起它修改的原因
开闭原则(OCP, Open-Close Principle)
对修改封闭,对扩展开放
里氏替换原则(LSP, the Liskov Substitution Principle)
子类可以完全替换父类。也就是继承只扩展新功能
依赖倒置原则(DIP, the Dependency Inversion Principle)
细节依赖于抽象,抽象不依赖于细节。抽象放在高层,并保持稳定
接口隔离原则(ISP, the Interface Segregation Principle)
客户端不依赖它不需要的接口。冗余依赖应该将接口拆分
迪米特法则(最少知道原则)(LoD, Law of Demeter)
一个类不应该知道自己操作的细节。只和朋友谈话,不和朋友的朋友谈话
构建型
#
工厂方法(Factory Method)
#
# 简单工厂, 根据参数创建不同的类
# 静态工厂,单例工厂
public interface Sender{
public void Send();
}
public class MySender implements Sender{
@Override
public void Send(){}
}
public SenderFactory {
public static Sender produceStatic() {
return new MySender();
}
public Sender produce(){
return new MySender();
}
public Sender produce(int i){
return new MySender();
}
}
# 工厂子类继承工厂接口, 不同产品对应不同工厂
public interface AbstractFactory {
public MySender produce();
}
public class MyFactory implements AbstractFactory {
@Override
public MySender produce(){
return new MySender();
}
}
抽象工厂(Abstract Factory)
#
# 生产抽象产品
public interface AbstractFactory {
public Sender produce();
}
public class MyFactory implements AbstractFactory {
@Override
public Sender produce(){
return new MySender();
}
}
单例(Singleton)
#
确保只有一个实例
# 大多有资源管理器的功能
# 反射机制会使所有单例失效:私有构造方法可以被访问
应用
线程池
缓存
日志对象
对话框
打印机
显卡驱动程序
o-> 饿汉
public class Singleton {
public static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
o-> 懒汉式
public class Singleton {
private static Singleton single=null;
private Singleton() {}
public synchronized static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
o-> 懒汉,双重检测(DCL)
# 解决问题并发创建问题。在不同jvm或多核cpu上,有无序写入bug。
# 解决bug: 1 直接创建static属性, 2 get方法修饰synchronized
public class Singleton {
private static volatile Singleton singleton = null;
# volatile: t1编译singleton = new Singleton()时重排序把没初始化对象赋值给singleton时, t2判断singleton为null。
private Singleton(){}
public static Singleton getInstance(){
if (singleton == null) {
// t1,t2并发进入
synchronized (Singleton.class) {
// t1释放后,t2进入
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
o-> map注册
# 学Spring,将类名注册
public class Singleton {
private static Map<String,Singleton> map = new HashMap<String,Singleton>();
static{
Singleton single = new Singleton();
map.put(single.getClass().getName(), single);
}
protected Singleton(){}
public static Singleton getInstance(String name) {
if(name == null) {
name = Singleton.class.getName();
}
if(map.get(name) == null) {
map.put(name, (Singleton) Class.forName(name).newInstance());
}
return map.get(name);
}
}
建造者(Builder)
#
# 提供工厂方法,建造内部复合对象
o->
public class Builder {
private List<Sender> list = new ArrayList<Sender>();
public void produceMailSender() {
list.add(new MailSender())
}
}
原型(Prototype)
#
# 复制原型来创建新对象
结构型
#
适配器(Adapter)
#
# 用来匹配接口
o-> 类
public class Source(){
public void method1(){}
}
public interface Targetable {
public void method1()
public void method2()
}
public class Adapter extends Source implements Targetable {
@Override
public void method2(){}
}
o-> 对象
public class Wrapper implements Targetable {
private Source source;
public Wrapper(Source source){
super();
this.source = source;
}
@Override
public void method1(){
source.method1()
}
@Override
public void method2(){}
}
o-> 接口
public abstract class AbstractTarget implements Targetable {
@Override
public void method1(){}
}
public class Adapter extends AbstractTarget {
@Override
public method2(){}
}
桥接(Bridge)
#
# 分离抽象和具体(两个维度发展)分别继承,抽象聚合(桥接)具体
public abstract class Gift {
GiftImpl impl;
}
public class Flower extends GiftImpl {}
public class WarmGift extends Gift {
public WarmGift(GiftImpl impl) {
this.impl = impl;
}
}
组合(Composite)
#
# 树状结构
abstract class Node{}
class LeafNode extends Node{}
class BranchNode extends Node{
List<Node> nodes = new ArrayList<>();
}
tree(Node b, int depth) {
b.print();
if (b instanceof BranchNode) {
for (Node n : ((BranchNode)b).nodes){
tree(n, depth+1)
}
}
}
装饰(Decorator)
#
# 持有被装饰实例,实现同一接口
public interface Sourceable {
public void method();
}
public class Source implements Sourceable {
@Override
public void method(){}
}
public class Decorator implements Sourceable {
private Sourceable source;
public Decorator(Sourceable source) {
super();
this.source = source;
}
@Override
public void method() {
source.method();
}
}
门面(Facade)
#
# 对外接待
# 内部都只关联它,如mq
享元(Flyweight)
#
# 共享元数据
代理
#
# 静态代理,实现同装饰
class TankTimeProxy implements Movable {
Movable m;
@Override
public void move(){
m.move();
}
}
# 动态代理,Proxy调asm生成代理类
Tank tank = new Tank();
Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader()),
new Class[]{Movable.class},
new Hander(tank)
);
class Handler implements InvocationHandler {
Tank tank;
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
return method.invoke(tank, args);
}
}
// 动态代理, CGLIB调asm,由于是继承,所以final类不能代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Tank.class);
enhancer.setCallback(new TimeMethodInterceptor());
Tank tank = (Tank)enhancer.create();
tank.move();
class TimeMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {
return methodProxy.invokeSuper(o, objects);
}
}
// Spring AOP: aspect指定代理类, pointcut指定被代理方法
行为型
#
观察者
#
# Observer, 对象变化,对观察者广播
public interface Observer {
public void update();
}
public class Observer1 implements Observer {
@Override
public void update(){}
}
public interface Subject{
public void add(Observer observer);
public void del(Observer observer);
public void notifyObservers();
public void operate()
}
public abstract class AbstractSubject implements Subject {
private Vector<Observer> vector = new Vector<Observer>();
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void del(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObservers(){
Enumeration<Observer> enumo = vector.elements();
while (enumo.hasMoreElements()) {
enumo.nextElement().update();
}
}
}
public class MySubject extends AbstractSubject {
@Override
public void operate() {
notifyObservers();
}
}
模板方法(TemplateMethod)
#
# 钩子函数
abstract class F {
public void m() {
op1();
}
abstract void op1();
}
class C1 extends F {
@Override
void op1(){}
}
状态(State)
#
# 状态便于扩展, 方法不便扩展。如果相反用switch
public class MM {
MMState state;
public void smile(){
state.smile();
}
}
public abstract class MMState {
abstract void smile();
}
public class MMHappyState extends MMState {
@Override
void smile(){}
}
# FSM例子,线程状态
public class Thread_ {
ThreadState_ state;
void move(Action a) { state.move(a);}
}
abstract class ThreadState_ {
abstract void move(Action a);
}
public class NewState extends ThreadState_ {
private Thread_ t;
@Override
void move(Action a) {
if ("start".equals(a.msg)) {
t.state = new RunningState(t);
}
}
}
public class Action {
String msg;
}
迭代器(Iterator)
#
public interface Iterator<E> {
boolean hasNext();
E next();
}
public interface Collection<E> {
Iterator<E> iterator();
}
class List<E> implements Collection<E> {
private class Itr<E> implements Iterator<E> {
@Override
public boolean hasNext(){}
@Override
public E next(){}
}
@Override
public Iterator iterator(){
return new Itr();
}
}
策略
#
# strategy, 封装多个算法类, 更换策略,调用方式一致
o->
public interface ICalculator {
public int calculate(String exp);
}
public class Minus extends AbstractCaculator implements ICalculator {
@Override
public int calculate(String exp) {
int arrayInt[] = split(exp, "-");
return arrayInt[0] - arrayInt[1];
}
}
public class AbstractCalculator {
public int[] split(String exp, String opt) {
String[] array = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
Icalculator cal = new Minus();
cal.calculate(exp);
备忘录(Memento)
#
# 快照
# Java序列化, ProtoBuf库
class C implements Serializable {
private transient List<Object> list;
}
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("")));
oos.writeObject(o1)
oos.writeObject(o2)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("")));
o1 = ois.readObject();
o2 = ois.readObject();
命令(Command)
#
# 别名Action或Transaction
# 配合组合实现宏命令, 配合责任链实现undo,配合备忘录实现事务回滚
abstract class Command {
abstract void do();
abstract void undo();
}
class InsertCommand extends Command {}
责任链(Chain of Responsibility)
#
interface Filter {
boolean doFilter(Msg m);
}
class HTMLFilter implements Filter {}
class FilterChain implements Filter{
List<Filter> filters = new ArrayList<>();
public boolean doFilter(Msg msg){
for (Filter f : filters) {
if (!f.doFilter(msg)) {
return false;
}
}
return true;
}
public FilterChain add(Filter f) {
filters.add(f);
return this;
}
}
FilterChain fc = new FilterChain();
FilterChain fc2 = new FilterChain();
Filter f = new Filter();
fc.add(f).add(fc2);
# ServletFilter
Filter1 implements Filter {
void doFilter(req, resp, chain) {
chain.doFilter(req, resp);
}
}
FilterChain implements Filter {
List<Filter> filters;
int curIndex = 0;
void doFilter(req, resp){
curIndex++;
if (curIndex < filters.size()) {
filters[curIndex].doFilter(req, resp, this);
}
}
}
访问者(Visitor)
#
# 内部结构不变,访问方式扩展
interface Visitor {
void visitCpu(CPU cpu);
}
class Visitor1 implements Visitor {
double price = 0.0;
@Override
void visitCpu(CPU cpu) {
price += cpu.getPrice() * 0.9;
}
}
class Computer {
Part cpu;
void accept(Visitor v) {
this.cpu.accept(v);
}
}
abstract class Part {
abstract void accept(Visitor v);
abstract double getPrice();
}
class CPU extends Part {
@Override
void accept(Visitor v){
v.visitCpu(this);
}
}
Visitor p = new Visitor1();
new Computer().accept(p);
p.price;
# Java类AST编译器Visitor, ASM
// 打印
class ClassPrinter extends ClassVisitor {
@Override
MethodVisitor visitMethod(){
print(name + "()");
retrun null;
}
}
ClassPrinter cp = new ClassPrinter();
ClassReader cr = new ClassReader("java.lang.Runnable");
cr.accept(cp, 0);
// 生成类
ClassWriter cw = new ClassWriter(0);
cw.visitMethod(ACC_PULIC + ACC_ABSTRACT, "compareTo", "(Ljava/lang/Object;)I", null, null).visitEnd();
cw.visitEnd();
MyClassLoader cl = new MyClassLoader();
byte[] b = cw.toByteArray();
Class c = cl.defineClass("pkg.Comparable", b, 0, b.length);
// 代理类
ClassReader cr = new ClassReader();
ClassWriter cw = new ClassWriter(0);
ClassVisitor cv = new ClassVisitor(ASM4, cw) {
@Override
public MethodVisitor visitMethod() {
MethodVisitor mv = super.visitMethod();
return new MethodVisitor(ASM4, mv) {
@Override
public void visitCode(){
visitMethodInsn(INVOKESTATIC, "TimeProxy", "before", "()v", false);
super.visitCode();
}
}
}
};
cr.accept(cv, 0);
cw.toByteArray();
解释器(Intepreter)
#
# 解释出AST
其它补充
#
元素模式
# 抽象各模式成元素,简化表示
actor
# 消息通信
reactor
# 事件轮循,注册回调,如libevent
proactor
# 注册事件回调,os通知触发回调
惰性求值
链式定义(配方),后自动触发(js tick调度)终止操作
dsl测试(如jasmine.js)