The name of the class clearly reflects the role it plays.
The description of the class clearly conveys the purpose of
the class.
The class represents a single well-defined abstraction.
The class's attributes and operations are all essential to
fulfilling the responsibilities of the class.
Each class represents a small, consistent and unique set of
responsibilities.
The responsibilities of the class are well-defined, clearly
stated, and clearly related to the purpose of the class.
Each class is relatively self-contained, and is loosely
coupled to other classes.
The responsibilities of the class are at a consistent level
of abstraction (i.e. high-level (application-level) and low-level
(implementation-level) responsibilities are not mixed).
Classes in the same inheritance hierarchy possess unique
class attributes, operations and relationships (i.e. they inherit all
common attributes, operations and relationships).
The complete life-cycle of an instance of the class is
accounted for. Each object is created, used, and removed by one or more
use-case realizations.
The class satisfies the behavioral requirements established
by the use-case realizations.
All requirements on the class in the requirement
specification are addressed.
The demands on the class (as reflected in the class
description and by the objects in sequence diagrams) are consistent with
the class's state machine.
All responsibilities of the class are related, such that it
is not possible for the class to exist in a system where some of its
responsibilities are used, but not others.
The generalization hierarchy is balanced, such that there are
no classes for which the hierarchy is unusually flat or deep.
Obvious commonality has been reflected in the inheritance
hierarchy.
There are no superclasses which appear to be merges of the
attributes of the subclasses.
There are no intermediate abstract classes in the inheritance
hierarchy with orthogonal properties, examples of which include duplicated
subclasses on both sides of an inheritance tree.
Inheritance is used to capture common design abstractions,
not primarily for implementation considerations, i.e. to reuse bits of
code or class structure.
The state machine is as simple as possible while still
expressing the required behavior.
The state machine does not contain any superfluous states or
transitions.
The state machine has a clear context.
All referenced objects are visible to the enclosing object.
The state machine is efficient, and carries out its behavior
with an optimal balance of time and resources as defined by the actions it
dispatches.
The state machine is understandable.
The state and transition names are understandable in the
context of the domain of the system.
The state names indicate what is being waited for or what
is happening, rather than what has happened.
The state and transition names are unique within the state
machine (although not a strict requirements, it aids in debugging to
enforce unique names).
Logical groupings of states are contained in composite
states.
Composite states have been used effectively to reduce
complexity?
Transition labels reflect the underlying cause of the
transition.
There are no code fragments on state transitions which are
more than 25 lines of detail code; instead, functions have been used
effectively to reduce transition code complexity.
State machine nesting has been examined to ensure that
nesting depth is not too deep to be understandable; one or two levels of
substates are usually sufficient for most complex behaviors.
Active classes have been used instead of
concurrent substates; active classes are nearly always a better alternative and
more understandable than concurrent substates.
Error or maintenance states have been accounted for.
Substates have been used instead of extended state variables;
there is no evidence of transition guard conditions testing several
variables to determine which to state the transition should occur.
The state machine does not resemble a flow chart.
The state machine does not appear to have been overly
de-composed, consisting of nested state machines with a single sub-state.
In cases where the nested sub-state is a placeholder for future design
work or subclassing, this may be temporarily acceptable providing that the
choice has been a conscious one.