Sunday, June 26, 2011

ExtJS 3 Views and Controllers

In a previous post I wrote about my impressions of Ext4.  The overall impression were that the ideas were sound, but the implementation was still buggy.  So instead of waiting (which is not possible in a business sense) I have back-ported the ideas to Ext3.  I have not yet figured out how to get stores and models working well, but I have gotten views and controllers works very well.

Layout
Views basically work as is, because that is how ExtJS was designed.  Any subclass of a UI widget will work as a view.  However, to make the concept of a view work well they should only be instantiated once and have their modification logic in a controller.  For this reason I recommend using the following directory layout:
  • app.js
  • ext/
  • app/
    • controllers/
      • Controller.js
      • ContentController.js
    • lib/
    • view/
      • layout/
        • Content.js
      • Viewport.js
      • OtherView.js

app.js
This should just a Ext.onRead function that instantiates the Viewport.js class.  It should also setup any globals that will be used throughout the app and should be included last.

lib/
Since views should only be instantiated once this is the place to put reusable code.  Items here will not usually have an xtype because they will be extended by view items.

Controller.js
This is the base class for all controllers.  It has the helper to bind to views and look them up afterwards.  A small override to Ext.ComponentMgr is required to make everything work.



Content.js
This needs to be a simple card layout so that you can add new items to it.


ContentController.js
This class binds to a something that would change the content panel, like a TreePanel, and then using Ext.ComponentMgr creates a card, adds it to the content, and shows it.

Saturday, June 18, 2011

Minimum Rcov

Uncle Bob, has stated that all code should be 100% covered, but 100% is an asymptote.  Therefore he expects something less then 100%.  This might be true in the Java, or C version of Rcov, but not for Ruby Rcov.  Also, I personally think that 100% is a bit low.

All 100% coverage means is that at least one test touches every line.  And in truly simple code that is usually enough.  But I work on systems, not simple code.  Rarely do I write single use code.  In most cases I write code that does one thing well, but is used by a lot of different part of the system.

Errors are very rarely in core modules, but rather in the runtime combination of core modules.  This is covered by integration testing which is not usually pulled into rcov.  I think this is a mistake.

The following is how I think about a minimum level of Rcov:

  1. Exclude libraries from rcov metrics. That is unless you decide to include their unit testing within your own.  Either way this will give you a more accurate reading of coverage.  Seeing rcov at 90%, but thinking it is 100% because rcov can't see libraries isn't a valid assumption, IMHO.
  2. Include integration testing in rcov.  Rcov has an option to aggregate several runs into a final number.  You should include both unit and integration testing in the final number.
  3. Expect greater then 100% coverage.  Actually, including edge cases, positive, and negative testing the number will be closer to 1000% percent covered.  You read that right, every line of code should be covered by at least 10 tests.
  4. Include the rcov threshold test in CI.  You should, before committing, always run all unit tests, integration tests, and rcov threshold.  At first set the threshold low (about 80%) and move it to 100% ASAP.  And by including threshold test in CI then the code can't go out the door without the correct amount of coverage.
  5. Review tests first and last.  If your teams doesn't already do code reviews, it should.  If it does then start with the tests and then review the code.  This lets you ensure the obvious edge cases are covered without being swayed by the code.  After reviewing the code re-review the tests to ensure there are no new edge cases need to be covered.

Monday, June 6, 2011

Ext4 Impressions

I have been using Ext for years, starting with 2.0.  In most cases this is paired with Ruby on Rails on the server and has generally been nice.  There were some growing pains in understanding that Ext is not like jQuery.  It isn't meant to enhance the page it is meant to control it.  Once it is understood that ExtJS is an event driven UI layer much like MFC (Microsoft) then things are rather easy to grasp.

In fact, Ext (pre 4) is almost just like MFC in that it is primarily a collection of UI widgets that you can put together in any way you wish.  This is great for very small UIs that do not have a lot of interconnected parts, but once the number of interconnected item reaches more then a few (say 5 or 6) then it is nearly impossible to map all the emergent properties mentally.  Enter MVC.

MVC is a design patter created over 30 years ago, whose sole purpose is the separation of concerns.  Business logic (model) is separated from UI (view) and they communicate via a defined set of actions (controller).  Anyone familiar with UI programming should be familiar with this pattern.  It is used in almost all major UI libraries except ExtJS, until now.

Ext4 aims to fix this flaw by retooling the framework to be MVC.  It is almost successful.  There is a major problem in separating models from collections (which is understandable given Javascript's nature) but there are more elegant solutions then the one Ext4 uses (see SproutCore and Backbone).  There are far too many annoyances at the model level for me to detail here, but as an example the LocalStore and MemoryStore are broken as of this writing and cannot update or remove models since they do not fire events.  This problem can be seen is a number of their own grid demos.

I also tried to use the compatibility mode to convert an older Ext3 app to Ext4.  I was successful in removing all of the errors and most of the warning, but could not get the page to render.  Each component thought it was rendered, but no DOM was presented to the browser.  Lots of digging later and it turns out you can't mix MVC Ext4 objects with non-MVC Ext3 like objects.  Not sure why, and without errors it is hard to tell what went wrong.

Finally I started from scratch and created extjs4-frame so that I could dig in without having to worry about Ext3 compatibility screwing things up.  Thing did not go much better.  I watched the videos and then dove right in.  As expected what was shown on the videos (obviously dumbed down) worked as expected, but as I started to add complexity things would break in mysterious ways.  Turning to the documentation was only marginally helpful, since it appears that it has not been full updated.  Also, some of the documentation does not match the JDoc comments in the source (probably human error in generating the docs).  This is an annoyance to be sure, but not a show stopper since I know how to read Javascript (as anyone that would be using ExtJS should).  However, documentation error (especially when generated from embedded comments) are indicative of a lack of attention to detail and since they do not provide their unit tests I can only guess that their storage engines are not well tested either.

Pros
  • Documentation videos are a nice touch
  • Simplified code due to the MVC nature
  • Sensible file structure (forced)
  • Auto-loader (turn off in production, but great for development)
  • Better stack and error handling (as compared with Ext 2/3)
  • Trees use real models (meaning the server can respond with any hierarchical objects)
  • Non-flash based charts
  • Smaller size (as compared to Ext 2/3)
Cons
  • Difficult to understand (even for those with MVC and ExtJS experience)
  • No backwards compatibility (the compatibility mode is a joke)
  • 4.0.X versions are not guaranteed compatible (there are still a lot of internal changes going on)
  • Documentation does not always match source comments and is not always correct (save some time and just start with the code)
  • Inconsistant Model/Container behavior
  • No generator scripts provided for aiding design patterns
  • No unit testing framework provided
  • No JS compiler/minifier provided (one that can read the requires directive is almost a must now that they exist)
Overall
Wait for 4.1 to see if things stabilize.  Or switch to SproutCore.