7

Since SPAs have most of their domain logic client side, how do you keep your domain model in sync with the back end?

For example, let's say I have a .NET WebAPI web service that uses the Entity Framework to communicate with SQL Server and one of my classes is called Product. Most of Product's domain logic will be client side.

Now I add a ProductType table to my DB, and I add a ProductTypeID column to my Products table. My EF Product class now has a new property called ProductTypeID. Do I now manually go into my JS files, find the definition for Product and add the ProductTypeID property?

While the client side doesn't need to know server side implementation specifics, it will need to know the shape of the model. How do you keep that in sync between server side and client side? Is it completely manual? How do you avoid errors like property name typos in JS?

  • You could always have your server-side return the model definition in json form to your client. – Kevin B Apr 24 '15 at 15:30
  • what is SPA ... ? – amphibient Jun 7 '17 at 23:22
  • 1
    @amphibient Single Page Application – Legion Jun 28 '17 at 10:50
7

Generally you don't keep them in sync in that way unless there is a reason to do so. Your entire premise is flawed. Most of the domain logic in an SPA, like any application, should be in the server. Only logic pertaining to the user interface should be in the client.

Edit:

So just to be clear on terminology. I assume that when you say "domain logic" you mean the core business logic of the application, the thing that makes your application more than just CRUD operations on resources. It may very well be that your application only needs to store, retrieve, update, and delete some data, in which case I suppose all of the "logic" would be in the client.

But imagine a simple purchasing system where you have inventory items and users are able to add items to a shopping cart for purchase. Imagine then that you need to know whether or not an item is in inventory or out of stock and if it's out of stock your particular use case does not allow a purchase to take place on an out-of-stock item. In this scenario I don't think you would be doing the right thing if you did not have this requirement checking logic in your back-end.

You would certainly want to disable the "Buy Now" button on the client if the item was out of stock, but allowing the back-end to process a purchase for the out of stock item simply because an enterprising teenager decided to submit a POST request using curl seems very wrong to me.

The reason for the client to know that the item is out of stock is different from the reason for the back-end to know it. The client needs to know it to disable a button but the back-end needs to know it to prevent an incorrect charge.

The client's model of the state of the system might just include a purchasable boolean if that is all that is needed, while the server's model may have to take into account a wide variety of reasons, not just whether or not the item is in stock--perhaps the item is not shippable to the current user's location or perhaps the current user has a 35% coupon in their account and the margin on the item is less than 35%. Chances are that the reasons for an item being purchasable or not is more complex to the server than the client, and it's very unlikely that a business system would allow the business logic to be made available to anyone who can download the JS files for the site (every visitor!).

Perhaps the server in that case simply removes the item from the list of results in a query for the purchasable items. The client cannot by definition apply any business domain logic to this item because it does not know that the item exists in the first place.

What if you next want to deploy a native mobile application? Are you going to recreate all of your business domain logic in each new client? What if the system has gotten so large that there are hundreds of rules?

One of the key takeaways of experienced software developers should be that there can and will be multiple models in a system.

  • While I'm still learning about SPAs, none of the texts I've read so far have asserted that javascript's sole area of concern is UI. All have talked about the domain existing client-side in javascript. Regardless, the problem remains. For any kind of client side logic to work it needs to know about the data it's receiving from the server. How do you keep the two sides in sync as the model changes at either end? – Legion Apr 23 '15 at 18:34
  • Point me at these texts so that I can read them. – RibaldEddie Apr 23 '15 at 18:35
  • Pro Single Page Application Development by Apress and this site: singlepageappbook.com/detail2.html are two that I was looking at today. Both show the model being created in JS. – Legion Apr 23 '15 at 18:39
  • Well I didn't say that there wouldn't necessarily be a model layer (although I am skeptical that it's a good idea to be anything more than a view model). – RibaldEddie Apr 23 '15 at 18:50
  • But a view model would only be a model in the UX domain. – RibaldEddie Apr 23 '15 at 18:50
1

I have an ugly but working solution to this problem. I found this post while searching for a better one but I'll post mine to possibly inspire someone. I'm not sure how it'd work outside of PHP though. On the back end I use this:

class BaseModel // All models extend this class
{
    // Returns an object with each property set to its own name as a string
    /* @return static */
    public static function getNameObject()
    {
        $obj = (object) get_class_vars(get_called_class()); // Note: Avoids calling constructor
        foreach (get_object_vars($object) as $key => $value) {
            $object->{$key} = $key;
        }
        return $obj;
    }
}

class User extends BaseModel
{
    public $id;
    public $name;
}

Then I put PHP in my JavaScript files:

<?php $u = User::getNameObject(); ?>

var user     = getUserFromServer();
var userId   = user.<?=$u->id?>;
var userName = user.<?=$u->name?>;

This way I can use the IDE's Refactor command to change a model property name and all the front-end code gets updated as well. All the *.js.php files are executed to become *.js files during the build process so they can be served as normal, static JavaScript.

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.