体系结构-声明性的。实现-势在必行。其他一切都是官僚主义

什么是建筑?建筑与设计有何不同?架构和实现之间的边界在哪里?你看到建筑了吗?可以测试架构吗?工程学和进化论的建筑方法有什么区别?什么是好的架构?建筑师的工作是什么?它与开发人员的工作有何不同?架构师可以使用哪些工具?是否可以与实现分开更改体系结构?建筑有DNA吗?







图片来自tomaszjaniak博客



向我们展示您的建筑



碰巧的是,您已经在一个项目上工作了几年,现在您正坐在代码中的手肘上,测试正在燃烧,笔记本电脑的散热器正在发出噪音,试图冷却被编译器过热的处理器的热量,仅需要几个小时-重构就完成了。然后,我们迫切需要删除所有内容并绘制项目的体系结构。已计划一个大客户,为了完成交易,有必要进行审核。在这种情况下,就没有架构图。因此,如果该项目仍然很小,并且其实际工作中的十几个开发人员在那里不需要任何体系结构,该怎么办?这是代码-一切都清楚了。但是没有出路。这是必要的-然后这是必要的。



如果您知道一切工作原理,则可以在一小时内绘制出任何产品的架构。通常,这足以进行审核。毕竟,审计的重点不是让外部人员真正了解您的产品架构。问题的全部重点是确定产品开发人员本身是否了解他们在做什么。如果您说话足够自信并且毫不犹豫地回答问题,一切都会顺利进行。但是,尽管如此,当故事结束时,蠕虫会在更深的某个地方安顿下来,这将使问题更加尖锐:但是,该产品实际上具有什么样的体系结构?毕竟,如果他们提出要求,也许其他人也有体系结构。如果我们没有它,这显然是一团糟。人们迫切希望做好一切,以便下次对体系结构负责。



您如何正确执行?您需要绘制图表,描述文档中的功能,然后将所有这些保持最新。然后将是建筑。但是,介绍了工作范围之后,很快就会意识到,所有这些都不值得花费时间。这是代码-一切都清楚了。如果有另一个客户来,那么在另一个小时内就可以绘制一个新图。



几年后,您可能会遇到相反的情况,用于描述另一种产品的体系结构的文档将再好不过了。当然,知道其他人的架构也很差很有用。但是,当一个项目的规模开始以数百万行代码来衡量,而开发人员的数量以数百为单位时,对体系结构的需求仍然变得很重要。



在这里,在工作流的框架内,各种架构图开始出现,架构提案开始写在功能上,所有这些都经过讨论,审查,验证,批准,当然,甚至在这些过程结束之前就已经过时了。不必说这些文档反映了应用程序代码的真实结构。当涉及到实现时,开发人员可能根本不阅读这些文档。或者正在执行与编写的完全不同的东西。有人误解了某人,或者迫切需要这样做,因此没有时间进行讨论。



也许一切都应该如此。也许,体系结构是围绕投机性文件的官僚机构,与现实脱节了吗?但是直觉告诉我们,毕竟没有。那么,“架构”又是什么呢?



建筑是...



如果您问“什么是建筑?”这个问题会怎样?十个专业开发商?如果您不浏览维基百科,他们会给出相同的答案吗?



架构既是一组重要的决策,又是元素的结构及其接口,规定,规则和协议的系统,维护秩序的解决方案,对全局问题的解决方案,交互作用的分解以及对系统及其生命周期的高级描述。部分,结构和行为的模式,难以更改或删除的成本或昂贵的东西,基本的决策和权衡等等。



架构也是应用程序如何实现其预期目的的方式。



API是一个体系结构,一个数据模式也是一个体系结构,以及模块和服务的结构。有一个应用程序伸缩体系结构,一个应用程序可靠性体系结构,一个组件交互体系结构和一个安全体系结构。当然,每个功能都有其自己的体系结构。所有这一切也是建筑。



所有这些都可以视为对“什么是建筑”这个问题的答案。 -也许是。一切似乎都正确,一切似乎都清晰。但这答案实际上有用吗,可以在实际工作流程中使用?并不是的。



您怎么知道决定是重要的还是根本的?什么是全球挑战?昂贵或便宜是什么意思?如何评估复杂度?高级别和低级别之间的边界在哪里?什么是订单?系统的目的是什么?



这些都是您也可以尝试回答的问题。制定定义,并举例说明,最坏的情况是组织决策过程。但这仍然会是有争议的,直观的,这取决于个人的看法,并且每个人的理解方式都略有不同。这意味着,总是存在基于以下事实的冲突:不同的人对同一情况的解释完全不同。开发人员会抱怨架构师在篡改实现细节,而架构师则在破坏体系结构。如果没有明确的界限,冲突是不可避免的。



每个人可能对架构是什么都有一些一般的了解。但是,很难说出一个经过正式验证和数学上精确的定义。



另一方面,如果您问“什么是实现?” -答案可能是明确的:“这是代码存储库的链接!”而且你不能与之争论。对此答案的解释毫无疑问或模棱两可。 1 +1 = 2,实现是代码。



而且代码很容易使用。如果您想了解实现,则可以在开发环境中打开项目。如果需要检查代码中的更改,则存储库中有分支。如果该发布该应用程序的新版本了,那么将启动测试。



当然,项目的结构可能会令人困惑,评审质量差,并且测试范围不完整。但是,至少在使用代码时,总是很清楚做什么和何时进行。



但是,如果架构像实现一样用代码表示,该怎么办?





现代开发中使用了许多主流编程语言。其中大多数是很久以前或很久以前出现的。尽管它们仍然不错,但它们仍然过时了。这些是弱类型语言:JavaScript,Python,PHP,Ruby和强类型语言:Java,C / Objective-C / C ++,C#。它们被新语言取代,这些新语言在同一平台的框架内试图解决长期存在的问题,向他们撒上句法糖,但是如果您放眼全球,则不引入根本的新概念:Swift,Kotlin,TypeScript,Go。这些都是基于面向对象范例构建的语言。另外,函数式编程方法已经获得了成熟的普及,既可以用列出的语言来实现,又可以用专门的语言来表示,但是不太受欢迎:Erlang,F#。实现实质性新概念的语言也开始流行:Rust,Haskell。



所有这些多样性有一个共同点:它们都是实现语言。这些编程语言都不是Architecture的表达。但是有一个例外-SQL。



SQL是唯一的声明式主流编程语言。它建立在关系代数模型上,具有狭窄的专业知识-处理存储的数据。但是,为什么仍然可以将SQL视为体系结构语言?



首先,SQL允许访问有关数据模式的元信息。您可以轻松地从数据库中获取表,列,关系,索引,视图,角色等的列表。存储模式的文档以及使其可视化的功能对于理解应用程序的结构有很大的帮助。数据模式描述是一种高级体系结构描述。



其次,SQL提供了一种数据查询语言,该语言允许客户端查询模式中描述的任何数据组合。如果没有查询语言,则对于客户端所需的每个数据模型,要么必须实现单独的API方法,要么客户端将必须对数据模式的不同部分进行多个API调用,并在其一侧组合所需的模型。查询语言的存在使得有可能从体系结构实现的描述中排除与用于根据通用方案获取特定数据模型的API方法的枚举相关联的细节。查询语言从体系结构的描述中排除了实现细节。



SQL提供了三个对于描述体系结构很重要的关键属性:



  1. 声明性-SQL使您可以将体系结构的描述与实现分开。
  2. 可分析性-SQL提供对数据架构的元信息的访问,该信息使您可以可视化,记录和分析其表示形式。
  3. 正确性-SQL允许您在数据模型上定义约束,这使得可以防止实施方案破坏各种数据完整性。


也许,SQL可以被称为以数据存储来描述体系结构的工具,但是显然不足以描述产品的完整体系结构。



描述架构的其他方式



SQL的直接类似物是GraphQL,它还允许您定义数据模式并提供通过查询语言对其的访问。同时,GraphQL建立在图论之上,而不是建立在关系代数模型上。与SQL相比,SQL较难使用层次结构,因此可以更自然地使用层次数据模型。



GraphQL通常被推广为客户端-服务器通信解决方案,但这不是其应用程序的唯一领域。同样,通过GraphQL,您可以提供服务器到服务器的通信,甚至服务器到基础的通信。现代数据库仅提供SQL接口,但不提供用于分层查询的便捷API,这一事实令人反感。



如果SQL是描述数据存储架构的体系结构的一种方法,则GraphQL允许您根据特定的应用程序领域在业务级别上描述数据架构的体系结构。从这个意义上讲,GraphQL允许您在更高级别上定义架构,更接近产品的实际应用领域。



代码模块和微服务以及它们的API和依赖项,也是在结构和关系方面表达架构的工具。



架构与实施



对于有十几个开发人员参与的小型项目,通常不需要对体系结构进行单独描述。如果项目代码编写得井井有条,结构合理,那么足以理解总体情况和发展方向。



随着项目的发展,出现了各种文档,描述了其总体架构以及新零件和主要改进的细节。当数十个人正在从事一个项目时,这是一种有效的方法。



但是对于一个相当大的项目,当有数百个开发人员时,这种方法开始失败。文件太多,它们的内容开始与《实施》越来越不同。以同样的方式向每个人表达思想变得越来越困难。组织了数十人的集会来讨论各种私人主题,而真正重要的更改可以实现而无需任何讨论。所有这些导致需要组织越来越多的流程,当某些流程必须提供某些东西,其他流程遵循,其他流程进行审查而其他流程却需要这样做时。官僚。结果,开发人员开始写更多的文档和更少的代码,这不是最重要的问题。



当然,官僚机构本身没有错。在任何工作中,其组织都很重要。问题在于每单位有用工作的官僚主义程度。如果要召开一次会议,您需要再举行两次会议,即三,四,五次会议,那么在任何地方都不再适合。



即使是关于开发人员可以自己做出什么更改的简单问题,因为这是一个实现,以及关于什么需要提出审查请求,因为这是一个体系结构,也开始引起麻烦。您必须提出各种架构触发器,即如果您更改数据架构或触及加密和安全性问题,则需要在架构上进行审查,而似乎没有其他主题,但这尚不确定。所有这些不仅需要制定并向数百名开发人员进行解释,而且还需要确保遵循所描述的规则。这样的过程将不断失败。



所有这些问题都与缺乏清晰的体系结构定义有关。



就像在存储库中明确地更改“ .java”文件表示实现上的更改一样,更改“ .architecture”文件也可以表示体系结构上的更改。当然,“。architecture”文件实际上并不存在。但是对于每个项目,您可以定义它的哪些方面与它的体系结构特别相关,并使其明确。



如果将数据模式的更改视为体系结构中的更改,则包含SQL迁移的文件必须引用体系结构。如果API也是体系结构的一部分,则可以以相同的swagger文件的形式定义API,并依赖它们。如果模块的结构是“架构”,则模块说明中的更改就是“架构”更改。等等。



并非可以通过标准方式来表达体系结构的所有方面。每个项目都有自己的细节。例如,如果产品使用权利,角色,订阅类型,附加组件等特定模型,则应考虑以某种合适的声明形式定义产品此方面的体系结构,从而从实现细节中强调体系结构的本质。当然,此类更改可能需要大量的代码返工。但是,与尝试在文档中描述其权限模型相比,这是在定义产品体系结构方面的一项重大投资。



用代码形式表示体系结构是可能的,只有这样才能清楚地定义什么是体系结构。此视图使得可以分析体系结构并自动生成有关体系结构的文档,该文档始终是最新的。其余所有:手工制作的文件,图表和图-官僚机构。



架构可以在代码中包含形式表达,只有这样才能在架构和实现之间定义明确的界限。并且需要这样的边界。



建筑工程与进化方法



在过去的半个世纪中,从瀑布模型到迭代开发,开发行业已经走了很长一段路。现在看来,该行业在这方面已经走得太远了。在某些地方,建筑师的工作不再像工程师甚至是园丁的工作,越来越多的人开始像季节性工的工作那样,其唯一目的是从杂草上除草。



工程与工艺的区别在于对自然规律和规律的理解,在此基础上人们可以进行计算和结论,设计解决方案,而无需进行实验。任何木匠都能制作出完全可以接受的凳子,但是需要使工程学知识使凳子最佳化的方法:轻便,可靠,稳定,简单且制造便宜。工程方法可让您以最少的努力快速获得最佳结果。不幸的是,在软件开发中,工程方法并非总是可行的。



通常,人们想要达到的结果是非常模糊的定义,许多影响解决方案体系结构的因素尚不清楚或根本不为人所知,解决方案本身的实现工作可能比详细阐述其体系结构更快,更便宜。这是迭代式开发方法如此受欢迎的原因之一。有时甚至无法衡量。



在最坏的情况下,体系结构的开发可以归结为以下事实:每个开发团队仅向架构师提供对其要实现的描述的审查。在这种情况下,架构师的工作被减少了。在这里你还没有忘记?您有考虑到这一点吗?这是错误的。您要在这里添加索引吗?如此反复迭代。



有必要除草杂草。但是,如果只这样做,花园会是什么样?花坛将在果树的阴影下凋谢,草莓和胡萝卜将交替出现,而所有这些都将被无数的路径浪费掉。这里很难谈论任何架构。



为了使建筑出现,建筑师必须至少完成园丁的工作。浆果和蔬菜应分开种植-结构和人们最常去的地方-您需要铺设道路-连接。观察细节,架构师可以主动采取行动,将在实现过程中出现的特定功能组织和系统化为单个结构。就像景观设计一样,建筑师可以塑造事件的自然过程,增强积极趋势并防止消极趋势。



在这里,我们需要在代码中明确定义架构。数据模式,模块和服务的结构,它们的API和交互规则。如果不定义这些工具,架构师要么陷入实施审查的泥潭,要么天真地希望开发人员真正遵守那里的某些文档中描述的规则,当然这不会发生。



如果对体系结构及其更改规则有正式的表述,这已经可以称为体系结构开发的进化方法。那还不错。但是我们应该限于此吗?



是的,最初的要求可能看起来很模糊,因素可能看起来很模糊,而且系统本身是如此复杂,以致于比设计容易。但是随着时间的流逝,这些事情开始变得清晰起来。凭借在架构开发方面的实践经验,其应用领域的组织细节越来越清晰。很明显,这种通用解决方案以五种不同的方式实现,并且用户遭受了这种多样性的困扰。有些东西不合适,需要移动,而另一些东西已经过时并被新的解决方案取代,因此需要将它们删除。而且新的发展不再显得那么新-我们已经实现了这一点。您还记得所有这些导致了什么吗?让我们立即进行操作,这样我们以后就不必重做。毕竟,一次正确地进行操作通常比必要时快。但这只是在您真的知道如何正确做的情况下。有了经验,这种理解就经常出现。



好的体系结构并不是先发展起来的,然后又有点组织起来的,而是整体的,对称的和有机的。可以采用一种工程学方法来开发体系结构,仅了解规则和模式可能需要一些时间。



特定项目的体系结构的正式定义不必是静态的。不推荐使用的API方法可以声明为“不推荐使用”,缺少的API方法可以声明为“未实现”。可以将代码中有意义的部分标记为放置在单独的模块中。您可以计划将表分成两部分,或将它们移至另一个数据库。等等。无需更改实现即可更改体系结构。实施将会赶上。而且为了赶上新手,可以通过在团队聊天中自动提醒来自动完成该过程。同样,开发人员在建筑文件中所做的更改可以自动转到建筑团队聊天中。



可以使用一种工程学方法来开发体系结构。



同时,不应认为建筑师的工作从根本上说要好于开发者的工作。她只是不同。首先,开发人员以命令式风格工作,而架构师的工作更具声明性。碰巧很难确定体系结构,但是实现是一个例程。反之亦然。



建筑与设计



术语“体系结构和设计”通常可以互换使用。您可以说:系统架构或系统设计。总的来说,这很清楚。但是,这些术语存在显着差异。



首先,设计意味着视觉,可以想象或看到的东西。方案,图表,模型。设计使您可以直观地显示实体之间的关系,交互的跟踪链,查看结构差异和类比。



但是,体系结构不仅是视觉的,而且可以包括规则和约束,推理和数学计算。视觉化效果较差的概念。



当然,两者都很重要。



如果在代码中显式定义了体系结构的重要方面,那将是很好的。但这还不够。使体系结构可视化及其自动化的内在原理非常重要。



如果体系结构包含数据模式,则必须对其进行可视化表示。模块具有依赖性-它们也需要呈现。如果有API,则应在其上有与服务结构直接相关的文档。等等。设计是建筑的视觉表示。



如果架构具有某些原则,例如“客户端应用程序只能访问某些类型的微服务,而不能访问全部”,那么如果存在通信模型,则可以自动检查它们。同样,您可以控制微服务和数据库之间的链接。如果数据模型的设计有某些规则,表的命名规则相同,则也可以自动检查它们。在开发中,使用了自动代码检查,可以对体系结构进行相同的检查。您可以在体系结构上编写自动测试。



结论



现代开发人员可以使用各种惊人的工具来简化工作。开发环境,构建系统,各种库和框架,基础结构服务和容器。开发人员不要在记事本中编写代码。



架构也是代码,使用架构可以实现与实现一样强大和丰富的工具包。 Google Docs不是唯一可以使用的架构工具,而且远非最佳。当然,现在可供建筑师使用的现成工具的范围并不比开发人员工具的范围宽。并非建筑师可以使用的所有东西都是开箱即用的。不过,情况还算不错。



许多工具已经问世数十年,例如SQL,您只需要学习如何正确使用它们即可。诸如GraphQL之类的新技术开始受到关注,它们提供了一个希望,随着时间的推移,描述业务域的任务将像描述存储域一样成为日常工作。提供了用于记录和可视化应用程序结构和API的工具,包括Swagger。您可以使用与测试实现相同的框架和集成工具来测试体系结构。



体系结构-声明性的。可能,文档的官僚作风永远不会从架构师的工作中完全消失,但是现在它的数量已经可以大大减少。架构也是代码,随着时间的推移,用于架构的可用工具会变得与用于实现的工具一样先进。我们会看到。



-

德米特里·马莫诺夫Dmitry

Mamonov)Wrike




PS,我从文章的开头列出了一些哲学问题,希望我能够给出非常具体的答案。至少那是我的观点。您是否在文章中找到了有用或新颖的内容?您自己如何回答这些问题?在评论中写。



All Articles