4

I’m struggling with how I should build out my entities, services, and DAOs in an MVC web application when it comes to returning a list (array) of data. On one hand, returning an array of entity objects keeps the code lean and easy to maintain, however, there's a performance hit for building and returning complex entity objects when my view(s) may not need all that data at once.

For this example, let’s say I was creating a service to work with campgrounds (you know, those places with tents, lots of dirt, and mosquitoes). Campground entities, in this project, are rather complex objects because they have many properties, nested value objects, and a few behaviors.

My CampgroundService is going to have some pretty standard methods like getById() and list().

UML Diagram

The getById() method is mostly straightforward and will primarily be used when displaying detailed information on a single campground. Having CampgroundService return a single Campground entity here is the perfect solution.

Things get tricky with the CampgroundService list() method. The list() method accepts a filter object argument that contains criteria to filter by. For example, there may be times when I need to grab a list of campgrounds for an entire US state or a list of campgrounds based on a bounding box of geospatial coordinates (i.e. latitude and longitude).

The views that display the list (array) generally only need a small subset of the data contained in the full Campground entity. For example, most of the time when listing I only need the name, state, altitude, latitude, and longitude. It feels like overkill to have to build out the full Campground entity with all the nested objects every time I want to get a simple list of campgrounds and there is most certainly a measurable performance hit for doing so.

Hence my question: Is there a best-practice or design pattern handling listing data in an MVC app?

Here are some possible solutions I have been considering:

1. Caching to the Rescue? Caching would handle the speed problem on subsequent requests for data, however, storing potentially large arrays of entities in memory seems like a bit of a waste. Additionally, there may be times where I cannot really use caching because one of the views in the app sorts campgrounds by the geographic data type. I have MSSQL (via my DAO) doing the heavy lifting here for geo spacial sorting since it does it very quickly and the reference point for sorting could change rapidly (when the user moves the map around). Caching doesn't feel right for this use case.

2. Create a new, smaller “Summary” Campground entity I could create a new entity object called CampgroundSummary and a new service called CampgroundSummaryService which would only hold the most basic fields for listing campgrounds. I expect this model would be much more lightweight and faster to assemble than the primary Campground model. However, the downside is that I feel like I’m violating the DRY (don’t repeat yourself) principle by creating similar (albeit abbreviated) entity objects and services.

3. Return a Basic Array Instead I could forget about returning an array of entities altogether when listing data, and instead, just return an array of simple key/value objects. This feels very “noobish” to me, but the performance advantage could make it worthwhile. The downside of this approach is that I lose the advantages of using entities that enforce data integrity and behaviors (assuming I need them someday).

4. A Hybrid of Options 2 and 3 Simplifying the model into a CampgroundSummary might be ideal in cases where I need to show a list of campgrounds by state, but only need a small subset of properties. I could even cache that data too to make it load lightning fast. However, for other cases where performance is the top priority, I could create a separate method in my CampgroundService like getSimpleList() which would return a simple array of key/value objects.

I would very much be interested in your insight on this subject.

Update: 7/12/2020 I had another possible solution:

5. Lazy Load Sub Objects This strategy involves not assembling any complex sub-objects within the Campground entity until they are needed. This means adding references to various service objects within the Campground entity so it can retrieve that data when needed. This approach would certainly be more performant if the view does not have a need for nested object data. However, it depends on the view because I could see the view displaying a list of campgrounds along with something like CampsiteTotal which would need to be calculated from sub-objects. It does feel a little like a code smell though adding service layer objects into my entities so I'm not sure how I feel about this solution.

1 Answer 1

3

Your question is a common one when designing and developing a multi-layer application: how much data should be in the data objects that are returned by the service layer.

As you explain in your question, the Campground entity is a complex entity in the sense that it contains other (sub) entities. Then the CampgroundService should not return a complete Campground entity with all the other sub entities, but only a plain Campground entity without any other entities. The other sub entities should be handled by other Service classes.

The idea is that the Service layer does not know how the Presentation layer is composing the objects to show; so it only returns the plain entities.

So your solution in Option 2. to create a SummaryCampground class is in the right direction. But this should be the real Campground class, and the enriched Campground class should only exist in the presentation layer as a DTO class.

So, if you want to show one Campground object (retrieved by an Id), you should first get the Campground object from the CampgroundService, and then get the sub entities of this Campground object from the other Services. And if you want to get a list of Campground entities, you only have to call the CampgroundService which returns a list of plain Campground entities without any sub entities.

I would not go with Option 1. because caching is not meant to solve problems with retrieving the right data. And with Option 3., you are indeed loosing the benefits of using strong typed classes.

2
  • Thank you for the insightful response! This has given me a lot to think about. If you don't mind, I have some follow up questions: 1. If I simplify the Campground object to only contain basic properties, how would you handle displaying a list of campgrounds, but within that list, you want to display something like campsiteTotal which would normally be calculated on the fly by the entity via its internal composition of sub-objects? 2. How would you handle a Campground's composed value objects? Would you leave those out too? I assume the same would be said of behavior methods?
    – Dave L
    Commented Jul 12, 2020 at 16:12
  • 1
    1. It depends on the number of sub-entities. If there are just a few needed, I would go with retrieving the Campground entities, and then retrieve the sub-entities, composing them together in a DTO object. In this DTO object you can do all the calculations/totals you want. For 2., you can do the same: map the entity into a DTO and do the composition/calculations/totals there.
    – Frits
    Commented Jul 13, 2020 at 6:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.