11

When using reusable business objects, what is considered best practice when building view models?

We use an object we call Builder to build our view models. One builder for each logical unit of views (orders, users etc), where each unit can contain a number of different view models (orders contains summary, order lines etc).

A builder may pull data through one or more standard business objects in order to build a view model.

What is considered the better practice when it comes to using business objects/models in view models?

Approach 1

Allow the use of business objects in the view model?

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary();
        obModel.Order = obOrder;

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public Some.Business.Logic.Order Order;
    //Other methods for additional logic based on the order
    //and other properties
}

Approach 2

Take only the necessary data from the business objects

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary()
        {
            OrderNum = obOrder.OrderNum,
            NumOrderLnes = obOrder.NumOrderLines,
        }

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public int OrderNum;
    public int NumOrderLines
    //Other methods for additional logic based on the order
    //and other properties
}

I can see the benefits and drawbacks to both, but I wonder if there's an accepted approach? In approach 1, there's no duplication of code around the models, but it creates a dependency on the business logic. In approach 2, you take only the data needed for the view, but you duplicate code around models.

3 Answers 3

12

Option 1 creates a tight-coupling between the domain model and the view. This contravenes the very problem view models are designed to solve.

A view models "reason to change" is if the view itself changes. By putting a domain model object in the view model, you're introducing another reason to change (eg the domain changed). This is a clear indication of a violation of the single responsibility principle. Having two or more reasons to change leads to view models which require a lot of maintenance - probably more so than the perceived maintenance cost of duplication across domain/view models.

I would always advocate approach 2. It's often the case that view models might look very similar, even identical to domain model objects, but the distinction as I mentioned is their differing reasons for change.

5
  • Am I correct in thinking that by "reason to change" you mean change in a maintenance sense, not change in an updating (eg ui event) sense?
    – Andy Hunt
    Commented Aug 2, 2012 at 15:38
  • @AndyBursh yep that's correct - see this article, particularly the line "Robert C. Martin defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to change."
    – MattDavey
    Commented Aug 2, 2012 at 15:44
  • I like your answer but some thoughts... The view model doesn't necessarily change just because the model changes. Only if you were binding or using a specific property that changed would this be an issue since your reference is to the entire object. Having a reference to the domain object makes it easier to make changes and save it again. Your save methods are also dependent on the domain object so you then have to convert the view model back or have your business method setup to accept view models which isn't good either. I still think #2 makes most sense, but just by two cents. Commented Dec 8, 2013 at 7:27
  • If you cannot have domain objects in a VM, then how would you represent something more complicated like an array of Orders?
    – Jeff
    Commented Sep 7, 2017 at 2:51
  • So does this mean things like, say, formatting a timestamp for user display, should belong to the view layer, not the domain layer, and domain level objects should return only a raw, unformatted timestamp to the view objects and the latter are what should contain the formatter logic? Commented Aug 4, 2019 at 3:16
2

Option 1 is preferable as it avoids code duplication. That's it.

If the domain model changes significantly , it's almost certain that the view will have to change anyway. With option 2, then you have to change the view model AND the builder as well as the view itself. That kind of thing is absolute poison for maintinability. YAGNI.

The point of having a separate view model is to keep state that is meaningful only for the view (e.g. what tab is currently selected) separate from the business model. But the business data itself should be reused rather than duplicated.

5
  • YAGNI - the secret assassin of solving most software design problems. Commented Aug 2, 2012 at 15:56
  • 7
    I'm sorry but this is horrible advice for all but the most trivial of applications. View models don't have state. They are data transfer objects. What tab is selected is part of the STRUCTURE of the view and has NOTHING to do with the DATA in the view model what so ever. Maintenance isn't a nightmare if you structure your program properly and use something like Automapper to hydrate your view models. Commented Aug 2, 2012 at 16:22
  • "If the domain model changes significantly , it's almost certain that the view will have to change anyway." - Agreed. But what about when you have a small change to the domain? With option one, every little change to the domain (even just renaming a property) requires a corresponding change to the view. This is also absolute poison for maintainability.
    – MattDavey
    Commented Aug 2, 2012 at 17:02
  • @MattDavey: if you rename a property then with a separate view model you have to change the view as well (or whatever maps between domain and view model) and now have two different names for the same thing, which is certain to cause confusion. Commented Aug 2, 2012 at 20:43
  • @Lucifer Sam: obviously we have very different concepts of what a view model is. Yours sounds very, very weird to me, like you're describing mainframe apps for dumb terminals, but certainly not modern web or fat client apps. Commented Aug 2, 2012 at 20:48
2

Principles and mantras are sometimes valuable for guiding design... but here's my practical answer:

Imagine your view models being serialized into JSON or XML. If you try and serialize your domain models you're going to end up with a hideous mess of text and most likely run into issues with circular references and other issues.

The purpose of a view model is not to group domain models together so that the view can consume them. Instead the view model should be a completely flat model of the view... the actual thing you're looking at on the screen. Your view logic should only be concerned with structuring the data that is present in the view model.

Ideally your view model should be composed almost entirely of pre-formatted strings. Think about it... you don't even want a DateTime or decimal in your view model because then you're stuck doing formatting logic in C#, Javascript, Objective-C, etc.

6
  • 2
    I've never had any problems with serializing domain models. And converting everything to strings in a model? Seriously? Commented Aug 2, 2012 at 15:59
  • 3
    @MichaelBorgwardt Yes, this is what a view model SHOULD be. You don't want to be serializing your domain models and sending them all over the place. All business logic should stay safely at home in one place. The views however should be flexible and able to be rendered on any device which is why you want to completely separate your STRUCTURE, DATA and STYLE. Commented Aug 2, 2012 at 16:07
  • Sorry, but THAT is horrible advice for any application, period. It leads to overengineered applications full of duplicate code that are the exact opposite of flexible. Commented Aug 2, 2012 at 20:40
  • 1
    @MichaelBorgwardt it sounds like you're used to working with anemic domain models where the entities are little more than property bags with little or no behaviour. In that case yes, a DTO/View-model would basically be a duplicate. However if you have a rich domain model with complex relationships, a layer of DTOs/View-models becomes necessary, and they will not be so similar to the domain entities.
    – MattDavey
    Commented Aug 2, 2012 at 22:15
  • @MattDavey: It sounds like the domain models you're used to working with are not just rich but veritable kleptocrats. I don't like anemic models either, but they're still models, and their behaviour should be confined to representing the domain. Single responsibility principle and all that... Commented Aug 3, 2012 at 10:01

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.