We recently completed and deployed a major application written in SmartClient and for interested readers I've put together a few notes about how our application is architected and our overall experience.
In terms of actual deployment of SmartClient, we've had no issues whatsoever with SmartClient itself. 6.5 and the TreeFrog skin came out just in time to be included, and we've had no issue with crashes or mysterious behavior. The client base runs IE6 on contemporary hardware and performance has been fine. This is an intranet application, used by many people throughout our company.
This project has been in the works for about a year, with the first 4 months or so getting up to speed with basic fundamentals of SmartClient. Things like how to make the various types of callbacks work and how to use closures took a little experimentation. Since our app is object oriented, we don't have global references to things, so the "this.getID() + ".method()" paradigm is used often. When building complex Windows, we also use the "parent: this" trick to allow us to call methods of the Window from sub-objects like ListGrids and DynamicForms. One of the most challenging things, due to the complexity or our app, was getting scope chain resolutions to work right so we could call the functions at various levels of Window widget hierarchy and object hierarchy. Once these basic "best practices" were worked out, most things were amazingly easy to do in SmartClient.
Our app uses PHP in the middle tier and Oracle on the backend.
The client application is driven by an Application base class (client-side controller) we wrote that handles requests from the MenuBar to instantiate and initialize ChildWindows that provide actual functionality. The Application object creates a MenuBar and Canvas, into which it draws all ChildWindows. The Application object also controls which users can access each ChildWindow, via a permissions mechanism. Each ChildWindow adheres to a standard design (actually subclassing the same base class), registering itself with the Application object to indicate whether it's a singleton or should get destroyed and created each time it's needed. The window also communicates it's permissions parameters so the Application can deny access to unauthorized users.
As part of the standard ChildWindow implementation, an initialization method is provided, which if defined is called by the client-side controller (Appliction object) and takes data needed to initialize the ChildWindow (typically a master ID used to fetch detail records).
Each ChildWindow is defined in a like-named Javascript file, which allowed us to implement a Developer's menu that re-fetches the .js file and re-instantiates and re-initializes the ChildWindow. This was a huge time saver during development and testing, allowing us to walk a complex UI path to the window under development and then dynamically re-load it to test changes to the underlying Javascript code without reloading the entire application.
The PHP middle tier consists of a middle-tier controller that brokers requests to ServerObjects to satisfy both Data Bound Control operations (requests from ListGrids and DynamicForms) and individual RPC calls. We used a method whereby we would specify the middle-tier object and method to be called in the GET (?m=Object.Method) and all parameters in the POST. Data to/from the client application is serialized to JSON for transport.
Business logic is present in both PHP and Oracle stored procedures as appropriate.
From a deployment and release management perspective, we use a set of build/release scripts that automate the production of releases.
We run a nightly job on the Javascript code base that gathers various metrics and runs jslint on all .js files. This keeps things in check and in particular highlights any dangling-comma issues that would break IE but not be seen in development because of course we use Firefox for that. For the SmartClient app, we "make" by concatenating all required .js files (based on a manifest list) into a single file, run jslint on it, run jsmin on it, and create a versioned release file in CVS.
For middle-tier releases, we do a similar concatenation and produce a versioned server script in CVS.
On our Apache server, the client application is launched by a PHP application launcher that inlines the latest version of the app (parameterized with a .ini control file) into an HTML file and sets various parameters into an object called isc.appData. This allows us to "bridge" parameters across from the PHP world into the SmartClient/Javascript world.
Likewise, when the client makes calls to PHP middle-tier ServerObjects, they come through a wedge that ensures the proper client version/server version matchup is maintained when we do version upgrades during the workday.
Now that we are deployed and live, I am more convinced than ever that building this application in SmartClient was the right decision. There is absolutely no way we could have produced the richness of user experience with a page-based application, and no other AJAX GUI solution I could find had nearly the completeness of API's that SmartClient provides. You don't really get to understand this until you work with SmartClient for a few months. First the developers see the light; then the users get their eyes on a ListGrid with filterEditor, and the are hooked too.
[editor's note: fixed line breaks only]
In terms of actual deployment of SmartClient, we've had no issues whatsoever with SmartClient itself. 6.5 and the TreeFrog skin came out just in time to be included, and we've had no issue with crashes or mysterious behavior. The client base runs IE6 on contemporary hardware and performance has been fine. This is an intranet application, used by many people throughout our company.
This project has been in the works for about a year, with the first 4 months or so getting up to speed with basic fundamentals of SmartClient. Things like how to make the various types of callbacks work and how to use closures took a little experimentation. Since our app is object oriented, we don't have global references to things, so the "this.getID() + ".method()" paradigm is used often. When building complex Windows, we also use the "parent: this" trick to allow us to call methods of the Window from sub-objects like ListGrids and DynamicForms. One of the most challenging things, due to the complexity or our app, was getting scope chain resolutions to work right so we could call the functions at various levels of Window widget hierarchy and object hierarchy. Once these basic "best practices" were worked out, most things were amazingly easy to do in SmartClient.
Our app uses PHP in the middle tier and Oracle on the backend.
The client application is driven by an Application base class (client-side controller) we wrote that handles requests from the MenuBar to instantiate and initialize ChildWindows that provide actual functionality. The Application object creates a MenuBar and Canvas, into which it draws all ChildWindows. The Application object also controls which users can access each ChildWindow, via a permissions mechanism. Each ChildWindow adheres to a standard design (actually subclassing the same base class), registering itself with the Application object to indicate whether it's a singleton or should get destroyed and created each time it's needed. The window also communicates it's permissions parameters so the Application can deny access to unauthorized users.
As part of the standard ChildWindow implementation, an initialization method is provided, which if defined is called by the client-side controller (Appliction object) and takes data needed to initialize the ChildWindow (typically a master ID used to fetch detail records).
Each ChildWindow is defined in a like-named Javascript file, which allowed us to implement a Developer's menu that re-fetches the .js file and re-instantiates and re-initializes the ChildWindow. This was a huge time saver during development and testing, allowing us to walk a complex UI path to the window under development and then dynamically re-load it to test changes to the underlying Javascript code without reloading the entire application.
The PHP middle tier consists of a middle-tier controller that brokers requests to ServerObjects to satisfy both Data Bound Control operations (requests from ListGrids and DynamicForms) and individual RPC calls. We used a method whereby we would specify the middle-tier object and method to be called in the GET (?m=Object.Method) and all parameters in the POST. Data to/from the client application is serialized to JSON for transport.
Business logic is present in both PHP and Oracle stored procedures as appropriate.
From a deployment and release management perspective, we use a set of build/release scripts that automate the production of releases.
We run a nightly job on the Javascript code base that gathers various metrics and runs jslint on all .js files. This keeps things in check and in particular highlights any dangling-comma issues that would break IE but not be seen in development because of course we use Firefox for that. For the SmartClient app, we "make" by concatenating all required .js files (based on a manifest list) into a single file, run jslint on it, run jsmin on it, and create a versioned release file in CVS.
For middle-tier releases, we do a similar concatenation and produce a versioned server script in CVS.
On our Apache server, the client application is launched by a PHP application launcher that inlines the latest version of the app (parameterized with a .ini control file) into an HTML file and sets various parameters into an object called isc.appData. This allows us to "bridge" parameters across from the PHP world into the SmartClient/Javascript world.
Likewise, when the client makes calls to PHP middle-tier ServerObjects, they come through a wedge that ensures the proper client version/server version matchup is maintained when we do version upgrades during the workday.
Now that we are deployed and live, I am more convinced than ever that building this application in SmartClient was the right decision. There is absolutely no way we could have produced the richness of user experience with a page-based application, and no other AJAX GUI solution I could find had nearly the completeness of API's that SmartClient provides. You don't really get to understand this until you work with SmartClient for a few months. First the developers see the light; then the users get their eyes on a ListGrid with filterEditor, and the are hooked too.
[editor's note: fixed line breaks only]
Comment