Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Client-side MV* - Should the model have a save method?

So this is a generic pattern question but one I have been going back and forth with for some time.

Should a model have a save method in MV*?

I often jump back and forth between Knockout, Ember, and sometimes even Angular but one of the persistent questions I always have is should the model have a save method on it's class or prototype that knows how to save changes to reduce dependencies around the application on services (aka the model has a service for saving that all of the other view models / controllers inherit by knowing about the model) or should there be a service that each of the view models / controllers depend on that has a specific method for saving changes to the object?

Example JavaScript pseudo-code

var person = new Model.Person();
person.name = 'Bill';
person.save();

vs

var personService = require('services/person.service');
var person = new Model.Person();
person.name = 'Bill';
personService.save(person);

Both accomplish the same purpose of saving the person but in Example 1 the view model / controller doesn't know about the service or how it is implemented only that if you want to change a person, you save it. In example two obviously we have to know about not only the way to save it but how the save is implemented.

Please read this before you answer -

I realize that this is an opinion-based question but if you can back up your opinion with facts it will be factual, so please have references to back up any claims so that this is not closed as 'Primarily opinion based'

like image 479
PW Kad Avatar asked May 16 '14 16:05

PW Kad


2 Answers

It depends on the pattern (and not at all opinion based imo).

  • Your first example: A domain object having a .save method is called an ActiveRecord (also see here).

  • Your second example: A mapper between the data mapping and domain layers is called a Repository (also see here)

Active Record pattern

Quoting Fowler:

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

The ActiveRecord pattern generally excels at prototyping, and is a good idea sometimes in very small applications where there exists a 1-1 mapping between objects and DB rows. Generally, you want to separate the logic of persisting an object and the logic of an actual domain object, since they are inherently different responsibilities.

This is one of the simplest ways to logically handle the persistence of data.

enter image description here

For example, this is what Backbone models and collections do with their sync() method. Which causes them to persist to the server. It's often the reason you see larger Backbone applications not use sync() altogether in favor of implementing their own adapters. After all, in the Backbone world it forces a 1-1 mapping between your REST API and your domain objects, effectively making your domain objects and data transfer objects the same which can grow hard to maintain as your application grows.

Repository Pattern

Quoting Fowler again:

Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

A repository is generally a better design pattern for larger applications since it removes the persistence logic from your domain object, so it does better separation of concerns.

Implementation wise, a repository usually looks like this: Repository

However, to its users a repository might look like:

enter image description here

As any abstraction, another object for a responsibility has some overhead, however - as an app grows it starts to pay off. If you create a $resource with Angular and wrap it in a service that maps these objects from the db query to your domain objects (your data mapper) and then query that service like a collection - that's a repository for you.

like image 56
Benjamin Gruenbaum Avatar answered Sep 17 '22 22:09

Benjamin Gruenbaum


The short answer in my personal opinion would be your second version. I typically think that the viewmodel on the client is basically a bag of data or properties. Services are used to persist/get those viewmodels to/from the server, and the controller is responsible for consuming the service methods and rendering the view. In the Angular.js world directives would handle any DOM-specific behavior, but I think that ultimately the events that happen as a result of UI interaction (saving, validation, etc.) would be handled by the controller (perhaps by calling a service method).

I formulated this opinion when I started using Angular.js, and was going through their developer documentation. The short of it is:

Use controllers to:

  • Set up the initial state of the viewmodel object
  • Add behavior to the viewmodel object

Do not use controllers to:

  • Manipulate DOM — Controllers should contain only business logic.
  • Format input
  • Filter output
  • Manage the life-cycle of other components (for example, to create service instances).

Use services to organize and share code and state across your app.

like image 42
MDiesel Avatar answered Sep 16 '22 22:09

MDiesel