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.

CodeYogi
  • 2,156
  • 1
  • 18
  • 34

2 Answers2

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

candied_orange
  • 102,279
  • 24
  • 197
  • 315
  • 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 08 '17 at 15:05
  • Can you please elaborate on " Have an "offer card" presentation object that takes messages from the model objects."? – CodeYogi Jun 08 '17 at 16:07
  • @CodeYogi done. – candied_orange Jun 08 '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 `` the details of how to render the offer is abstracted in this web component. – CodeYogi Jun 08 '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 08 '17 at 18:03
  • @CandiedOrange what I understood till now is to let controller make two http calls to fetch `offers` and `merchant` and create a third object `OfferCard` containing all the information needed to be shown (I am not sure if this object should have any behaviour or just public fields) and then pass this object to my presentation component something like `` – CodeYogi Jun 08 '17 at 18:07
  • @CodeYogi "... `offer-card` which takes two parameters right now `offer` and `merchant` ..." This is backwards. Your presentation layer shouldn't hold references to `offers` and `merchants`. It should implement interfaces that `offers` and `merchants` can use to send messages to an `offer-card` or anything like it. – candied_orange Jun 08 '17 at 19:29
  • @CandiedOrange I am having trouble getting your last comment, should I give proper example? or you could explain in some more depth. Thanks, – CodeYogi Jun 09 '17 at 04:10
  • @CodeYogi I know it's a bit weird to get at first. This is a bit like the observer pattern but there is no going back and asking for values from getters. When your `offer` object is told about a change it accepts that change, updates it state, and then it sends a different message to the `offer-card` object. The message is different because `offer` is allowed to perform logic that takes the message into a different level of abstraction. – candied_orange Jun 09 '17 at 04:21
  • @CodeYogi `offer` might have been told to insert something into a sorted list. When it talks to the `offer-card` it's not going to say "here's what was inserted." It's going to say "here's the updated list" or at least "here's where to insert this" Work is done every step along the way based on the state of the objects doing it. Control can flow from outer layers to inner layers and back to outer layers. All without getters, circular references, or inheritance. Interfaces can be designed around how their used rather then what is implementing them. It makes every layer change polymorphic. – candied_orange Jun 09 '17 at 04:29
  • @amon you can check the link [here](https://gist.github.com/vivekimsit/e31e2d55370bddf61d56f85ebc5c9141) and provide some insight – CodeYogi Jun 10 '17 at 03:10
  • @CandiedOrange you gave me some great advice, but I missed some part since its a long time I used java I am pasting my code [here](https://gist.github.com/vivekimsit/e31e2d55370bddf61d56f85ebc5c9141) and you can get some idea on what I am saying. – CodeYogi Jun 10 '17 at 03:12
  • @CandiedOrange It would be really great if you could give some comment on my code snippet I shared with you last because I am new to this OOP world and I am finding hard to understand all the terms used here. – CodeYogi Jul 10 '17 at 05:09
  • @CodeYogi take it over to [Code Review](https://codereview.stackexchange.com/). Might want to explain your thinking and form a good question. – candied_orange Jul 10 '17 at 06:06
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.

John Wu
  • 26,032
  • 10
  • 63
  • 84
  • 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 08 '17 at 18:05
  • Can you please take a look at my code snippet [here](https://gist.github.com/vivekimsit/e31e2d55370bddf61d56f85ebc5c9141) and comment on that basis? – CodeYogi Jul 10 '17 at 05:08