Thursday, December 6, 2012

Knockout.js Building factories for your View Models

I have given some thought to building View Models lately for use in Knockout. As I look through some of the samples of Knockoutjs.com, I noticed some reference to reusable view models. It is just like any other dependency you would inject inside your view model. 

First some concepts that I have developed while working this problem:
  • Field- anything that will ultimately be wrapped in a ko.observable or some extended version.
  • View Model Item Objects- a object with Fields or Collections
  • View Model Collection Objects- ko.observable or some extended version.
Some ideas I wanted to plan for:
  • Easy to update Field level sub properties (makes it easy to add change tracking or accept/cancel)
  • Ability to add shared functionality across View Model Item and Collections Objects
  • Easy to add type checking at a top level.
  • A control freak's alternative to ko.mapping.
  • Allow for reususe of View Models if the shape you are passing down is the same and the behavior is the same or can easily be extended to suit multiple use cases.
First we will look at the item factory. This is what will be instantiated to make new View Model Item Objects within our view model. For simple examples you may just new one of these at the top level. It is also possible to composite together multiple calls to this factory to get more complex view model structures.


Sample 1: View Model Item Factory

    core.models.viewModelItemFactory = function (itemInit) {
        var mapper = function (data) {
            itemInit(data, this, ko.observable);
            this.toJson = function () {
                return ko.toJSON(this);
            }
        };
        return mapper;
    };

Basically there are two parts to this factory:
  • A itemInit function is passed in that will handle Field initialization. Notice we pass ko.observable in to that function. If later we want to have other properties or functions hung off each field we could change that in one place for the entire application.
  • We also wrap toJSON from ko. This means we can keep our view models dumb of our usage of Knockout.js and will just have to change the implementation if we ever switch over to another library.

Sample 2: View Model Item Factory Usage and Instancing

core.profile.profileItemViewModel = 
        core.models.viewModelItemFactory(
        function (input, output, field) {
            output.fname = field(input.fname);
            output.lname = field(input.lname);
            output.line1 = field(input.line1);
            output.line2 = field(input.line2);
            output.city = field(input.city);
            output.state = field(input.state);
            output.zip = field(input.zip);
        });
var currentProfile = {
                fname: "Joshua",
                lname: "Kincaid",
                line1: "42 A Street",
                city: "Norfolk",
                state: "Va",
                zip: "23502"
            };
 $(function () {
                var vm = new core.profile.profileItemViewModel(currentProfile);
                ko.applyBindings(vm, $('#address')[0]);
                ko.applyBindings(vm, $('#formatted')[0]);
            });

The usage shown in Sample 2 drives the similarity in complexity to any of the samples that more tightly couple view model creation to definition. 

For View Model Collections we just pass the Item View Model in as a mapper.

Sample 3: View Model Collection Factory Usage

core.profile.profileViewModel = core.models.viewModelCollectionFactory(core.profile.profileItemViewModel);

With the implementation I again wanted to divorce my View Model definitions from Knockout.js, so I changed some of the structure of the view model object to show this. Here are the functions:
  • items - the traditional ko.observableArray although there it could be changed to anything else in one line of code instead of being riddled throughout the application.
  • add - a spiced up version of the ko version. Supports splice as an insert. Also will automatically call the View Model Item mapper if it is a pure JSON object instead of the expected view model object.
  • remove - a wrapper around the ko version.
  • toJson - a convienence object for converting the collection to JSON.

Sample 4: View Model Collection Factory

    core.models.viewModelCollectionFactory =
    function (itemMapper) {
        var mapper = function(data) {
            this.items= ko.observableArray(ko.utils.arrayMap(data, function (item) { return new itemMapper(item); }));
            this.add= function (data, index) {
                var vm = data instanceof itemMapper ? data : new itemMapper(data);
                if (typeof index === 'undefined') {
                    this.items.push(vm);
                } else {
                    this.items.splice(index, 0, vm);
                }
            };
            this.remove = function (item) {
                this.items.remove(item);
            };
            this.toJson= function () {
                return ko.toJSON(this.items);
            };
        };
        return mapper;
    };

The usage is exactly the same as the Item example.

Sample 5: View Model Collection Instancing Usage

var currentProfile = [{
                fname: "Joshua",
                lname: "Kincaid",
                line1: "42 A Street",
                city: "Norfolk",
                state: "Va",
                zip: "23502"
            },
            {
                fname: "Lars",
                lname: "Aldritch",
                line1: "430 21st Street",
                city: "Norfolk",
                state: "Va",
                zip: "23505"
            },
            {
                fname: "Valtino",
                lname: "Landry",
                line1: "98 Chesapeake Ave",
                city: "Norfolk",
                state: "Va",
                zip: "23513"
            },
            {
                fname: "Jeremy",
                lname: "Kilpatrick",
                line1: "490 Atlantis Street",
                city: "Newport News",
                state: "Va",
                zip: "23602"
            }];
            $(function () {
                var data = new core.profile.profileViewModel(currentProfile);
                var vm = { contacts: data };
                core.currentProfileVM = vm;
                ko.applyBindings(vm, $('#people')[0]);
            });

These samples were all pulled from a presentation I did at work on this topic. I have stuck them up on github.


Monday, September 10, 2012

Managing Entity/Entity Set Permanency

Whenever participating in development of data driven application, decisions occur on how permanent data entities should be within the application. In fact such decisions are usually fundamental to the problems the application is working to solve. It often leads to great pains due to weak analysis or evolving understanding of constraints and assumptions. I wanted to discuss the issues from a database design perspective in this post. But first lets discuss permanency from a database design theory perspective.

The key reason I see permanency discussed is to answer two core questions:
  • How do we manage the life cycle of an entity/entity set?
  • How do we reflect an entity/ entity set phases of maturity for integration with outside applications? In simpler terms: How are applications to validate the entities are applicable to whatever operation the application wishes to proceed with?

Database Design Theory related to Permanency

  • Authorization/Ownership- Some type of ownership exists over an entity/entity set handled outside the database and may be modeled through relationships with other entities/entity sets. Often deletes are handled through a limited process.
  • Discriminating field(s)- the entity has fields used to filter records based on some criteria.  Discriminators may be used to get around requirements which state data is permanent or least long lived.
  • Atomicity- An entity set is normalized so portions represented as entity records can be deleted based atomic nature of each entity within a set. That is data that should be deleted or updated together is stored in the same entity. This is different from using fields for discrimination because the application makes decisions based on the existence of a record in a particular entity related to a entity under action for describe stages within a particular life cycle.
  • Transformation- As data moves through the life cycle it is transformed from one entity set to another. The schema design is not necessarily the same from one set to another. Some form of data transformation may occur during the transition or it maybe a reflection. 

Options for Managing Permanency

I mention SQL Server syntax in all caps though other technologies are similar in concept if not syntax.
  • Using built in ON CASCADE DELETE- This is a good default if you can manage Authorization and Ownership. My usually recommendation is to default with this and opt in to other strategies on a case by case basis. A domain may never want to delete anything for particular entities. The suggestion here is to work up a justification for not Cascading. If you never plan to delete than everything that references that entity is also severely limited.
  • ON CASCADE SET NULL/SET DEFAULT- Setting an foreign key field to NULL or to some default can be valid in certain cases. Maybe you have a 'Unassigned' record that allows a user to reassign after a delete to the new valid record.
  • Analyze Dependencies there being none Delete - When a delete screen is used in this scenario the screen allows delete unless the entity is referenced in a particular way. Essentially there can be varying levels of what if analysis. A user can be allowed to override the analysis depending the scenario. 
  • Polling- You notify Owners of a pending delete and the delete proceeds after some criteria is met. Examples of criteria include delete on expiration of some timeout after notification or another possibility is unanimous consent by owners of entities that reference said data. 
  • Custom Triggers/Delete Routine- Whether there is a standardized strategy across the database or not, eventually you will have delete something. Maybe you manage the delete routine/script on an entity by entity.  There is danger here if you standard is custom always or if the stakeholders are not making the call if you do. 
  • Soft Deletes- Using Transformation or Discriminators as described above allows data to disappear without an actual delete occurring. Danger is also here if you do not have consistency. 

Tuesday, June 5, 2012

Maintainable JavaScript: Part II: Common Function Stumbling Blocks


Series Synopsis

I see often JavaScript in the wild lacks a focus on maintainability. I want to cover some of the basics that have served me well in improving maintainability as I try to tame whatever project I am working on. These crop up with such a usual frequency I want to save my fellow programmers some reoccuring pain.

The topics I covered so far in this Maintainable JavaScript series:
Part I: Fundamentals of an Object Oriented Approach
Part II: Common Function Stumbling Blocks (you are here)

Patterns


I believe starting the discussion of patterns early is useful for learning any programming language. The patterns do not change from language to language only implementation details. Throughout this series I will cover patterns as they come up. Last time we covered the beginnings of implementation constructors in JavaScript. This is a natural time to bring up Factory methods and other helpers. Deciding on common methods for implementing features is key to code reuse and thus consistent architecture.

Limit Function Arguments

Anytime I start breaking up code into functions the first question that comes up is, "What should I pass in?" Experience has shown more than three arguments on a function brings about issues in almost any language. With JavaScript, the dynamic nature of the language just increases the number of issues. The biggest issue is JavaScript does not produce any errors if you provide less or more arguments than the signature defined in the function declaration.

Sample 2.1: Parameters Problem

var jrf jrf || {};
jrf.trash jrf.trash || {};
jrf.trash.passMeStuff function (firstsecondthird){
        console.log("Run:");
        console.log(first);
        console.log(second);
        console.log(third)
        console.log(arguments[0]);    
        console.log(arguments[1]);
        console.log(arguments[2]);                    
}       

jrf.trash.passMeStuff(1)//second argument is undefined
jrf.trash.passMeStuff(1,2);
        

Output to console:
Run:
1
undefined
undefined

1
undefined
undefined

Run:
1
2
undefined

1
2
undefined

Sample 2.1 does not produce any JavaScript errors. JavaScript is happy to return undefined for second, third arguments as necessary. Therefore it is imperative for the JavaScript developer to code defensively against possible missing parameters.

One parameter approach

The jQuery library exposed a plug-in model as a way of extending jQuery while limiting what features jQuery was responsible for internally. If jQuery did not create the one parameter approach they certainly made it more popular for  JavaScript developers. The basic premise is for any component that exposes number optional parameters for a given function get callers to create a JavaScript composed of the options necessary.

Sample 2.2: One parameter

var jrf jrf || {};
jrf.trash jrf.trash || {};
jrf.trash.passMeStuff function (options){
    console.log("Run:");
    if(typeof options === 'undefined'){
        console.log("Nothing");                
    }
    else {
        if(typeof options.first !== 'undefined'){
            console.log(options.first);
        }
        if(typeof options.second !== 'undefined'){
            console.log(options.second);
        }
        if(typeof options.third !== 'undefined'){
            console.log(options["third"]);
        }
    }        
}       

jrf.trash.passMeStuff();
jrf.trash.passMeStuff(first:})//second argument is undefined
jrf.trash.passMeStuff({first1second2});


Output to console:

Run:
Nothing
Run:
1
Run:
1
2

Another great side effect of the one parameter approach is you can create a function that serves as a factory for  reusable defaults for certain function calls that use identical arguments or for workhorses.

Sample 2.3: Default Factory

var jrf jrf || {};
jrf.trash jrf.trash || {};
jrf.trash.passMeStuff function (options){
    console.log("Run:");
    if(typeof options === 'undefined'){
        console.log("Nothing");                
    }
    else {
        if(typeof options.first !== 'undefined'){
            console.log(options.first);
        }
        if(typeof options.second !== 'undefined'){
            console.log(options.second);
        }
        if(typeof options.third !== 'undefined'){
            console.log(options["third"]);
        }
    }        
}  

jrf.trash.optionsDefaultFactory function(){
    this.first 1;
}   

var defaults new jrf.trash.optionsDefaultFactory ();
jrf.trash.passMeStuff();
jrf.trash.passMeStuff(defaults)//second argument is undefined
defaults.second 2;
jrf.trash.passMeStuff(defaults);

Output to console:
Run:
Nothing
Run:
1
Run:
1
2

One slight difference in Sample 2.3 from previous examples in post 1 is my constructor member initialization syntax for OptionsDefaultFactory. Sample 1.5, used a different syntax for lost member:


jRF.grid.gridMetadata function (){
    lostMember51 
};

I eliminated the bad habits from 1.5 for brevity. The key difference is in Sample 2.3 syntax we can place arbitrary code in the constructor not just define members. We are making the assumption that we own the function name. Not too dicey of an assumption.

Setting Defaults

Finally I wanted to cover a simple way defining defaults in a constructor. Regardless of whether a consumer of API wants to define a value for option member it is often useful to move on with a convenient default. I find great value in shooting for  'It just works' type scenarios when it comes to defaults. That is I try to limit the responsibilities of an object to a single responsibility with the option of composition of other objects or extension of the current object under development. More on inheritance and composition patterns later.

Sample 2.4: Setting a default

var jrf jrf || {};
jrf.trash jrf.trash || {};
jrf.trash.passMeStuff function (options){
    console.log("Run:");
    if(typeof options === 'undefined'){
        console.log("Nothing");                
    }
    else {
        console.log(options.first || 0);
        console.log(options.second || 0);
        console.log(options.third || 0);
    }        
}   

jrf.trash.optionsDefaultFactory function(){
    this.first 1;
}   

var defaults new jrf.trash.optionsDefaultFactory();
jrf.trash.passMeStuff();
jrf.trash.passMeStuff(defaults)//second argument is undefined
defaults.second 2;
jrf.trash.passMeStuff(defaults);

The only difference between this code and our last sample is we are using a default when we try to use option members' first, second, and third. I could even use 'Nothing' instead of zero since JavaScript is not statically typed. I am in favor of using default values sharing a type with expected values but honestly it depends on usage. The secrete sauce here is consistentancy whatever convention you happen to pick with defaults.