专栏内容:
- 手写数据库toadb
本专栏主要介绍如何从零开发,开发的步骤,以及开发过程中的涉及的原理,遇到的问题等,让大家能跟上并且可以一起开发,让每个需要的人成为参与者。
本专栏会定期更新,对应的代码也会定期更新,每个阶段的代码会打上tag,方便阶段学习。
开源贡献:
前言
当架构师对与产品框架进行了总体设计,期望负责人进一步设计实现时,在讲解总体设计时总时满怀期待,尤其是讨论工作量时,感觉改动很小,看到开发人员因难的样子,往往采取妥协,留有充余的时间。而现实的结果,往往与期待相差甚远。
概述
本文分享一些架构设计过程中遇到的有趣的事情,期待与各位共鸣,一起能共同成长。架构师常常会根据产品发展方向,客户需求,当前产品存在的问题,给出一些产品架构的调整或者优化的总体设计,期待开发人员能经过进一步细化设计后转化为代码落地。在这一过程中,会发生一系列期望与现实,沟通表达与接收理解的偏差,不断调整偏差的艰难过程经历后,才到达交付的终点。
设计预期
架构总体设计中各模块界线清晰,通过业务流程进行交互,各模块有自己的数据,对外接口,如同面向对象设计中各个对象一样,每个对象内部通过触发,维护更新自己的数据。
案例设计
假设有一个绘图软件,架构师设计可以支持三种图形的绘画,架构分为三层,上层是用户交互层,中间图形逻辑抽象层,下层图形算法层。
那么对于这样一个通用的三层架构,我们通常称为MVC,期待的C语言代码接口可能是这样的。
/* 用户交互层 */
int drawRectangle(int num, Vertex vertex[]);
int drawSquare(int num, Vertex vertex[]);
int drawTriangle(int num, Vertex vertex[]);
这一层处理与用户的交互逻辑,得到用户指令后,将用户输入信息转成下层接口的数据格式,调用下层接口处理。
/* 逻辑抽象层 */
typedef struct Context
{
Shape drawShape;
shapeProc start;
shapeProc draw;
shapeProc end;
}Context, *PContext;
PContext globalDrawContext = NULL;
/* 初始化画布,颜色,线型,背景等 */
int drawShapeStart();
/* 调用对应形状开始绘画 */
int drawShape();
/* 清理工作 */
int drawShapeEnd();
这一层起承上启下的作用,上层用户接口层的输入的数据形成globalDrawContext
本层的上下文数据,然后执行标准的三个动作即可。
-
调用
drawShapeStart
进行初始化环境的工作,用户每次输入的是部分关键信息,还有一些信息是通过对用户环境的检测获取,如画布的位置,大小,线条的形式,背景信息等等;同时根据用户需求的图形类型,初始化对应的初始化,绘画,结束处理接口;最后调用对应在图形的初始化接口。 -
再调用
drawShape
就是真正的执行绘画的动作了,所需要的数据已经准备齐全,根据上下文结构调用绘画接口即可。 -
最后调用
drawShapeEnd
,结束本次绘画;清理上下文数据,分配的内存,保存当前绘画后的画布等;
每种图形从用户层调用,都必需经过这三个标准动作,即可完成绘画的处理,当然每次绘画处理对应的数据和真正的图形处理接口根据当前上下文而不同。
/* 图形算法层 */
typedef struct Shape
{
int shapeType;
int color;
int lineType;
int background;
int num;
Vertex vertex[];
}Shape, *PShape;
int shapeStart(PShape shapeInfo);
int shapeEnd(PShape shapeInfo);
int rectangle(PShape shapeInfo);
int square(PShape shapeInfo);
int triangle(PShape shapeInfo);
图形算法层的实现就相对简单,这一层的数据是绘画图形所需要的Shape
数据结构,由上层传递给具体的绘画处理函数。每种图形定义了一种处理函数,来绘制对应的图形。每种图形只关心自己的图形算法即可,不需要整个系统运行情况,更不用直接关心用户层的情况。
新增设计
当某一天用户需要绘画一种新的图形-圆形,那么架构师认为数据结构方面在Shape
中增加半径定义,增加用户层绘画圆形的接口,在图形算法层增加圆形的算法处理,同时新增一种图形种类,这样在逻辑抽象层将圆形的用户接口和算法接口联系起来。
整体工作难度不大,算法都是常规算法,两个人可以进行并行开发,开发周期并不长。
实际情况
给大家讲解一下需求和总体设计。
嗯嗯,大致听明白了,大家边点头边说。
那就开始吧。
实际实现
经过一段时间,大家说开发差不多了,我们一起看一下吧,实际实现后就是如下样子:
/* 绘制长方形 */
int drawRectangle(int num, Vertex vertex[])
{
/* 关键代码 */
logic_drawRectangle(num, vertex);
}
int logic_drawRectangle(int num, Vertex vertex[])
{
algo_drawRectangle(num, vertex);
}
int algo_drawRectangle(int num, Vertex vertex[]);
/* 绘制正方形 */
int drawSquare(int num, Vertex vertex[]);
int logic_drawSquare(int num, Vertex vertex[]);
int algo_drawSquare(int num, Vertex vertex[]);
/* 绘制三角形 */
int drawTriangle(int num, Vertex vertex[]);
int logic_drawTriangle(int num, Vertex vertex[]);
int algo_drawTriangle(int num, Vertex vertex[]);
其它三种图形也是类似,有几种图形就有几份代码文件,看似结构清晰,每种图形的处理流程也是层次分明。
但是总感觉有点说不出来感觉,大家有什么建议吗?
增加需求
当某一天用户要求再增加一个圆形图形的绘制时,功能也是比较简单,一个人从头到尾再开发一套,新增一个圆形的代码文件。
发现bug
这就头疼了,有bug了,在绘制正方形时有个问题,幸好被很快定位和修补上了。 接下来要回顾,发现在其它图形中都存在,那么意味着每个图形都要修改一遍,工作量直接翻几倍。
总结
在软件设计到实现的过程中,除了编写设计,编写代码,还有很多沟通工作,尤其在多人多团队的开发模式下,每个人听到的,理解的,再思考消化后形成的结果,都是不一样的。因此,分工协作的团队,沟通能力变得更加重要,在面试时会被重点考查。
结尾
非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!
作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。