用Bit中的组件加速跨团队/项目的整合,轻松解决测试、数据模拟、文档等问题。
Bit的产品副总裁Itay Mendelawy的现场网络研讨会和演示会。
主要收获。
- 组件可以用来拥有架构中实体的表示,允许其他人在与服务集成时使用。
- 这样的'实体组件'是独立的,并与自己的发布周期解耦,提供一个关于 "什么是实体 "的单一真理来源。
- 这种方法改善了开发者的集成体验,当你在IDE中集成时,会有本地反馈,有模拟数据可供测试,有使用实例,还有文档。
- 在规模上,通过与语义版本(Semantic Versions)交流变化,以及实现代码库中所有实体的可发现性,与组件的整合可以实现更好的协作。
- 最后,组件还可以简化与外部服务的集成,同时减少因抽象而破坏变化的潜在影响。

转载。
所以,我认为我想为这些网络研讨会开始的主要事情之一是,从一个非常小的东西开始,它实际上对我们快速交付的能力,以及我们的开发人员的总体速度有很大影响。
这并不是Bit的一个具体功能,我们使用的流程可能与你们任何人做的不同,这只是我们在过去几年中设计的一种做法。我们使用组件,或组件驱动的方法,将应用程序的集成部分作为我们实际代码库的一部分。
今天我想和大家讨论一下这种做法,同时也讨论一下实际使用比特的这种方法的一些好处。
从本质上讲,我们的目标是什么,或者说我们在整合能力方面所缺乏的主要东西之一,是得到一些感觉像TypeScript的Definitely Typed的东西。想象一下,你可以为不同的API或不同的实体获得类型推理,这样你就可以在驾驶过程中为集成获得更好的保证。
而这就是我们在架构中用组件构建的东西。本质上,我们正在做的是建立一个基本的组件。它不是一个UI组件。在功能方面,它并没有很多 "动力",但它确实拥有我们架构中的一个特定实体。
比如说,我们是一个电子商务应用。我们可能想把发票作为一个实体来管理。我们可能想把一个货物、一个用户、一个产品作为一个实体来管理,因为这个实体在代码库本身的许多地方都有使用,无论是前端、后端、自动化步骤、中间件、数据库等等。
那么,这个实体组件是什么呢?它是一个非常基本的,主要是一个基于节点的组件。它包括一个类,允许我们对该实体有一个内存中的表示。这个内存表示法以后会帮助不同的开发者或消费者在他们的开发过程中使用这个实体。如果他们需要获得不同的属性或用户函数或任何功能,它将在一个标准化的地方。
这个实体组件还可以提供类型定义。这些类型定义可以是针对这个组件所需要的不同的API。如果我们有一个API,比如说我们处理发票,我们想有一个API来创建一个新的发票,那么这就有一个特定的接口,一个特定的合同。而且我们希望这个接口是我们可以使用的,并围绕它建立一个开发体验,而不仅仅是我们使用的实体本身。
一个实体组件也可以包含模拟数据。因为我们经常看到不同的开发人员在不同的项目上,他们想开始与外部服务集成到他们的应用程序。因此,他们需要弄清楚如何进行网络调用,数据结构是什么,他们需要开始为他们的测试或开发构建模拟数据。
但是,如果我们在拥有整个事物的同一个组件中已经有了模拟数据,那么他们就可以快速导入模拟数据,获得事物的渲染,并开始运行,因为他们知道这是他们已经从服务本身获得的数据类型。
它还可以包含从/到JSON函数。这使得我们可以通过电线传输这个实体或这个组件。如果我们需要将发票信息从后端服务发送到前端应用程序,我们需要通过电线,我们需要一种方法来实现从/到JSON。
我们还可以用额外的函数和方法来重载该实体。在我将要展示的例子中,我们可以看到我们甚至可以在不影响实体本身的情况下向它添加额外的参数。所以,如果我们发现许多开发者需要一个特定的功能,那么他们可以通过标准化的方式为所有可能使用该实体的消费者获得该功能。
所以,我知道这是一种非常高层次的抽象描述,但这就是为什么我想快速进入一个演示并展示更多一点。
在这里,我有一个非常基本的Express.js应用程序,用于处理用户。这个expression.js应用程序,因为我们用比特做的所有事情都与组件有关。这实际上是一个Bit组件,它运行在我的工作空间上,为我提供这个小服务器的功能。
它有一个本地的用户数据库,对吧,可以从中提取信息的东西。这个服务有非常基本的功能。让我们看看当我们在本地的时候,它看起来是怎样的。所以,我可以在一个特定的地方点击这个服务,你知道我们现在得到了信息。作为这个工作区的消费者,如果我想开始建立一个应用程序,我需要开始了解为我返回的这个JSON的结构是什么,以及这里的能力是什么。
我只有名和姓,如果我想获得全名的功能会怎样?我需要去要求后端团队添加这个新参数吗?我需要自己来实现吗?如果我有多个需要全名功能的应用程序,而我又要为不同的情况重复编写同样的功能,会发生什么?
解决所有这些问题的另一种方法是创建一个基本组件。这就是用户组件。它是一个Bit组件,所以它享有任何Bit组件的所有好处,有专门的交付管道,独立的版本控制,完全隔离,能够在任何项目中构建该组件,即使你的后端是.net或java。
你可以初始化Bit,并在需要时建立一个小类型的组件供你的前端消费者使用。很明显,如果你在一个node.js的后端,你的node.js实际上可以使用这个组件。而且它其实没有什么,它有一个非常基本的类型给我的用户。
如果我需要它与不同的服务有额外的接口,我可以有多个类型。一个在内存中代表用户的类。一个非常简单的toString函数来/自JSON对象,当数据通过电线传输时,我可以传输这个。模拟数据也被提供在一个独立的文件中,所以消费者可以在与用户的集成中,拉入所有这些模拟用户,作为他们与用户服务集成的一部分,等等。
这就是当我们建立一个新的领域,当我们在架构中建立一个新的API或一个新的服务时,我们可以开始考虑合同的问题。这是大多数团队已经在做的事情,因为你有一个后端团队、前端团队和一个架构师讨论什么是服务所需要的数据点、API条目、签名等等。你把它写下来,在文档中分享,然后每个团队按照他们自己的方式,根据所做的决定和讨论来实现这些组件。
所以,我们要做的第一件事是建立实体组件,并将我们刚刚同意的合同对准,什么是API签名,什么是被炮击的数据。我们只是建立一个基本的组件,并确保这对两个团队来说都是可用的,包括后端和前端。
而合同,而不是只有文件,我们实际上在我们的架构中得到了一些东西。这样,如果我们了解到我们有额外的需求,我们可以在组件上进行合作,并在那里添加额外的需求。
因此,例如,我可以去添加一个新的功能,叫做 "全名",我可以在这个组件的API上进行协作,而每个依赖于它的集成本身将得到这个功能。而且我们发现这比依赖文档要容易和干净得多,因为你们都知道,我们倾向于升级我们的代码而不是升级我们的文档。
正如我们所讨论的,这种方法的好处是,我们实际上有一个独立的发布周期,为我们架构的一部分,真正拥有该实体的概念。我们为集成提供开发人员的经验,而不是让人们阅读复杂的文档。
对于什么是这个实体,有一个单一的真理来源,这是以后的事情,如果文档过时了,因为项目仍然有这个依赖性,很容易把这个依赖性添加到另一个项目中,事情就会顺利进行。
当你构建时,当你使用你的组件时,你会得到设计时与你的IDE中的本地反馈的集成。你不需要等待远程服务调用或集成的漫长反馈循环,也不需要构建应用程序和服务。
它需要的计算机资源要少得多,因为这里有模拟数据。有接口,一切都在那里供你使用。还有所有其他可用于组件的功能,如文档、使用范例、测试、依赖性图表、组件比较等等。
现在,当我们考虑将比特加入到这个组合中时,我们开始从我们这边考虑这如何开始扩展,我们的选择是什么,真正使集成成为简单和轻量级的东西,而不是我们的冲刺和交付管道中非常耗时的项目。
如果已经有了现有的服务,并且已经有了促进这些实体和这些服务的组件,那么对于开发者来说,为新项目重新整合或重新引入这些实体就变得很容易。
例如,如果我们已经有一个管理用户和注册的系统,但现在我们需要建立一个应用程序或一个实现用户资料的新页面,那么我们就不必重读文档或重新认识服务的签名。
这只是通过Bit提供的不同的搜索功能来拉动已经存在的那种依赖性,我们基本上可以拉动所有这些实体,并将它们组成一个新的页面。
在一天结束的时候,我们作为开发者所做的很多事情就是操纵这些数据,并以不同的方式呈现出来,如果我们有一个关于这个数据点的真实来源,那么我们的很多工作已经为我们完成。
变化基本上是通过语义版本来沟通的。如果某个API有任何突破性的变化,我们就可以构建我们的整个软件,看看发生了什么,并在我们的IDE中真正了解到底改变了什么。鉴于我们使用的是typescript,就像一个强类型的集成,我们可以快速地深入进去,修复和解决那些可能会破坏的新变化。
另一件事是,因为在服务和消费者之间有另一层抽象,通过实体组件,有机会减少破坏性变化的影响。如果后端服务决定改变他们返回数据的方式,因为他们需要重组不同的项目,这里就有机会在实体组件中实现一个变化,将这种破坏性的变化抽象为一个潜在的小变化或补丁变化。
我们也用这个来简化与外部服务的整合。有时我们使用外部服务提供者,但我们也想把这些服务提供者引入,并使其成为我们代码架构的一部分。所以,我们会建立实体组件来促进与他们的沟通。
而最重要的也许是它为来自这些实体的不同需求的协作开辟了一条道路。就像我们之前展示的用户实体以及我们如何快速添加一个用户名功能一样,也许该实体的所有者有很多来自不同团队的请求,说 "嘿,我们不断地在发票上做这一个功能,我们总是想按日期排序,他们从来没有取消正确的日期,或者我们总是想有功能来解决这些问题"。
在我们的架构中,在管理'什么是发票'的地方为发票的排序能力添加一个地方是非常容易的。它使所有使用该功能的开发人员更容易得到一个标准的发票排序方式。
因此,我们甚至消除了很多重复的代码和由不同的开发人员完成的不同计算,并把它们放在一个单一的地方。我们知道,如果我们修复了这一个单一的地方,如果我们发现一个问题,其他的东西都会得到修复。
我想讨论另外三个例子来展示我们是如何使用这个的。
所以,首先,这些实体组件可以被使用,而且我们经常使用它们,在反应钩中。每当我们有一个从后端服务获取数据的钩子时,我们会尝试将这些数据转换回实体本身,并带来一个对象,而不是一个JSON,供另一个消费者解析,使数据获取的流程更加容易,更加标准化。
今天在这里使用的应用程序中,有一些案例是用来显示这些幻灯片的。我们实际上也是把不同的幻灯片作为实体来管理。而这与后端服务无关,幻灯片是一个纯前端的应用。但是如果我想创建一种新的幻灯片供人们使用或分享,我就可以使用幻灯片实体并建立更多类型的幻灯片。
我在这里展示的最后一个例子是叫做组件描述符的东西。正如你可能知道的,我们在比特做的一切都围绕着组件。组件是我们最关心的核心东西,它在我们的前端、后端、Bit CLI中都有。Bit CLI也有自己的前端,在我们的数据库中也有自己的后端,索引提供者,我们所做的一切都围绕着一个叫做组件的实体。而我们需要这个东西是标准化的,是大家都同意的。
因此,我们功能中的一个核心部分,甚至整个用户界面,告诉我们一个组件有哪些标签,不同的版本,每个组件有哪些功能,是一个叫做组件描述符的单一组件,它只包含一个特定组件的所有可能的信息。
组件描述符,像其他东西一样,有一个类型,一个类,更复杂的类显然来自于我们想使用的两个不同的函数,以及代表一个组件的模拟数据。正如你所看到的,模拟组件是很难的,所以这需要在一个地方进行分类,以便与该组件进行整合,并在其中建立更多的功能。这个小的组件没有太多的代码行,真的可以帮助我们这个团队更好地对齐,并与组件建立更好的集成。
每当有一个新的功能需要关于组件的数据,并需要了解如何很好地展示它,找到它,如何解析它,有一个单一的真理来源,已经被尝试和测试过,这就是我们使用的,也是真正帮助我们推动和建立更多与组件有关的功能。所以,这就是我们在比特建立和规范组件结构的方式。
我想讨论的最后一个项目是如何开始使用这个。如果这是你感兴趣的东西,如果这是你觉得对你的团队有价值的实验,我建议从建立一个单一的组件开始,包括一个类、类型、一堆函数、模拟数据,把它拉到Bit中,看看如何能让你的集成更简化,如何能建立一个协作流,如何能在这个实体上建立讨论。
你可能会发现,组织里有不同的利益相关者,他们对这个实体有不同的想法和不同的要求,这可以帮助你真正建立围绕这个实体的讨论。
你不必把大海煮沸,把所有的实体都作为组件来使用。如果你从一个实体开始,并且这个流程是有意义的,那么你就可以反复冲洗和重复,再来一遍。你可以把我们分享的任何一个例子,用Bit fork来分叉它们。也会有一个新的模板来使用,基本上是你需要开始的一切。
另一件将与此分享的事情是,我们用来真正用比特建立幻灯片的这个小应用程序,也将与网络研讨会和所有资源一起分享。所以,如果你想尝试一下,并在本质上建立幻灯片和React,这也是一种可能性。
非常感谢你的时间。
在这里查看网络研讨会的幻灯片。
了解更多
如何用组件更快整合》最初发表在《Bits and Pieces》杂志上,人们通过强调和回应这个故事来继续对话。