General Rules
- The Comparator should always be in a consistent state. Every user action
should run to completion or terminate itself, returning the system to a
deterministic state. If there is a manipulable value, it should have some
default, even if the default is to do or define nothing. All data should have a
deterministic value. If an entity cannot present a consistent state, it should
employ some locking mechanism to prevent others from inspecting it. It should
never be possible to see an incomplete transaction.
- Entities with both persistable and non-persistable properties should
distinguish what will be preserved when the entity is persisted.
- Computations should use a bounded amount of memory or have some mechanism
to prevent exhausting the virtual machine heap. Even if the computation can
trap the memory error, other threads may have unpredictably been unable to
allocate memory and the application cannot reliably continue.
- Operations should fail fast. That is, when an operation cannot be
completed, a minimum of work should be performed before the operation is
aborted.
- All exceptions should be caught and handled at module boundaries. A module
should never allow an exception to cross to another module, bubble up to the
Comparator itself, unwind the event thread, or otherwise be handled by the
default exception handler.
- The Comparator facilities for logging, debugging, and messaging should be
used in preference to external libraries.
Working with Data
- Every data object or its owner must define a locking mechanism. If there is
no explicitly defined mechanism, the object should only be accessed while on
the event thread.
- Every time a data object is changed, the change should be announced to all
potential viewers of the object. A series of operations can be treated as an
atomic transaction, with a single announcement at the end, if the object is
protected by a locking mechanism.
- When two views exchange data, it is always done through the Comparator
storage. This allows anyone interested in watching the data to easily access
the data and receive update notifications.
- A computation with discrete steps should provide access to as many of the
intermediate results as possible. When appropriate, these results should be
cached for faster access.
- A data object should never be cast from an immutable version to a mutable
version unless there is some prearranged agreement that the object can safely
be altered. This allows data providers to skip wrapping many data objects into
immutable containers that consume more memory and have slower access
times.
User Interface
- No view should create a program modal dialog or alter the frame outside of
its view area.
- All interface components should use the Swing library.
- All changes to the user interface must be done on the event thread. This is
a requirement of Swing. Any computation requiring a noticeable amount of time
to complete should not be done on the event thread. This prevents the event
thread from blocking which gives the program a frozen appearance.
- Never expose an interface component to multiple views. Swing does not
correctly support simultaneously placing a component into multiple containers.
Instead, create separate components that share a common store.
- All views should use a consistent style of widgets and graphical elements.
The colors, fonts, and styles of the default widgets are defined by the look
and feel. Custom widgets should use also these resource values to duplicate the
visual style.
- Views should have a minimum of configurable options accessible through the
interface. Any option adjustable during runtime should only change data values
and not select different code paths.