许式伟的架构课
许式伟
七牛云 CEO
84946 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 89 讲
许式伟的架构课
15
15
1.0x
00:00/00:00
登录|注册

60 | 架构分解:边界,不断重新审视边界

不断重新审视边界
回到最初的需求
IO DOM 模式
Visitor 模式
全局性功能的设计
IO 子系统的需求与初始架构
接口的审视
模块的业务边界
架构分解:边界,不断重新审视边界

该思维导图由 AI 生成,仅供参考

你好,我是七牛云许式伟。
在上一讲 “59 | 少谈点框架,多谈点业务” 中,我们强调:
架构就是业务的正交分解。每个模块都有它自己的业务。
这里我们说的模块是一种泛指,它包括:函数、类、接口、包、子系统、网络服务程序、桌面程序等等。
接口是业务的抽象,同时也是它与使用方的耦合方式。在业务分解的过程中,我们需要认真审视模块的接口,发现其中 “过度的(或多余的)” 约束条件,把它提高到足够通用的、普适的场景来看。

IO 子系统的需求与初始架构

这样说太抽象了,今天我们拿一个实际的例子来说明我们在审视模块的业务边界时,需要用什么样的思维方式来思考。
我们选的例子,是办公软件的 IO 子系统。从需求来说,我们首先考虑支持的是:
读盘、存盘;
剪贴板的拷贝(存盘)、粘贴(读盘)。
读盘功能不只是要能够加载自定义格式的文件,也要支持业界主流的文件格式,如:
Word 文档、RTF 文档;
HTML 文档、纯文本文档。
存盘功能更复杂一些,它不只是要支持保存为以上基于文本逻辑的流式文档,还要支持基于分页显示的文档格式,如:
PDF 文档;
PS 文档。
对于这样的业务需求,我们应该怎么做架构设计?
我第一次看到的设计大概是这样的:
type Span struct {
...
SaveWord(ctx *SaveWordContext) error
SaveRTF(ctx *SaveRTFContext) error
LoadWord(ctx *LoadWordContext) error
LoadRTF(ctx *LoadRTFContext) error
}
type Paragraph struct {
...
SpanCount() int
GetSpan(i int) *Span
SaveWord(ctx *SaveWordContext) error
SaveRTF(ctx *SaveRTFContext) error
LoadWord(ctx *LoadWordContext) error
LoadRTF(ctx *LoadRTFContext) error
}
type TextPool struct {
...
ParagraphCount() int
GetParagraph(i int) *Paragraph
SaveWord(ctx *SaveWordContext) error
SaveRTF(ctx *SaveRTFContext) error
LoadWord(ctx *LoadWordContext) error
LoadRTF(ctx *LoadRTFContext) error
}
type Document struct {
...
TextPool() *TextPool
SaveWord(stg IStorage) error
SaveRTF(f *os.File) error
SaveFile(file string, format string) error
LoadWord(stg IStorage) error
LoadRTF(f *os.File) error
LoadFile(file string) error
}
从上面的设计可以看出,读盘存盘的代码散落在核心系统的各处,几乎每个类都需要进行相关的修改。这类功能我们把它叫做 “全局性功能”。我们下一讲将专门讨论全局性功能怎么做设计。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文探讨了在架构设计中审视模块的业务边界时需要采用何种思维方式,以IO子系统为例进行了详细分析。首先介绍了IO子系统的需求和初始架构设计,指出了全局性功能架构设计的不足之处。随后,引入了Visitor模式作为一种解决方案,并分析了其优缺点。作者提出了架构设计的KISS原则,强调了业务语义表达上的准确无歧义。通过对比不同架构设计方案的优劣,读者可以更好地理解架构设计中的边界审视和技术特点。文章还讨论了IO DOM模式和需求分析中的细节,强调了在架构设计时需认真细致地过一遍所有的用户故事,以确认架构的适应性。最后,文章提到了下一期的话题,并鼓励读者对架构设计进行思考和讨论。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《许式伟的架构课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(17)

  • 最新
  • 精选
  • Sam
    许大,请教您一个问题。文中提到的如下代码片段: func Save(src interface{}, format string, doc IoDocument) error func Load(src interface{}, doc IoDocument) (format string, err error) 其中format参数有何用意,麻烦指点下。 第二个: func Save(dest interface{}, format string, doc IoDocument) error 我没想到改造方法,只想到了增加了 func Export(dest interface{}, format string, doc ViewDocument) error,这种方式,感觉好Low

    作者回复: 1、format就是要保存的文件格式; 2、其实你说的是一个好方法,我也用的是这个方法。

    2019-11-27
    5
  • 木瓜777
    项目经常在开始前,根本不知道具体业务需求,而是不断迭代的,请问怎么进行 良好的架构设计呢?

    作者回复: 1、走进用户;2、整理/梳理需求,做需求分析,千万别跳过需求分析这个关键步骤就设计

    2021-04-16
    3
  • 老大,go语言的入门书介绍一下,go语言擅长做啥了

    作者回复: 网上随意买一本都可以,Go语法确定性较强,掌握门槛比较低,关键在用起来。Go能够用的领域可以很广泛,主要做后端开发,单我甚至也用它做过游戏。

    2019-11-26
    2
  • Bachue Zhou
    感觉什么约束都没有的 interface{} 不该出现在重要的接口里 不可能真的什么约束都没有 肯定会要求实现某些接口或者约定了某种反射方式 还是应该在接口里体现出具体的约束细节

    作者回复: 是这样。大部分情况下不应该用 any 类型,除非有什么让人信服的特殊理由。

    2019-12-07
    1
  • will
    介绍IO DOM 模式时提到有两套DOM,一套是 IO DOM我可以看到在代码中反映,但是说另外一套是Document 类及其相关的接口,实在理解不来... 相关接口是什么接口,好像示例代码省略了很多?

    作者回复: 一般来说,业务dom和io dom是超集关系

    2020-05-29
  • 丁丁历险记
    最近买了打印机,pdf 打出来模糊,wps pdf 转word 想的挺好,实施起来各种坑。 思来想去,还是github 上找找pdf 转html的代码,毕竟ai 很成熟了。 然后html 打印。 毕竟对开发来说,调html样式 比编写word 容易太多。

    作者回复: pdf 转 word 的确比较复杂,这里没有讨论。

    2019-11-26
  • 落石
    func Save(dest interface{}, format string, func () interface{} docmentLoader) error 由调用方决定 document 的类型。 1. 将document也调整为父子类的形式。但隐约感觉到老师好像不太赞同继承? 2. 或者在调用时强转为 SaveWord 或 SavePDF 中的 IoDocument 和 ViewDocument

    作者回复: 仔细想想,是否可以解决问题

    2019-11-26
  • 丁丁历险记
    这下好了,满脑子架构就是业务的正交分解了。。。。。
    2019-11-26
    10
  • 许式伟-七牛云(已满)
    其实,这里面有一个隐含的决策没有交代,为什么有引入 IO DOM,直接拿核心系统的 DOM 来作为 IO 系统依赖行不行?欢迎留言探讨。
    2019-11-26
    4
    6
  • 越来越有味,这系列文章需要反复研究
    2019-11-26
    5
收起评论
显示
设置
留言
17
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部