- 论坛徽章:
- 0
|
第二部分,接口
至今我们仍然没有真正定义一个接口究竟是什么。我们知道,我们更愿意基于一个消息传递的基础架构来构建系统,因此,接口显然必须定义为消息的集合。于是就有了我们最初的想法:一组消息的集合,其中每条消息都有名称,以及一组类型化的参数。
interface IInfoScreen { message expectedAircraftArrivalUpdate(id: ID, time: Time) message flightCancelled(flightID: ID)...}
当然,同时还需要具备定义数据结构的能力。因此,我们添加了这样的内容:
typedef long IDstruct Time { hour: int min: int seconds: int}
在对接口进行了一段时间的讨论之后,我们现在注意到简单地将接口定义为一组消息还远远不够。我们希望做到的最小要求是能够定义消息的方向:它是流入端口还是流出端口?或者更一般地说,系统中存在哪些消息交互模式?我们识别出了好几个,这里是oneway和request-reply的范例:
interface IAircraftStatus { oneway message reportPosition(aircraft: ID, pos: Position ) request-reply message reportProblem { request (aircraft: ID, problem: Problem, comment: String) reply (repairProcedure: ID) }}
真的是消息吗?
我们对各种消息交互模式进行了长时间的讨论。显然,消息的其中一种核心用例就是将各种资源的状态更新发送到各个对其关注的部分。例如,如果航班因为飞机的一个技术问题而延误,则该信息就会被发送到系统的所有InfoScreens中。我们为一个确切状态项的“广播式”完整更新、增量更新、无效更新等方式建立了必需的几种消息原型。
然而,现实却给了我们沉重的打击:我们一直在一种错误的抽象中工作!虽然消息传递对于这些事项而言是一种适合的传输抽象,但我们真正谈论的其实应该是复制的数据结构(replicated data structures)。基本上,所有的这些结构都采用同样的方式工作:
定义了一个数据结构(例如FlightInfo)。
系统保持对这样一组数据结构的跟踪。
一组数据结构会被几个组件所更新,而且,通常这组数据结构会被众多其他的组件所读取。
从发布者到接收者的更新策略总是包括对这组数据结构中所有项的完整更新,对一个或多个项的增量更新,无效更新等。
当然,一旦我们了解到除了消息之外,系统还包括额外的核心的抽象,我们就应该将它添加到我们的架构语言中,并能够像下面所示的方式进行编写。我们定义了数据结构和复制项。然后,组件能够发布(publish)或者使用(consume)这些复制的数据结构。
struct FlightInfo { from: Airport to: Airport scheduled: Time expected: Time ...}replicated singleton flights { flights: FlightInfo[]}component DelayCalculator { publishes flights}component InfoScreen { consumes flights}
毫无疑问,上面的描述比基于消息的描述更准确。系统能够自动地衍生出完整更新、增量更新和无效更新等需要的各种消息。这一描述同样清晰地反映了实际的架构意图:比起那种仅仅表达了我们希望如何去做(发送状态更新消息)的较低级的描述,新的描述方式更好的表达了我们希望做什么(复制状态)。
当然,我们还不能停下前进的脚步。现在,我们拥有了作为“头等公民”的状态复制,就能够为它的技术规范添加更多的信息:
component DelayCalculator { publishes flights { publication = onchange }}component InfoScreen { consumes flights { init = all update = every(60) }}
上例的意思是,只要底层的数据结构的内容发生改变,发布者就会发布复制的数据。然而,InfoScreen只需要每隔60秒进行一次更新(当它刚启动的时候,会对数据作一次完整的加载)。根据这一信息,我们能够产生出所有需要的消息,同时为参与者生成一个更新时间表。
更多内容?
在余下的讨论中,我们识别了架构的其他几个方面,并为它们添加了语言抽象:
为了解决版本冲突,我们增加了一种方法,可以将一个已经存在的组件指定为按照新版本(替换)方式执行。工具能够确保“即插即用的兼容性”。
为了能够表达消息的语义,以及它们对系统状态的影响,我们引入了前置条件和后置条件。我们还扩充了组件的概念,将stateful作为可选项。
最后,我们为组件添加了可配置参数。组件会指定参数,而组件实例则必须为它们指定值。
结论
采用这种方法,我们能够快速地把握系统的整体架构。我们还因此能够区分开“希望系统做什么”和“系统如何实现它”:这样一来,技术层面的讨论仅仅属于为此处给出的概念性描述提供实现细节(当然是非常重要的实现细节)。我们明白无误地理解了不同术语所代表的含义,并给出了明确的定义。组件这一模糊的概念在这个系统中具有了正式的、明确界定的含义。
当然,它并没有到此为止。下一步要讨论的是如何为组件的实现进行编码,以及讨论系统的哪一部份可以被自动生成。更多内容参见下一节。 |
|