SOA 更新请求粒度和空值
我们正在努力实现 SOA 企业...
给定更新成员详细信息的三个选项,我们如何设计合同?
业务流程非常简单。客户致电(或自行登录)并更新他们的个人详细信息,以便我们获得最新的详细信息。客户雇主还可以提供会员详细信息(这将是批量的 - 可能一次 10 到 1000 个)。这样我们以后才能正确地与他们沟通。我们有多个后端系统。
详细信息包括:
- 电话号码、
- 地址、
- 电子邮件、
- 姓名或公司名称、
- 联系人、
- 税号
- 、婚姻状况
- 、吸烟者状况
目前的业务规则是: 如果已提供有效的税号,则无法再次提供。 (可以被覆盖)如果存在有效的地址详细信息,雇主无法更新它们,只能在第一次提供。
选项 1: 一项操作,Member.UpdateDetails
- 仅创建和管理一项服务。
- 如果业务规则增长,该服务的凝聚力可能会降低。
- 存在必须区分指定应删除某些内容和保留其原样的问题。
- 单一工作单元、单一事务。
选项 2: 分解为四个操作:Member.UpdateContactDetails;会员.ProvideTaxFileNumber;成员.更新名称; Member.UpdateDemographics
- 可能会简化单个操作 - 将复杂性分散到四个操作中。
- 仍然存在必须区分指定应删除某些内容和保持原样的问题。例如,如果我只想指定吸烟者状况而不指定婚姻状况怎么办?
- 需要进行一些深入的分析才能弄清楚如何正确地对它们进行分组 - 凝聚力取决于业务流程。
- 更多需要编写和维护的服务。
- 事务成为一个问题——调用者处理多个事务?
选项 3: 进一步细分为:Member.UpdateAddress;会员.更新业务详情;会员.UpdateContactNumbers;会员.更新联系人;会员.更新电子邮件地址;会员.更新邮寄地址;会员.更新物理地址;等。
- 消除了必须区分指定某些内容应删除与保留原样的问题。
- 业务规则可以在任何操作中轻松发展。
- 需要编写和维护大量服务。
- 事务成为一个问题——许多事务是由调用者处理的?
- 开始看起来像属性设置者/CRUD - 显然不行。
在选项一或二中,假设呼叫者只想更新家庭电子邮件地址 - 我不能指望客户完成整个消息 - 客户是否会留下所有其他标签? 处理此问题的公认的、明显的、直观的模式是什么?
如果这确实是该模式,那么客户端如何清除该字段,或将其设置为空?在 . NET,在服务器代码中我看不到明显的方法来区分不已提供且为空。由于它并不明显,我预计这不是一种可接受的模式。
We are striving towards an SOA enterprise...
Given three options for say updating member details how do we design the contract?
The business process is quite simple. The customer calls (or logs in themselves), and updates their personal details so that we have the latest details available. The customers employer can also supply members details (this will be in bulk - potentially 10s of 1000s at a time). This is so we can communicate with them correctly in the future. We have multiple back end systems.
The details are:
- Phone numbers,
- Addresses,
- Email,
- Name or company name,
- Contact person,
- Tax File Number,
- Marital Status
- Smoker status
As it stands now the business rules are:
If a valid tax file number has already been supplied, you cannot supply it again. (can be overridden) If valid address details are present, the employer cannot update them, only supply them the first time.
Option 1:
One operation, Member.UpdateDetails
- Only one service to create and manage.
- If business rules grow, this service could become less cohesive.
- Has the problem of having to differentiate between specifying that something should be removed versus leaving it as is.
- Single unit of work, single transaction.
Option 2:
Break down into four operations: Member.UpdateContactDetails; Member.ProvideTaxFileNumber; Member.UpdateName; Member.UpdateDemographics
- Potentially simplifies the single operation - spreads the complexity over the four operations.
- Still has the problem of having to differentiate between specifying that something should be removed versus leaving it as is. For example what if I only wanted to specify smoker status without marital status.
- Requires some deep analysis to figure out how to group these correctly - The cohesiveness depends on the business process.
- More services to write and maintain.
- Transactions become a concern - multiple transactions handled by the caller?
Option 3:
Break down into smaller still: Member.UpdateAddress; Member.UpdateBusinessDetails; Member.UpdateContactNumbers; Member.UpdateContactPerson; Member.UpdateEmailAddress; Member.UpdateMailingAddress; Member.UpdatePhysicalAddress; etc.
- Removes the issue of having to differentiate between specifying that something should be removed versus leaving it as is.
- Business rules can evolve easily in whatever operation.
- Loads of services to write and maintain.
- Transactions become a concern - many transactions handled by the caller?
- Start to look like property setters / CRUD - apparently a no go.
In option one or two, say the caller only wants to update the home email address - I cannot expect that the client complete the entire message - does the client leave all of the other tags out? What is the accepted, obvious, intuitive pattern to dealing with this problem?
If this IS indeed the pattern, then how does the client clear the field, or set it to null? In .NET, in the server code I cannot see an obvious way to distinguish between not supplied and null. Since it is not obvious, I expect that this is not an accepted pattern.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我强烈建议使用第二个选项,因为它保留了用户进行更改一直到作用于其上的代码的意图。
第一个优点是,它使您无需回答“如何在 DTO 中表示删除”的问题 - 因为现在您可以显式地将这一事实捕获为
DeleteContactNumber
消息。第二个优点是,您无需回答“如何一次添加多个地址”的问题 - 因为您不必推断有人从变异的 DTO 添加了地址,您会得到一个
AddContactAddress消息。
第三个优点是,您可以在一天结束时进行更有趣的业务分析 - 因为您知道发生的事件是什么,而不必对 DTO 进行分析并进行推断。
最后,向特定事件添加更多信息变得很容易:您想知道为什么人们删除他们的联系地址吗?
使用“获取数据、改变数据、保存数据”的模型可以减少代码行数,但最终会让您更难理解系统中执行操作的原因 - 这最终会让您付出代价。
I would strongly suggest the second option, because it preserves the intention of the user making the change all the way through to the code that acts on it.
The first advantage is that it absolves you from answering the question of "how do I represent deletion in a DTO" - because now you would capture that fact as a
DeleteContactNumber
message, explicitly.The second advantage is that you are absolved answering the question of "how do I add multiple addresses at once" - because you don't have to infer that someone added an address from the mutated DTO, you get an
AddContactAddress
message.The third advantage is that you can do more interesting business analysis at the end of the day - because you know what the events that happen are, without having to do analysis of the DTO and infer that.
Finally, it becomes easy to add more information to the specific events: do you want to know why people are deleting their contact address?
Using a model of "fetch the data, mutate the data, save the data" is less lines of code, but it ultimately makes it harder to understand why things are done in your system - and that will eventually cost you.
使用具有细粒度参数的粗粒度 api。如果您不希望更新某个字段,请传递一个描述符以及数据。就像这样:
拥有细粒度的 API 基本上就意味着死亡,因为传输通常是模糊的。
如果有人写道:
他们很可能刚刚进行了 a) 3 次网络访问,以及 b) 3 次数据库访问,最后得出 c) 3 次数据库事务。这还没有算上所涉及的所有编组和解编的乐趣。
这当然是疯狂的。
服务 API 是否需要远程?不,当然不是,但很多都是,而且至少很多都是透明的传输(可能是本地的或远程的,你不知道)。
所以。粗略的 API,细粒度的参数。详细地弄清楚你想做什么,然后一次性完成。
Use a coarse grained api with fine grained arguments. If you don't want a field to be updated, pass along a descriptor saying that along with the data. Something like:
Having a fine grained API is basically death, because transport is often obscured.
If someone writes:
They have very likely just made a) 3 trips over the network along with b) 3 trips to the DB, concluding with c) 3 transactions on the DB. This doesn't count all of the marshalling and unmarshalling fun involved.
Which, of course, is insane.
Is a service API required to be remote? No, of course not, but many are, and minimally, many are transparent of transport (could be local or remote, you don't know).
So. Coarse API, fine grained arguments. Figure out what you want to do, in detail, and do it all in one go.
就我个人而言,我认为同时拥有 UpdateMember 功能和 UpdateAddress 等更简单的功能并没有太大的问题。有些人可能会争论,但我认为这是完全可以接受的。
“直觉”可能是更合适的词——您觉得什么是合适的?
对我来说,UpdateMember 似乎是一个明确的候选者。如果 UI 使用此服务,则所有字段可能已由 GetMember 调用填充,因此所有字段都将使用其原始值填充。即使它不是 UI,您也可以使用类似的东西。然后,对于更简单的特殊情况,您还可以使用 UpdateAddress、Update PersonalDetails。
然而,我不喜欢的是仅具有 UpdateMember 功能,然后将您不想更改的字段留空的想法。我认为没有多少人使用这种模式,我当然也不会。正如您所说,如何将字段设置为空。
Personally, I don't see too much wrong with having both the UpdateMember capability AND the simpler capabilities of UpdateAddress etc. Some may argue, but I think this will be perfectly acceptable.
'Intuitive' may be the better word to follow here - what feels right to you?
To me, UpdateMember would seem a definite candidate to include. If this service is being consumed by a UI, all the fields would likely already be populated by a GetMember call, so all the fields would be populated anyway with their original values. You could possibly use something similar even if it is not a UI. Then you can have UpdateAddress, Update PersonalDetails as well, for simpler, specialized circumstances.
What I don't like however is this idea of only having the UpdateMember capability and then leaving fields you don't want to change blank. I don't think many people use this pattern and I certainly wouldn't. As you say, how do you then set a field to null.