如何跨不同的编程语言分享业务概念?

时间:2012-08-03 20:01:12

标签: c# c++ python serialization cross-language

我们开发了一个分布式系统,该系统是用不同编程语言(C ++,C#和Python)实现的组件构建的,并通过网络相互通信。 系统中的所有组件都以相同的业务概念运行,并且在这些概念方面也相互通信。

结果,我们在以下两个挑战中奋力拼搏:

  1. 保持我们的业务概念代表这三种语言同步
  2. 跨这些语言对我们的业务概念进行序列化/反序列化
  3. 这个问题的一个天真的解决方案就是定义相同的数据结构(和序列化代码)三次(对于C ++,C#和Python)。

    不幸的是,这种解决方案有严重的缺点:

    • 它创造了很多“代码重复”
    • 需要大量的跨语言集成测试才能使所有内容保持同步

    我们考虑的另一个解决方案是基于ProtoBufs或Thrift等框架。这些框架有一个内部语言,其中定义了业务概念,然后这些框架自动生成C ++,C#和Python(以及序列化逻辑)中这些概念的表示。

    虽然此解决方案没有上述问题,但它还有另一个缺点:这些框架生成的代码将表示底层业务概念的数据结构和序列化/反序列化这些数据结构所需的代码耦合在一起。 p>

    我们认为这会污染我们的代码库 - 我们系统中使用这些自动生成的类的任何代码现在都“熟悉”这种序列化/反序列化逻辑(严重的抽象泄漏)。

    我们可以通过我们的类/接口包装自动生成的代码来解决它,但这会让我们回到原始解决方案的缺点。

    任何人都可以推荐解决所述问题的解决方案吗?

7 个答案:

答案 0 :(得分:4)

列夫,你可能想看看ICE。它提供面向对象的IDL,并映射到您使用的所有语言(C ++,Python,.NET(据我所知,所有.NET语言,而不仅仅是C#))。虽然ICE是一个中间件框架,但您不必遵循其所有策略。

特别是在您的情况下,您可能希望在ICE IDL中定义组件的接口,并将它们作为代码的一部分进行维护。然后,您可以生成代码作为构建例程的一部分并从那里开始工作。或者你可以使用ICE给你的更多力量。

ICE支持C ++ STL数据结构并且它支持继承,因此它应该为您提供足够强大的形式,以便随着时间的推移逐步构建您的系统,具有良好的可维护性。

答案 1 :(得分:2)

好吧,曾几何时MS试图用IDL来解决这个问题。好吧,实际上它试图解决的问题不仅仅是定义数据结构,但是,无论如何,这些都是过去的事情,因为这些日子里没有一个心智正常的人会去COM路线。

要查看的一个选项是SWIG,它应该能够移植数据结构以及跨语言的实际调用。我自己还没有做到这一点,但它有可能将序列化和数据结构与protobufs紧密结合。

然而,你应该考虑上述耦合是否是一件坏事。什么是理想的解决方案?据说它可以做两件事:它根据一个定义生成跨多种语言的兼容数据结构,它还提供序列化代码将它们拼接在一起 - 但是在一个单独的抽象层中。我们的想法是,如果有一天您决定使用不同的序列化方法,您可以切换出该层,而无需重新定义所有数据结构。所以考虑一下 - 实际上有多么真实地期望有一天只切换序列化代码而根本不接触接口?在大多数情况下,序列化格式是最永久的设计选择,因为您通常会遇到向后兼容等问题 - 所以您愿意立即支付多少开发成本,以便能够在理论上将其拉出来。未来?

现在让我们假设存在这样一种工具,它将数据结构生成与序列化分开。让我们说,2年后你决定需要一个完全不同的序列化方法。除非此工具还支持可插入的序列化格式,否则无论如何都需要开发该层,以便将现有结构与新的序列化解决方案相结合 - 这与完全选择新包的工作量大致相同。因此,满足您需求的唯一真正可行的解决方案不仅支持所有语言的数据类型定义和代码生成,而且不仅与序列化无关,而且还可以实现您希望切换到的未来序列化格式 - 因为如果它只对序列化格式不可知,则意味着您仍然需要自己实施 - 使用所有语言 - 这不是&#39 ;重新定义一些数据结构的工作要少得多。

所以我的观点是序列化和数据类型定义经常在一起的原因 - 它只是最常见的用例。我会仔细研究一下您希望能够使用所需的抽象级别实现什么,想一想开发这样一个解决方案需要做多少工作以及它是否值得。我确定这是做这件事的工具,顺便说一下 - 可能是昂贵的专有类,每张许可证的成本为1万美元 - 我认为同样的论点也适用于此 - 它可能只是过度工程化。

答案 2 :(得分:1)

我同意Tristan Reid(包含业务逻辑)。 实际上,几个月前我遇到了同样的问题,然后偶然发现了“Unix编程艺术”一书(免费提供online)。引起我注意的是将策略与机制分离的理念(即来自引擎的接口)。现代编程环境(如.NET平台)尝试将所有内容集成到单个域下。在那些日子里,我被要求开发一个必须满足以下要求的WEB应用程序:

  1. 必须很容易适应用户界面的未来趋势,而无需更改核心算法。

  2. 必须通过不同的界面访问它:web,命令行和桌面GUI。

  3. 它必须在Windows和Linux上运行。

  4. 我打赌用C / C ++完全开发机制(引擎)并使用本机OS库(POSIX或WinAPI)和良好的开源库(postgresql,xml等等)。我开发了引擎模块作为命令行程序,我最终实现了2个接口:web(使用PHP + JQuery框架)和桌面(.NET框架)。这两个接口都与机制无关:它们只是通过调用Windows中的CreateProcess()或UNIX中的fork()等函数来启动核心模块可执行文件,并使用管道来监视它们的进程。

    我不是说UNIX编程哲学适用于所有目的,但我从那时起应用它并取得了良好的效果,也许它对你也有用。选择实现机制的语言,然后使用另一种使界面设计变得容易的语言。

答案 3 :(得分:1)

  

系统中的所有组件都以相同的业务概念运行并进行通信   在这些概念方面也是另一个。

当我找到你的时候,你已经将你的系统拆分成不同的部分,通过定义良好的接口进行通信。但是你的接口共享你称之为“业务概念”的数据结构(很难理解而没有看到一个例子),并且由于这些接口必须为你所有的三种语言构建,所以你在保持它们“同步”时会遇到问题。

当保持接口同步会出现问题时,您的接口显然过于宽泛。使用不同的解决方案有不同的可能原因。

可能的原因1 - 您过度概括了您的界面概念。如果是这种情况,请在此重新设计:将泛化推广到板上并创建只有它们必须广泛的接口。

可能的原因2:用不同语言编写的部分不处理单独的业务案例,它们之间可能有“水平”分区,但不是垂直分区。如果是这种情况,则无法避免接口的广泛性。

如果原因2是您的问题,代码生成可能是正确的方法。如果现有的代码生成器不满足您的需求,为什么不编写自己的代码生成器呢?在C#中定义接口,例如作为类,引入一些元属性,并在代码生成器中使用反射,在生成相应的C ++,Python以及“实际使用的”C#代码时再次提取信息。如果您需要使用或不使用序列化的不同变体,也可以生成它们。一台工作的发电机应该比几天更省力(YMMV取决于您的要求)。

答案 4 :(得分:0)

您可以将业务逻辑包装为Web服务,并使用所有三种语言调用它 - 只需一个实现。

答案 5 :(得分:0)

您可以使用UML建模器等工具对这些数据结构建模(因为它可以为所有人生成代码,因此可以想到Enterprise Architect),然后直接从模型生成每种语言的代码。

虽然我会密切关注之前关于使用XSD的评论。

答案 6 :(得分:0)

我会通过使用某种关于域实体的元信息(XML或DSL,具体取决于复杂性)来实现这一目标,然后针对每种语言进行代码生成。这将减少(手动)代码重复。