4

I have couple of models Merchant and Offer. A merchant can have multiple offers. I am developing a web application and writing a custom component which show offer details like title, description etc. I also need to show merchant thumbnail in the same component.

The data I have is offer list in JSON and each offer contains the merchant_id. What I am showing at present is for showing each offer card I am fetching its associated merchant detail and then passing two models in my presenter component namely offer and merchant, I am sure that in future I will be needing more information from merchant.

Is it a good practice or I should pass a custom model which contains both merchant and offer details and name is something like OfferDescription and to save extra request pre-populate this model from backend?

I am not sure if there is some better approach. My main criteria is flexibility and maintainability.

4

A presentation layer is under no obligation to use the same abstractions as the model it uses. Indeed there is a lot of power in using different abstractions.

It sounds like the abstraction you need in your presentation is "offer card" and isn't the same as an offer or a merchant. Allow this difference to be reflected in your code. Don't create an "offer card" model object. Have an "offer card" presentation object that takes messages from the model objects. It can then populate a UI with that information.

Going the other way can work of course. But it really has exactly the same problem inheritance does. Sure you get a new layer and some indirection but the interface is the same so the level of abstraction is the same. That is very limiting. Prefer new abstractions in new layers to old abstractions.

Can you please elaborate on " Have an "offer card" presentation object that takes messages from the model objects."? - CodeYogi

Sure thing. In this diagram your model is now Business Rules. enter image description here

Here's an example where your "offer card" presenter doesn't know about or hold a reference to your offer or merchant models. All your presenter has to do is implement the interfaces they talk to. When they talk to you you translate what they say into things the UI can display.

As the presenter, you don't ask the model any questions at all. You don't ask the UI any questions. You get told to do things and you tell other things to do things.

This is tell, don't ask. It insures as you go through a layer you have the full benefits of polymorphism, of being object oriented, and have the right to abstract anyway you feel like abstracting.

It's amazingly powerful. But to take full advantage it demands you be willing to abstract at every layer. This means thinking of lots of names. Thankfully, you'd already done the hard work: "Offer card". Indeed, as I've mastered structuring my code in any conceivable way I've come to find what limits me more than anything else is thinking of a good name.

If you're wondering exactly what "talk to" means here's how Uncle Bob puts it:

You separate the UI from the business rules by passing simple data structures between the two. You don’t let your controllers know anything about the business rules. Instead, the controllers unpack the HttpRequest object into a simple vanilla data structure, and then pass that data structure to an interactor object that implements the use case by invoking business objects. The interactor then gathers the response data into another vanilla data structure and passes it back to the UI. The views do not know about the business objects. They just look in that data structure and present the response.

Robert C Martin

To put that a little simpler

The important thing is that isolated, simple, data structures are passed across the boundaries. We don’t want to cheat and pass Entities or Database rows. We don’t want the data structures to have any kind of dependency that violates The Dependency Rule.

Robert C Martin

A very good existing answer about this comes from @zapl

  • The “presentation object” is sometimes also called “page object” or “view model” (though the latter may be associated with data binding in an MVVM design which is not necessary). Whatever it's called, I strongly recommend this approach since it keeps as much logic as possible out of your presentation layer. – amon Jun 8 '17 at 15:05
  • Can you please elaborate on " Have an "offer card" presentation object that takes messages from the model objects."? – CodeYogi Jun 8 '17 at 16:07
  • @CodeYogi done. – candied_orange Jun 8 '17 at 16:35
  • @CandiedOrange if you heard of web components then, is that a presentation layer? I am asking this because I have created a web component named offer-card which takes two parameters right now offer and merchant entities something like <offer-card offer="vm.offer" merchant="vm.merchant"></offer-card> the details of how to render the offer is abstracted in this web component. – CodeYogi Jun 8 '17 at 18:00
  • @CandiedOrange to give you more context there are three category of objects in my application service, view model/controller, entities. The controller is responsible for asking service to fetch the entities from server, the controller then communicates with template and binds data to it. – CodeYogi Jun 8 '17 at 18:03
1

You can use two models in the View, but that means the View will need to contain the logic to coordinate those two models correctly. This has two drawbacks:

  1. Views are the hardest part of the site to unit test. So you will want to keep the logic there are simple as possible.
  2. If you want to show the offer card in a different View, you will need to re-implement the logic in the second View.

I recommend creating a model representing the offer card so you can keep the logic contained in pure c# code where it is easier to test and reuse.

  • May be I am mistaken but I am talking about client side of code which uses AngularJS framework. But my question is framework agnostic. – CodeYogi Jun 8 '17 at 18:05
  • Can you please take a look at my code snippet here and comment on that basis? – CodeYogi Jul 10 '17 at 5:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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