服务应该依赖于许多存储库,还是将它们分解?
我正在使用存储库模式进行数据访问。所以我基本上每个表/类都有一个存储库。我的 UI 当前使用服务类来实际完成工作,并且这些服务类进行包装,因此依赖于存储库。在许多情况下,我的服务仅依赖于一两个存储库,因此事情并不太疯狂。不幸的是,我的 UI 中的表单之一期望用户输入跨越五个不同表的数据。对于此表单,我创建了一个依赖于五个存储库的服务类。然后,服务中用于保存和加载数据的方法调用所有相应存储库上的适当方法。
正如您可以想象的那样,该服务中的保存和加载方法非常大。此外,对该服务进行单元测试变得非常困难,因为我必须设置很多假存储库。
将这个单一服务分解为几个较小的服务会是更好的选择吗?它将在 UI 层放置更多代码,但会使服务更小且更易于测试。
I'm using a repository pattern for my data access. So I basically have a repository per table/class. My UI currently uses service classes to actually get things done, and these service classes wrap, and therefore depend on repositories. In many cases my services are only dependent upon one or two repositories, so things aren't too crazy. Unfortunately, one of my forms in the UI expects the user to enter data that will span five different tables. For this form I made a single service class that depends upon five repositories. Then the methods within the service for saving and loading the data call the appropriate methods on all of the corresponding repositories.
As you can imagine, the save and load methods in this service are really big. Also, unit testing this service is getting really difficult because I have to setup so many fake repositories.
Would it have been a better choice to break this single service apart into a few smaller services? It would put more code at the UI layer, but would make the services smaller and more testable.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不会为每个表/类提供一个存储库类。
每个“模块”或“根聚合”应该有一个存储库。也就是说,某个存储库可以涵盖的不仅仅是一张表。我们已将相关表分组到一个存储库中。示例是,我们在 Person、Company 等不同表的顶部有一个 RelationRepository,在 Orders、OrderLines 表顶部有一个 OrderRepository,在表顶部有一个 FlightRepository,用于存储航班的所有数据等。
这是存储库模式,因为无论如何您都应该根据领域驱动设计来使用它。
I would not have a repository class per table/class.
You should have one repository per 'module' or 'root-aggregate'. That is that a certain repository can cover much more than just one table. We have grouped related tables into one repository. Examples is that we have a RelationRepository on top of different tables like Person, Company and the OrderRepository on top of the tables Orders, OrderLines, FlightRepository on top of the tables to store all the data for Flights, etc.
This is the repositorypattern as you should want to use it according to domain driven design anyway.
一种可能是按照您的建议分解服务,但是创建一个用于使用这些存储库的外观并保持单一服务也可能是合理的。这将允许您将服务和数据操作中的业务逻辑分开,并可能在存储库中和存储库之间流动。
One possiblity would be to break up the service as you suggest, however it might be also reasonable to create a facade for working with those repositories and keep single service. This will allow you to separate business logic in the service and data manipulation and maybe flow in and between repositories.
我想说,如果您可以将保存抽象到每个存储库,而不是从服务中调用抽象,那么您就可以获得更可测试和可维护的代码,而无需在 UI 中添加任何额外的代码。
我目前有一个 UI,它调用多个服务来以单一表单(异步)保存输入,要让它正常工作是一件痛苦的事情。您遇到的最大问题是处理验证和错误。第一个位可能是正确的,但第二个位可能会失败。您必须返回并删除第一位,因为它已经保存了。相信我,这很痛苦。
I'd say that if you can abstract the saving to each repository and than call the abstraction from the service you then have a more testable and maintainable peace of code without putting any extra code in your UI.
I currently have a UI that calls more then one service to save the input in a single form (async) and it is a pain to get it to work properly. The biggest issue you have is handling validations and errors. The first bit might be correct, but then the second bit fails. You'd have to go back and delete the first bit, because it was already saved. Trust me, it's a pain.
我想我会集中讨论中间段落中的两句话:
首先,为什么服务类中的保存和加载方法“非常大”?你能把他们拆散吗?也许那里有更小的单元可以单独测试。也许,这意味着将服务分割成许多子组件,服务将其大部分工作委托给这些子组件。您有望避免沿着该路线向 UI 层添加任何更多代码,因为 UI 仍然能够仅与一个服务交互,但您可以单独测试所有组件。
其次,为什么在测试工具中设置假存储库如此困难?你能让这变得更容易吗?我经常使用构建器来设置类似但不相同的数据结构以供测试使用。然后,您最终会得到这样的测试:“给定通常的设置除了差异 X,检查 Y 是否发生”。
另一种想法是注意数据访问代码通常非常重复,并且通常可以根据数据库模式自动生成其中的大部分代码。我们生成了许多基本数据访问层,包括用于测试的存储库类的虚假实现。当然,我们必须手动编码性能关键的位,但这会减少很多苦差事,并且可以轻松处理模式的更改。
I think I would concentrate on the two sentences in the middle paragraph:
Firstly, why are the saving and loading methods in the service class "really big"? Could you break them up? Perhaps there are smaller units in there which can be tested separately. That would, perhaps, point to cutting the service up into a number of sub-components that your service delegates most of its work to. You could hopefully avoid adding any more code to the UI layer going down that route, because the UI would still be able to interact with just the one service, but you could test all the components separately.
Secondly, why is it so difficult to set up fake repositories in your test harness? Could you make that easier? I often use a builder to set up similar, but not identical, data structures for use by tests. You then end up with tests that read 'given the usual setup except for difference X, check that Y happens'.
One other idea is to notice that data access code is often very repetitive and it is frequently possible to generate much of it automatically based on your database schema. We generate much of our basic data access layer, including fake implementations of repository classes for testing against. Of course we have to hand-code the performance-critical bits but it takes a lot of the drudgery out of it and makes it easy to handle changes to the schema.