Will Duquette

Anatomy of a Large Application: Architectural Patterns and Solutions

JNEM, the Joint Non-kinetic Effects Model, is a large simulation application. Written almost entirely in Tcl/Tk, it makes architectural use of the Snit object system and the SQLite3 database engine. The paper will address a number of architectural patterns and solutions that have been found useful during the two-plus years of JNEM development. Patterns include the three-tier package architecture, application, domain, and utility; Snit types as application modules; saving and restoring application state; data-base backed objects and the managed- object pattern; SQLite3 as an application debugger; and a generalization of the scrollbar/scrollable pattern.

Here is a brief summary of the patterns listed above, which will be described in full in the final paper.

* Three-tier package architecture. Virtually all JNEM code resides in packages, each containing multiple modules, which reside in one of three tiers. The lowest tier is the utility tier; code in this tier can, in principle, be brought over unchanged to new projects. Modules in this tier should make few, if any, assumptions about the environment in which they will be running; for example, if multiple objects cooperate they must be explicitly wired together by the application. The middle tier is the domain tier. Modules in this tier are specific to the project's domain, but are designed to be used in multiple applications within that domain. They may make more assumptions and implement more policy than utility modules. Finally, each application within the domain has the bulk of its code in an application package. Application modules may make any assumptions the programmer likes; for example, they may presume the existence of other application modules by name, rather than by being wired together. In the application tier, consequently, singletons are preferred to object types unless multiple instances are definitely required.

* Snit types as application modules. Per Mark Roseman's paper of a few years ago, we've found it useful for each application module to have a single entry point, an ensemble command whose subcommands are the module's public operations. With proper pragmas, a Snit type makes an outstanding module ensemble.

* As a simulation that may run for many days, JNEM must be able to save its state. By adopting SQLite3 and a few simple conventions, saving and restoring state becomes easy.

* The data-base backed object pattern is a straightforward and lightweight way to use Snit to add behavior to objects whose main data store is an SQLite3 database. The managed-object pattern is used to create Snit instances on the fly, as needed, and cache them for later use.

* Given that much of the application's data is stored in an SQLite3 database, the ability to enter queries from the application's console and receive formatted responses is a powerful debugging tool.

* The Scrollbar/Scrollbar pattern, familiar from Tk scrollbar, text, canvas, and other widgets, is a paradigm for how to link two objects in a control relationship when each must update the other on change. JNEM's GUIs use this pattern to implement searching and filtering controls for a log display.