Forward Engineering: Analysis Pseudo-code and OO Design Principles
White paper prepared by Codel
Services Ltd
©
Introduction
The purpose of this paper is to state some of the
OO design principles involved in successful model-lead analysis,
particularly in cases where the analysis is used for forward-engineering.
Since this is a model-led approach, the emphasis on
getting a robust and coherent model is greater then is normally expected.
However, the techniques involved are relatively new, so many of these
principles have only become evident in observing what works well in the
model.
Design Principles
#1.
Business rules as operations
Is what is shown in the model a business rule or an
operation? It is actually both, allowing the benefits of UML to help add
structure, precision and versatility as to how business rules are
specified.
Actually since we are in the analysis domain, it may
be more helpful of understanding operations as responsibilities.
So what is so similar between business rules and
operations? They both have:
(a)
logic
(b)
pre/post conditions (i.e. a contract)
(c)
arguments
(d)
reference to other conceptual entities and/or collaboration. This
is usually implicitly inferred in a model – but why not make explicit -
since this makes the model tighter?
(e)
hierarchies/inheritance/polymorphism
Treating them as operations also them be shown in
sequence models to show collaboration. This also emphasises encapsulation
as well, where collaborators need only know what their friend class is
doing - but not how it is doing (i.e. whether that class can expedite its
responsibility on its own or requires further collaboration)
Effectively such sequence models are a visual way of
describing the traditional “CRC card” (Class responsibility collaboration)
scenario!
#2.
Stereotypes of Analysis Class
To help developers understand what the main purpose
of class is, and also to help promote good class cohesion, the standard
robustness modelling stereotypes are used:
(a)
Controller - Main purpose of the class is process control. A good
example would be Trade Manager where the majority of its
responsibilities (thus business rules) are around control (confirmed by
the prevalence of "do" operations on the class).
(b)
Entity - Main purpose is to persisted what it owns - taking the
Trade Manager example further, persistence parts of it are delegated
to its constituent parts such as Identifier, Alternative Identifier,
Name etc, which are set as entities
(c)
Boundary - Main purposes is to sit on the fence between system and
outside world - although this must be taken in conceptual terms, and
should not be treated as an interface. A good example is the Request
class that must both understand the XML and the outermost working of the
STP framework.
#3.
Naming convention for business rules
Names of operations should follow a convention which
makes the purpose of the rule self evident.
This helps both users review, and enforces cohesion
and clarity of purpose in writing.
e.g. if an operation is "doXYZ" but its
implementation suggests setting many attributes for persistence, then this
would be a poorly named and written business rule.
Also a name convention makes clear that the purpose
of the operation is to satisfy a business rule, since if a "pure" OO
approach is taken many of these operations would be rationalised
The Naming convention is:
(a)
initialise - rules on how to set up the conceptual model
(b)
set<<X>> - rules including derivation, enrichment, creation
and copying of data that is to be persisted. Separate name conventions
(e.g. enrich<<X>>) for these are not recommended since this couples the
name with its implementation - which reduces opportunities for
polymorphism of rule sets, and forces a name change if implementation
changes)
(c)
do<<X>> - processing rules that govern what needs to be
done, the order of execution and what to do with exceptions
(d)
is<<X>> - processing rules on how to do evaluation, but that
makes no judgement as to whether response is correct e.g. is15a6
(e)
valid <<X>> - rules that perform evaluation but also makes
judgement as to if is correct
(f)
associate<<X>> - rules on how to link one item to another.
Note that most associations do not require a rule as the relationship can
be described from the model. It should only be shown as a rule if there
are constraints or other complexities associated with the relationship.
(g)
mapTo/From<<X>> - rules on what physical items to map to
(e.g. to persist) or from (e.g. lookup)
(h)
get<<X>> - public attributes have implicit getters so rule
is not generally required. Note that for is<<X>> named attributes,
the implicit operation is is<<X>> as well.
All can return Boolean, since a rule is either TRUE
or FALSE. Some setters may return VOID, if they don't have responsibility
of calling validation.
Operation and attribute names should also not
reference their class (for example TradeManager:: isTradeBond should be
rewritten as TradingAccount :: isBond). Firstly, auto generated
documentation will display the class name anyway, and secondly (and more
importantly) it reduces the scope of inheritance and polymorphism
opportunities.
#4.
Attribute visibility
Attributes are used to identify what domain knowledge
is required, most business rules will be based directly or indirectly
(through collaboration) on the value of these.
Attributes should generally not be made public – i.e.
access to them should only be though operations. An exception to this are
Boolean process attributes (of the style “is<<XYZ>>”). It is enough to
assume that there is an implicit getter for these since to explicitly add
an operation for these would add to model clutter. This is shown in the
model by making these attributes these protected or public.
So an attribute CLASSA::isSomething can be referenced
in the pseudocode by CLASS.isSomthing().
#5.
Classes know how to create themselves
Especially in the case of rule sets, it is useful to
conceptualise the ability of each sub-class in knowing whether or not it
extends the base class behaviour.
In the case of business rules, some short cuts have
been taken in the pseudo-code to prevent it from turning into code - i.e.
remember the operation is a business rule not a piece of code! This is
important to bear in mind when coding, so as not to take any
“inefficiencies” that may be acceptable in the analysis/design domain to
explain something, into the physical.
What is adopted is hybrid design pattern that
combines the factory and facade patterns. This is best shown by example in
the following section.
#6.
Classes know how to create themselves: Creating SubClasses
This creation pattern allows this class to
instantiate a subclass of itself. Any subsequent references to the class
will therefore use the correct subclass.
(The "abstract" identifier on the class denotes to
the developer that the parent class is not in itself instantiated)
It is a combination of the FACTORY and PROXY pattern.
The following code except shows how this is done and used:
Take three classes Parent Class A. Subclasses
B and C:
CLASS A
{
A a;
A()
{
if (** some logic **) {
a = new B();
} else {
a = new C();
}
}
public void someMethod()
{
a.someMethod();
}
}
So whenever object "a" is referred to the correct
subclass is referenced.
This is assumed in the analysis model since objects
are not referred to: Whenever an operation is invoked elsewhere it is
therefore assumed that the correct subclass is referred to.
For example another class subsequently referring to
a.someMethod() will either refer to B's or C's method depending
what was instantiated. This is ideal since once the class is created,
special behaviour is encapsulated, and only the abstract superclass is
required to be referenced.
If the specific instantiated subclass does need to be
identified (e.g. if subsequent logic is based on it), then rather than
using flags, use the following pseudocode:
IF a.Type = B then .....
I.e. the class always "knows" what type of subclass
it is.
#7. Classes know how to create themselves: Polymorphism, Overriding
Operations and Rule sets
The above example of how classes know how to create
themselves shows polymorphism of business rules in action.
Where an operation's behaviour extends that of a
parent (overriding) it is shown in the model with the <<override>>
stereotype.
As a modelling principle, use overriding as the
default, with the overriding logic just specifying the difference between
it and the parent behaviour as it makes specification easier to read.
However in complex inheritance situations, where only part of the parent
behaviour is inherited, this could be open to misinterpretation.
For example
parent rule: enrich one way then validate
<<override>> child rule: enrich another way.
In this case we want the validation step to remain
the same, but we don’t want to reiterate this for the child since we only
state what is different for the rule. This is another compelling reason
for making rules atomic!
Whilst this does lower the reuse potential, it is
still a valid OO principle since the operation inherits the same name
(just not its implementation. An outside caller just call the name on the
object without worrying about the subclass of object.
This implicitly polymorphic nature of business rules
- i.e.
"classifying a bond trade is a bit like the
generic debt one except....."
.....is probably the most compelling reason for
modelling business rules as operations, since this structure can be
modelled very well using inheritance. These sets of rules actually start
to look like the traditional rule set approach (except our approach is
easier to review of course !)
Classes know how to create themselves: Worked Example
ABSTRACT CLASS: Confirmations
Initialise ()
// Confirmations class knows which subclass to extend
itself by
IF **Some condition**
NEW TelexConfirmation
ELSE
NEW SWIFTConfirmation
ENDIF
FormatAddress()
//Some Generic behaviour
CLASS: TelexConfirmations::FormatAddress()
//Some Overloaded Behaviour
CLASS: SWIFTConfirmations::FormatAddress()
//Some Overloaded Behaviour
CLASS:TradeAccount::Initialise()
NEW Confirmations
IF Confirmations.Initialise() = OK //Strictly
speaking this has occurred in the previous step, but for analysis purposes
its clearer to state again.
Confirmations.FormatAddress() //Don't need to
worry about which subclass to call.
END IF


© 2002-2007 Codel Services Ltd
This paper has been prepared
by Codel Services Ltd to illustrate how structured business
modelling can help your organisation. Codel Services Ltd is an IT
Consultancy specialising in business modelling. If you would like further
information, please contact us at: Deryck Brailsford, Codel Services Ltd,
Dale Hill Cottage, Kirby-Le-Soken, Essex CO13 0EN,United Kingdom.
Telephone: +44 (0)1255 862354/Mobile: + 44 (0)7710 435227/e-mail: info@codel-services.com