Thursday, August 8, 2013

Client-Side Chaos - Part III : The ViewModel

This is the third and final installment in the series Client-Side Chaos. It examines the ViewModel object internals.

Let's start with the constructor :


  • "this" is established as a private variable named viewModel which can be accessed by public methods contained in the eventHandlers public object.
  • errorMessage, a JsonResult property that must be returned from every post request, is established as an observable property of the ViewModel instance.
  • If specified an error callback is established as a subscription event to be fired whenever the errorMessage observable changes.
  • jQuery is extended with a serializeObject method that can be used to create post input objects using selectors that yield either a single element (in which case the resulting object contains properties having values for all of the specified element's child elements) or a list of elements (in which case the resulting object contains properties having values for only the selected elements).

Encapsulated in the public eventHandlers object are 3 methods :
  • post

    • post takes required parameters of url and successCallback, and optional parameters of shouldMap and element.
    • shouldMap defaults to false and controls whether the returned JsonResult object is mapped to an equivalent object containing only observables and observableArrays.
    • element is used only when shouldMap == true and limits binding to the specified element which defaults to window.document.
    • successCallback will be called with two parameters, url and the returned JsonResult object which is mapped when shouldMap == true.

  • map

    • map calls the private innerMap helper to obtain a mapped object without databinding. See innerMap description below for more information

  • unMap

    • unMap creates an equivalent POJO from an object consisting solely of observable and observableArray type properties, maintaining object hierarchy and structure

Encapsulated within the private pvt object are 4 methods and one property. The alertOnErrorproperty is retained from the constructor parameter having the same name. The methods are:
  • errorHandler
    • sets ViewModel errorMessage observable
    • maps and databinds the errorObject if mapping was specified
    • logs to console
    • then either issues alert or calls view errorHandler

  • successHandler
    Note that successHandler will be called for some server errors.
    • maps and databinds returned JsonResult object if indicated by post shouldMap parameter
    • if error log to console
    • if error alert user if constructor parameter alertOnError == true
    • if successful call the successCallback if one was passed on the post request

  • map
    The private map method is called to databind the mapped object
    • viewModel is the object to which a sub-View Model object will be added as a property
    • url is the url that had been used to obtain a model object that will be mapped to the sub-View Model. It is also used to derive the sub-View Model property name.
    • model is the object returned from post to the url and which will be mapped to the sub-View Model via a call to pvt.innerMap
    • element is optional and the HTML element that will be used in databinding with the sub-ViewModel as can be seen in the call to ko.applyBindings.

  • innerMap
  • innerMap is a helper for the public map method which accepts a model object and recursively iterates properties descendant properties while adding those properties and their values to a corresponding View Model object as observables and observableArrays. This View Model object has identical structure and hierarchy as the input model object.

This concludes the series. The full working, zipped Visual Studio solutions may be downloaded from SkyDrive and include both Visual Studio projects and a database creation script. Other-platform developers can still salvage the ViewModel object from the zip file.

As always, feedback is appreciated.

Click here for the VS2012 solution.

Click here for the VS2010 solution.

Wednesday, August 7, 2013

"Stuff" happens, sometimes as planned

Every developer evolves over time. One accrues experience and hopefully embraces an increasing number of best practices. There are purely technical best practices...things to do or not to do in design and implementation but there are also other kinds. There are infrastructure, organizational and social best practices. Projects never fail for exclusively technical reasons.

Let's not indulge in self-delusion, companies are no different than people in this respect. They are the sum total of the people that comprise them but like individuals, they range in effectiveness and many other dimensions. Sometimes large groups of people, in lemming-like fashion, willingly plunge headlong off of one figurative cliff or another. There can be severe dangers inherent in corporate inbreeding, believing one's own press and in drinking the kool-aid.

I once came across a plausible analogy for a corporation as "limited autocracy." Think about it, there is secrecy, absolute power over continuation of individual participation, inability to challenge a wide swath of inappropriate behavior or low business practices and a resulting ability to plant the flag of success in the jaws of defeat. And if you don't like it you can hit the road, Jack. 

OK, a little harsh but I'm not saying corporations are all bad. There are some great ones and I've worked for many of them. It's just that there are challenges, many of which result from the collision between what we all hope for from gainful employment; promotion, compensation, advancement; and the goals of the corporation itself which are normally ROI, growth and the other accoutrements of success.

Examples are in order, just to be clear.

During the 70's and 80's IBM distributed software upgrades on magnetic tape. There was extreme deadline pressure, As today, to roll out new releases. Management figured that things would go smoother if they gave managers bonuses for meeting release deadlines. Then we started receiving tapes that would either not install or which contained buggy software. However, we learned to wait for the second or third tape for the same software.


There are analogs within corporations of almost every conceivable human foible and personality disorder. I'm still waiting to see a corporate DSM-5. There is the proverbial elephant in the corporate living room, more likely to happen when challenging ideas, even bad ones, is assured to be career-limiting. If it is easy for individuals to hide the results of their initiatives by sweeping them under the proverbial carpet that carpet can grow lumpy over time. Then the "stuff" can hit the fan and launch the next crusade to remedy the problems. That crusade can even be led by the one who caused the problem in the first place in the same way the arsonist lingers to watch the results of their handiwork and even help the fireman. There are opportunities for key individuals in crisis management when the fix might be remembered much longer than the cause... even when the fix is nothing more than stopping what you were doing.

We can gaze off into the not so distant past for other examples such as those taped internal phone conversations of Enron employees joking about how they were going to screw grandmothers in CA on their power bills. The worst, in that case, bordered on psychopathy. 

The IBM and Enron anecdotes are the worst examples of corporate dysfunction and I'm only stating the extreme case for illustrative purposes and somewhat humorously, I hope. Sort of. There has to be some way to define what the corporate challenges might be and for an individual to navigate the straits (s)he might find (her || him)self in. There is a point in all this and if you're still following the thread we'll arrive at it soon, I promise.

I once worked for a Japanese company which, by its own admission, recognized the pitfalls of their cultural tendency to all too willingly and quickly form consensus...thus the reason for intentionally manufacturing some tension resulting from somewhat autonomous US development groups. During my tenure there in an effort to better understand cultural differences I purchased a great book titled Kiss, Bow, or Shake Hands, touted as a "Bestselling Guide to Doing Business in More than 60 Countries." Particularly memorable was the author's description of a culturally instilled trait "asal bapak senari " which translates to "keeping father happy." Apparently upper management in Indonesian companies have a difficult time getting accurate assessments of problems because of employee reluctance to send any messages other than "happy news" upwards.

That's no slam on Japanese culture either. I departed with a deep respect for how the Japanese go about business. At the other extreme are culturally American companies which more resemble a bickering family with little harmony.  In a nutshell, the challenges seem to be both manufacturing a healthy tension which allows vigorous debate and ideas to be challenged while, at the same time, not letting it tear the company apart, devolve into a destructive form of competition or result in lingering resent.


There are also challenges in cultivating the precise balance in a company's culture but there are ways to do this among them some element of peer technical review which formalizes the idea of bringing all ideas to the table no matter how conflicting they might be. Observing the introduction of this approach in one company it was noteworthy that the ones having the most difficulties with it were typically the grizzled veterans who we not accustomed to having their ideas challenged. But when done correctly the civility that the process requires can become ingrained and reap great rewards. When the prime objective is not to review the vast majority of code and design even the smallest dose of review has a way of breaking down the walls that prevent essential collaboration.

As a junior developer years ago I'd thought that all companies were created equal. We all interview and rejection, aside from the source of the rejection, can hurt. That was my experience but it might be self-inflicted because of what author Pat Conroy so eloquently described as "that southern boy thing about needing to be liked."

To distill a bit more -- in order to better navigate the organizational straits that might present themselves it helps to understand the challenges that companies face and what the ways they rise to those challenges mean for you as a prospective employee.

There are ways to assess and questions to ask during interviews. The answers to those questions can provide the insights you need. However covertly it might need to be done, you are interviewing the company as much as they are interviewing you.

On the technical side great guidance can be had from the Joel on Software evaluation, devised by Joel Spolsky, formerly of Microsoft. That's a succinct list which he elaborates on further in his book Joel on Software. The number of "YES" answers are a good measure of any software development organization's effectiveness. It's something to consider because "a rising tide lifts all boats" and "you can't fight city hall", as it were. Your personal growth and success can be severely limited by the perspective of the company in which you work. No single individual can move a company from a 2-3 rating to 10+. That's even a challenge for someone near the top, that is if they have deep experience.

The Joel test is also an accurate predictor of whether you'll be building software with the equivalent of rocks and sticks, whether your time on the job doing what you like best (design and implementation?) will be maximized or whether you'll spend most of your time fighting fires and, in a sense, chasing your tail. We are all malleable and not only add to the environment we're pickling in but draw from it as well. It is guaranteed that after years at a company that rates 2 of 12 you won't emerge as the same developer you might if you worked at a company rating 10+ out of 12.

As an aside, I loved question number 8 after having worked in environments in which there were insufficient meeting rooms to support the software development process which necessitates extended periods of heads-down interspersed with flurries of collaboration, brainstorming and information sharing. Sometimes, if the environment or methodology, as practices, does not support this it will not happen as needed.

These things must be taken into account in plotting one's career trajectory and one can't focus on this early enough in his || her career.


You have to be clever in ferreting out the information you want to know about a company. Companies can be as sensitive as a first date, despite being ultimate arbiters of the hire/pass decision. They should be approached with the care and calm one might have trying to hand feed a scared animal in which one sudden move will certainly result in flight. 

For example, I once asked "How does your process encourage developers to "plug in" and collaborate as opposed to "going dark" and working in self-imposed confinement avoiding collaboration. That's a mouthful but the issues are very real. We all know that. As it turned out, the company claimed to be "agile" but that term can be used to loosely describe chaotic and "catch as catch can" or it can be being used  precisely in the formal sense as a tried an true development methodology addressing the nature of a business in which requirements change rapidly so that locking in on a set of requirements cannot be cast in stone, necessitating shorter iterations and concurrency between prior iteration implementation and the next iteration's requirements gathering. If the interviewer is the least bit sensitive about their methodology being referred to in the former sense then such a question might be perceived as inflexibility or an indictment. So be clever in the way you ask questions.

It not only helps to get the lay of the land in both in terms of technology, apps, business, methodology and infrastructure but also the roles in which you'd be interacting. Asking the general question, which is certainly legitimate, can lead to a motherlode of useful information such as whether there are testers, business analysts, on-site users and project managers. Again, be careful. I once declared that I have come to appreciate the role of business analyst as a user proxy and got a snippy, rather caustic reply of "...maybe, if they're any good!" LOL! I was hardly any better off for having stated it that way as opposed to asking a more general question then reflecting over the response.


Finally, software methodology and development lifecycle are very important predictors of how productive you can be. There is never one-size-fits-all but anything that can provide:
  1. Accepted, repeatable and generally recognized junctures for collaboration (as is common with most development methodologies) with endorsement at the highest level of management.
  2. Process rules or guidelines that apply equally to all team members which ensure that leading will be by example rather than from the rear (which can engender resent)
  3. Widely accepted steps for resolving fundamentally healthy technical disagreement and "moving on"
  4. Ways to measure performance, defects and velocity and to amend approaches "in stride" using these metrics
  5. A solid, fundamental; perhaps documented; understanding of build and release steps by all team members
...can be of benefit. Sure, there might be times in which a single developer or team of two can get by on less if requirements are well understood but as projects become larger these things become more important.

Have fun out there !!!

Tuesday, August 6, 2013

Client-Side Chaos - Part II : The View

This is a continuation of Client-Side Chaos Part I which describes a generic ViewModel object that makes use of KnockJS databinding. Part I detailed design goals and the ViewModel API.

Before diving in deeper lets look at a brief vid demonstrating at the desired behavior that's being implemented :




  
Now let's look at the ASP.Net MVC4 View, Index.cshtml :

<h2>@ViewBag.Title</h2>
<table>
    <tbody class="todoList" data-bind="foreach: vm.HomeGetAllToDoItems.entityList" >
       <tr>
          <td>
             <input type="checkbox" data-bind="checked: IsDeleted, click:   
              onCheckboxClicked" />
          </td>
          <td>
             <span data-bind="text: Item, css: { 'deleted': $data['IsDeleted'] }"></span>
          </td>
       </tr>
    </tbody>
</table>
<h3>@ViewBag.Message</h3>
<div id="primary">
    <span><input id="itemEntry" type="text" placeholder="enter a ToDo..."/></span>
    <span class="pos_right">
       <input type="button" value="Save" onclick="saveItem()"/>
    </span>
    <br/>
    <span data-bind="text: vm.errorMessage"></span>
</div>


  • A foreach binding is used for the ViewModel HomeGetAllToDoItems sub-View Model entityList property which happens to be an observableArray. Further binding of entityList array item properties is possible because the entire hierarchy of entitList has been mapped so that it consists only of observables and observableArrays
  • Each row consists of a checkbox and text for a ToDo list item. There is a checked binding between the checkbox and the IsDeleted property as well as a clicked binding to trigger update of the IsDeleted property in the database
    .
  • A text databinding is used between a span and the Item property. The span also uses a css binding so that strikethrough style tracks with the IsDeleted property state.
  • Also that below the submit button a databinding exists between the span and an errorMessage property of the ViewModel
  • The div having id="primary" contains a textbox used for entry of a new item and a submit button that triggers mapping then pushing the new item into the entityList observableArray.

There is minimal javascript in the view to support :
  • ViewModel instantiation
  • The ViewModel constructor is passed an error callback which corrects the IsDeleted value if the failed request was one that was attempting to update IsDeleted.

  • view initialization
  • All ToDo items are fetched then mapped into the entityList observable array as part of the view's foreach binding.

  • deletion via the checkbox
  • The ToDo entity which just had its IsDeleted state toggled is unmapped then posted to the server for update. No successHandler is specified because the post for update returns no relevant data but the error callback will be called if the post and update do not succeed.

  • addition of a new ToDo list item
  • post passes a new ToDo description and returns the ToDo entity that was saved to the database. That entity is mapped to an observable then pushed into the entityList observable array


NEXT : Part III will take a look inside the ViewModel implementation.

Client-Side Chaos - Part I : Design & API

I coded some JavaScript back in 2000, off and on thereafter. The advances in this area keep on coming but practice still seems raw, lacking and in need of some patterns, layers, architecture etc. etc. Why does most of it encountered at various companies seem so freaking chaotic? Maybe I'm just working at the wrong places.

Anyway, JQuery was a big step forward. I like KnockoutJS too. It was pretty much a no-brainer and not so hard to understand how it was designed and implemented. The obtrusive dependence on binding attributes might bother some people but for me, the good seems to outweigh the evil.

Having used MVVM for WPF, KnockoutJS had immediate appeal but the examples on the site gave me a vague uneasy feeling because examples seemed to address small ViewModels and nowhere did they provide a working sample of a moderately complex page. Questions immediately came to mind, such as:


  • How can ViewModels and data access best work together?
  • How can encapsulation, hiding and OO be leveraged?
  • How can composition of simple ViewModels such as the ones in the examples scale to more complex pages?
  • How can the separation of concern and layering inherent in MVVM best be implemented?
  • How can all of these worthwhile things be accomplished without tools that are more complicated than the typical client-side chaos we'd all like to escape?
  • What sort of simple tool might be devised which would satisfy most common scenarios without the sort of bloat that happens when you try to do everything for everybody?
There were some basic goals :
  1. A generic or universal ViewModel should be possible. In other words, one object to suit any and all data. Without that there will be more code to write for each View in need of a ViewModel which seems unnecessary. JavaScript offers some advantage for ViewModels that can be had with C# in .Net only with the expense and complexity of reflection, CodeDom etc.
  2. Avoid tedious, repetitive code dedicated to moving values from point A to point B. Even COBOL had the old "move corresponding" feature and surely we've advanced a little bit since the days of old. So ViewModels must populate their own properties to accomplish this.
  3. Small ViewModels are OK and nice for control-like widgets but it would also be nice for a single instantiated object to be able to support the entire page to avoid having to manage potentially dozens of ViewModel instances. Aggregation to the rescue -- any ViewModel can be made  to expose multiple models...sub-View Models, if you will,  which can be creared and destroyed in response to events. These sub-View Models can be extended with methods.
  4. Sometimes I need to asynchronously obtain server data as POJOs (Plain Old JavaScript Object) without binding. Suppose I have an observableArray, a foreach binding and a need to push newly created items into the observableArray. A callback will be sufficient notification that the new entity has been saved.  No databinding is caled for. Therefore my ideal tool would support both databinding and callbacks.
  5. Being lazy by nature and always looking for ways to leverage design to make the job easier and faster, why not incorporate data access into the tool in order to avoid repetitive plumbing work needed to call DAC then pass model Data to ViewModel?
  6. My goal was not to be everything to everybody because fulfilling that need often leads to complexity and bloat. There's always a sweet spot to be found between the extremes of flexibility and simplicity. I've done some Java and in that parallel universe I'd always been impressed by how configuration could make the code simpler but if carried to the extreme could lead to configuration hell. I do like Microsoft's "convention over configuration" perspective with ASP.Net MVC but with a commercial product it is incumbent on the creator to also provide optional configuration alternatives or overrides to the convention which also leads to complexity. However, I could afford to favor convention over configuration.
  7. Despite high speed Internet access client-side bloat is still a concern. Add JQuery, KnockoutJS, possibly Backbone, a wide variety of plugins for all these things and your own custom scripts and it can get out of hand PDQ even with minified scripts. So I thought that maybe KnockoutJS map functionality might be achievable in 100 characters rather than 8kb. 2kb minified seemed a reasonable goal for a generic ViewModel that included map/unmap and data access functionality.
Well, that's my story and I'm sticking to it. It took several iterations and some false starts but after several days an initial cut that more or less attains these goals emerged. Sure there are a few rough spots but without more widespread use in a variety of situations I hesitate to leap further without looking more. Others can judge for themselves but enough of this blogificating, let's step through the code, why don't we?

Here's the API with a grand total of  4 public methods :

ViewModel(alertOnError[, errorCallback])

The constructor is easy enough. The ViewModel can issue alerts or leave all error notification to a global (i.e. for all requests to the ViewModel) errorHandler.


post(url, input[, successCallback[, shouldMap[, element]]])

The post method posts to a partial url that gets appended to location.host. Input is optional and can be null or empty string if not provided. If server-side processing code does not need input then use null or empty string. If you want to use a callback then specify successCallback accepting two parameters, one for the url and another for the retrieved model. The callback approach is more do-it-yourself and does not require that databinding be used. To use databinding pass true for shouldMap which will create a property of the ViewModel object having the same name (minus any "/" characters) passed as url. That property serves as a sub-View Model and is initialized to an object graph equivalent to the Model returned by the post request, but rather than consisting of basic types, objects and arrays it is comprised of observables and observableArrays suitable for binding. In order to use multiple of these "sub-View Models" , each can be associated with non-intersecting element hierarchies. When shouldMap is true  then ko.applyBindings(sub-viewmodel, element) is called internally after initializing the sub-View Model property of the ViewModel instance.

The caller is free to delete the sub-View Model property once it is no longer needed. ViewModel also extends jQuery with a serializeObject method that can be used to create a post input object from a jQuery selector that resolves to a single element or a list of elements. In the former case the object properties are derived from child elements and in the latter from the selected elements.


map(modelObject)

This method accepts a POJO and returns the quivalent object graph in a new object being comprised of observables and observableArrays rather than objects, arrays and simple types.

unMap(viewModelObject, modelObject)

The unMap method does the reverse of map, taking a viewModelObject consisting of observable and observableArray properties and an empty modelObject (i.e. {})that is initialized with the equivalent object graph with properties as objects, arrays and simple types. unMap returns the fully populated modelObject.


Continue to Client-Side Chaos - Part II : The View
       
 
 

Monday, August 5, 2013

Finally Did It

I've been telling myself to create a software development blog but never seemed to get around to it. No more excuses, besides I grow weary of bright lights and rubber hoses during interviews in which I encounter skepticism that I've dun what I've dun. So call it a resume extension, proof or maybe giving something back.

Within software development my primary interests are .Net, development methodology, social factors and challenge facing later career developers.

Work can be as fun and rewarding as play with the added advantage that it pays the rent. Each activity is a diversion from the others and some balance is needed. I feel lucky to enjoy my vocation as much as I do my avocations. I might be an old geezer but I'm still kickin' ! When I'm not designing and coding I like to :
  • surf  (yeah it's me. Old Guys Rule !)


  • play guitar
    an original composition




  • paddle my ocean paddleboard
    Not me, just a vid for those who think paddleboard == SUP

  • toot around King Harbor here in Redondo Beach on my 13' standup paddleboard chasing the harbor seals with my two labs, Scout and Ellie onboard.