3.267. 细节的丢失
本文尝试从一个更容易理解的角度探讨一下架构设计是什么。
我们建立一个数据结构:
class Student {
private:
string Name;
bool IsBoy;
int Age;
static class Student gAllStudents[MAX_STUDENT_NUM];
public:
Student(string Name, bool IsBoy, int Age);
class Student *FindByName(string Name);
};
这是代码,但不是全部的代码,但我们看了这个数据结构,我们就能拼出这个代码一部分的图样来:它把每个学生封装成一个Student对象,保存在一个数组里面,用name作为index进行查找。
至于怎么查找,是顺序比较,还是基于Hash来抽取,这里没有说。如果我们用这个数据结构作为抽象,那么如何查找这件事情,就是被抽象的部分。所谓“不知”。我们既不关心它是这样,也不关心它不是这样。我们关心的是:我不用那个做我其他逻辑的根。
这就是架构设计的核心。架构设计是其他设计“架子”,是其他设计可以依赖的“根”。所有坚挺的逻辑,都需要其他逻辑为基础,架构设计自身也不例外。架构设计是建立一个逻辑,这个逻辑有自己的根,一路搭建上去,每个下级逻辑都有其他的根去支撑。但它不碰其他“不知”的部分,把这些部分留给下一级设计作为自由度(如图3.9):
图 3.9 架构设计的知和不知
所以,架构是精确和不完整的。它的作用是让我们看看在这么粗疏的逻辑链构建中,是否都有不可逾越的逻辑障碍,导致这件事情做不成。这种被单独拉出来的逻辑链,就是我在其他地方描述的“逻辑闭包”,也是很多架构设计资料中说的“视图”。只是强调点不同。逻辑闭包更强调逻辑的自洽性,而视图更关注逻辑抽象的分类。
我们可以有无限的抽象的可能性,可以有无数的“视图”,那种视图最有利于我们发现未来细节中的破绽,这取决于我们如何抽取属性。所以人们常常认为这是一种“艺术”,因为它和其他“艺术”,比如舞蹈,绘画,写作一样,关键在于你抽取哪个属性。如果追究它的本源,是因为抽象是个“机器学习”的结果,是人脑在大量的细节训练后,单独在大脑中留下的一组参数,每个人的训练集不同,造就了不同的训练结果。所以,同一个抽象,在不同的人脑子中复现为不同的样子,而做架构设计,是希望这这个模糊的范围内,取得一定程度的共识,并把它复现现实中(最终实现出产品)。
所以,我们进行抽象,成本都在逻辑的关联上,关联少的逻辑,我们就不作为我们视图的一部分。比如,在实际操作中,上面这个数据结构有很多东西我们其实是不关心的。比如这个IsBoy,或者也许以后我们会需要一个IsTallerThan180mm的属性,但这些属性,和它关联的逻辑仅仅就是“如何显示”,其他逻辑和它一点关系没有。这种属性,我们就希望忽略。
所以你看到更多的构架描述会是这样的:
图 3.10 学生数据结构建模
我们放弃掉了更多不影响其他逻辑的条件,把它们填到“不知”中。这样那个条件就是可以变化的,这样,我们在可以在另一个上下文中决定要不要它。比如我们这里讨论要不要IsBoy这个属性,你有什么条件来做判断呢?这个属性的判断条件是:“用户是否想知道这个学生的性别”,这个和“我们需要通过名字查找一个学生”这个逻辑,一点关系没有。你要正确地,详细地描述这个学生的所有属性,强行把“性别”这个属性放上来,为了判断这个属性是否正确被使用,你就需要进入另一个逻辑空间,去问:“到底要不要显示学生的性别?”这就把很多的信息放到同一个逻辑空间内,你脑子就处理不了了。
所以,抽象的过程,其实是一个重要性和关联性不断进行判断的过程,而重要性和关联性这两个属性,在每个具体场景中都不是一样的,所以架构设计没有固定的方法,只有针对具体问题的反复判断。