Principles 1-7
Home Business Change Analysis & Design Agile Testing Templates About us

Principles 1-7
Principles 8-15
Modelling Patterns
Back

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

 

Next

© 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