Coding With UML
Coding With UML
Stephen J. Mellor
What’s the problem?
1
A simple embedded system
Set the time,
Close the door,
Press ‘cook’
It’s that easy!
But…..
For safety, the door must be closed
If the door is opened, cooking must stop.
There are some details about timers
And power levels……
And…. And…. And….
Complex Systems
• We want to be able to:
– Develop concepts rapidly
– Test ideas with confidence
– Reduce required code by
identification of cross-cutting
commonality
– Understand performance
before implementation
– Adapt easily to hardware and
platform changes
– Maximize parallel development
Abstraction
Price Performance System Complexity
High Level
Assembly UML Models
Language
Compiler Model
Assembler
Compiler
Increased
Productivity
Testing
• Systems are difficult to test—and it occurs too
late.
– Wasted effort in constructing wrong code
– Late discovery of problems and delayed delivery
What we get
What we’d like
Defect
Rate
Mapping
2
Code for a Microwave Oven
struct Oven_s {
UniqueID_t OvenID; /* * OvenID */
/* Association storage */
Door_s * Door _R1;
Cooking_Step_s * Cooking_Step _R2;
Cooking_Step_s * Cooking_Step_R3;
Magnetron_s * Magnetron_R4;
/* Association storage */
Oven_s * Oven_R2;
Oven_s * Oven_R3;
isOpen
R2 Cooking Step
Oven
R3
stepNumber
cookingTime
Magnetron powerLevel
R4
powerOutput
pulseTimer
Associations
• Classes may be associated to capture
relationships in the subject matter.
• We number the relationships to ensure
uniqueness.
describes first
R2 Cooking Step
parameters for executes first
Oven
R3
stepNumber
cookingTime
describes second executes second
powerLevel
parameters for
Association Classes
• Some associations give rise to other classes.
Font Table
fontName:string
Loaded Font
*
R5 fontName:string
* printerID:string
Logical Printer
printerID:string
current_state:state<State_Model>
Generalization
• One class may be a supertype of others.
follows
Allocated Job
R3
printerID:string
jobNumber:integer 0...1
{disjoint, preceeds
R2 Complete}
printerID:string printerID:string
jobNumber:integer jobNumber:integer
Class Diagram
Abstract classes based on both:
Data
Behavior
R1
Door
isOpen
R2 Cooking Step
Oven
R3
stepNumber
cookingTime
Magnetron powerLevel
R4
powerOutput
pulseTimer
Coding Behavior in UML
3
State Event Matrix for the Oven
static const StateNumber_t Oven_StateEventMatrix[3][4] =
{
/* Row 1: Oven_State_1 'Not_Cooking' */
{ Oven_State_2, CANT_HAPPEN, IS_IGNORED, IS_IGNORED },
/* Row 2: Oven_State_2 'Checking_Safety' */
{ Oven_State_2, Oven_State_3, IS_IGNORED, IS_IGNORED },
/* Row 3: Oven_State_3 'Cooking' */
{ CANT_HAPPEN, CANT_HAPPEN, Oven_State_3, Oven_State_1 }
};
…and the Cooking Step
static const StateNumber_t Cooking_Step_StateEventMatrix[3][3] =
{
/* Row 1: Cooking_State_1 'Ready' */
{ Cooking_State_2, IS_IGNORED, Cooking_State_3 },
/* Row 2: Cooking_State_2 'Executing' */
{ IS_IGNORED, Cooking_State_1, Cooking_State_3 },
/* Row 3: Cooking_State_3 'Complete' */
{ IS_IGNORED, IS_IGNORED, IS_IGNORED }
};
Lifecycles
Build a lifecycle model
for each class.
Ready
startStep
interrupt
Executing
Lifecycle for
Cooking Step finishStep
finishStep
Complete
State Event Matrix for Oven
Signal
start cook step_done stop
State
CANT CANT
Not Cooking Checking IGNORED
HAPPEN HAPPEN
CANT
Checking Checking Cooking IGNORED
HAPPEN
CANT CANT
Cooking Cooking Not Cooking
HAPPEN HAPPEN
Event dispatching code for the Oven
. . .
state = instance->current_state;
next_state = Oven_StateEventMatrix[ state ][ event_number ];
if ( next_state <= 3 )
{
/* Update state and execute the state action */
instance->current_state = next_state;
( *Oven_Actions[ next_state ] )( instance, event );
}
. . .
… and for Cooking Step
. . .
state = instance->current_state;
next_state = Cooking_Step_StateEventMatrix
[ state ][ event_number ];
if ( next_state <= 3 ) {
/* Update state and execute the state action */
instance->current_state = next_state;
( *Cooking_Step_Actions[ next_state ] )( instance, event );
}
. . .
..and the rule to produce it
. . .
state = instance->current_state;
next_state = <class name>_StateEventMatrix
[ state ][ event_number ];
if ( next_state <= <class num_states> )
{
/* Update state and execute the state action */
instance->current_state = next_state;
( *<class name>_Actions[ next_state ] )( instance, event );
}
. . .
Constructing the State Event Matrix
static const State_Number_t <class name>_StateEventMatrix
[<class states>][<class events>] =
{
/* Row <state1 number>: <state1 name> */
{ <state1event1 next_state number>,
<state1event2 next_state number>, . . . }
/* Row <state2 number>: <state2 name> */
{ <state2event1 next_state number>,
<state2event2 next_state number>, . . . }
. . .
};
Coding Communication in UML
4
Instances
Recipe
Recipe Recipe Cooking Cooking Heating
Name Time Temp Rate
Recipe Name {I}
Batch Nylon 23 200 2.23
Cooking Time Batch
Kevlar 45 250 4.69
Cooking Temperature Batch ID Amount of Recipe
Batch ID {I} Stuff 67 280 1.82 Status
Heating Rate Batch Name
Amount of Batch
Recipe Name {R2} 1 100 Nylon Filling
Status 2 127 Kevlar Emptying
3 93 Nylon Filling
4 123 Stuff Cooking
Executing the Model
startStep
interrupt
Executing
– timers finishStep
finishStep
Complete
– other instances as
they execute
Instances
• An executable model Ready
finishStep
finishStep
Complete
Oven
Not Cooking
start
start Ready
startStep
interrupt
Checking
finish_step Executing
stop cook
finishStep
finishStep
Cooking
Complete
How does time work….?
– There is no global clock
– Time is relative to each observer
Checking
cook finish_step
stop
Cooking
Ready Ready
startStep
startStep interrupt interrupt
Executing
Executing
finishStep finishStep
finishStep finishStep
Complete Complete
Communication
Oven Cooking Step 2
5
Coding Logic in UML
related by oven->[R4];
objectB
magnetron.powerOutput =
self.powerLevel;
objectA
generate powerOn to
magnetron;
Action Language
Executing
Lifecycle for Ready
Cooking Step startStep Entry/
Executing
select one magnetron
finishStep related by oven->[R4];
Complete magnetron.powerOutput =
self.powerLevel;
generate powerOn to magnetron;
Sequence Diagrams
Diagrams
Class
Diagrams
Communcation
Diagrams
xtUML
xtUML is a streamlined subset of the UML
industry standard that:
(x) Executes models
– Allows for early verification
– Optimized code
Completing the Models
6
Timers
To build an implementation, we will use timers.
magnetronID:arbitrary_id
powerOutput;integer
pulseTimer:inst_ref<Timer>
2. PulseON 2. PulseOFF
Timers are generally provided.
Timers
<<external entity>>
SecondsTimer
<operation>
timer_start(seconds : integer, event_inst : inst<Event>) : inst_ref <Timer>
timer_cancel(timer_inst_ref : inst_ref<Timer>) : boolean
timer_remaining_time(timer_inst_ref : inst_ref<Timer>) : integer
<<operation>>
current_date : date
create_date(second : integer,minute : integer,hour : integer,day : integer,month : integer, year
get_second(date : date) : integer
get_minute(date : date) : integer
get_hour(date : date) : integer
current_clock : timestamp
timer_start(microseconds : integer, event_inst : inst<Event>) : inst_ref<Timer>
timer_reset_time(timer_inst_ref : inst_ref<Timer>, microseconds : integer) : boolean
timer_add_time(timer_inst_ref : inst_ref<Timer>, microseconds : integer) : boolean
timer_cancel(timer_inst_ref : inst_ref<Timer>) : boolean
Tying an instance of an Event to a Timer
3. PulseOFF
Entry/
If self.powerOutput < 10
seconds_off = (10 –self.powerOutput);
create event instance pulseon of MW_MT3:’pulse_on’ to self;
self.pulseTimer = Bridge STIM::timer_start(seconds;seconds_off,
event_inst;pulseon);
end if;
Bridge to Hardware
We must also bridge to the hardware.
• Bridge PIO::PulseOff();
• If self.powerOutput < 10
• seconds_off = (10 - self.powerOutput);
• create event instance pulseon of W_MT3:'pulse_on' to self;
• self.pulseTimer = Bridge STIM::timer_start(
seconds:seconds_off, event_inst:pulseon);
• end if;
External Entities
The operations allow bridging from one domain to another.
<<operation>> <<operation>>
DisableKeyEntry : void timer_start(seconds : integer, event_inst : i…
EnableKeyEntry : void timer_cancel(timer_inst_ref : inst_ref<Time…
timer_remainging_time(timer_inst_ref : inst_r…
<<external entity>>
Process Input/Output <<external entity>>
Timer
<<operation>> <<operation>>
CookingOn : void current_date : date
CookingOff : void create_date(second : integer, minute : inte..
PulseOn : void get_second(date : date) : integer
PulseOff : void get_minute (date : date) : integer
Initialization
• select any oven from instances of MW_OV;
• If (empty oven)
• create object instance oven of MW_OV;
• Bridge CP::EnableKeyEntry();
• // now that system is initialized
• end if;
Domain Package Diagram
– Application
– Proxies for
external <<external entity>>
entities <<subsystem>>
External Entities
– Datatypes Cooking Control
– Functions
<<data type>> <<function>>
Datatypes Functions
Mapping to an Implementation
7
Concurrency in the generated code
– An application is inherently concurrent except
insofar that it is purposefully sequenced
– xtUML captures necessary sequentialization in
the model.
– Model compilers translate the concurrent
specification onto an implementation of
concurrency.
So, what should the structure of that
implementation be?
Activities
• The basic unit of allocation is the activity.
Oven cooking
pulse OFF
executing
Cooking Magnetron
Step
Activities
• Each activity is caused to execute on receipt of a signal.
Door closed
Door closed
pulse ON
• What happens next? Oven checking
safety
Magnetron
Oven cooking
pulse OFF
executing
Cooking Magnetron
Step
Dequeuing Signals
• When a signal is received, we:
– Determine what to do next based on the
name of the signal and the current state
– Do it
Oven
Signal
start cook step_done stop
State
Not Cooking
CANT CANT start
Not Cooking Checking IGNORED
HAPPEN HAPPEN start
CANT Checking
Checking Checking Cooking IGNORED
HAPPEN step_done
stop cook
CANT CANT
Cooking Cooking Not Cooking
HAPPEN HAPPEN Cooking
Communication
• If actions generate signals to other objects, we:
– Store the new signals
on an internal queue
Door
– Pick them off closed
one by one
checking
– When the queue Oven safety
executing
Cooking
Step
External Communication
Door closed
checking
Oven safety
Ready
NotCooking startStep
interrupt
start
Executing
Checking
stop cook finishStep
finishStep
Cooking Complete
Single Tasking Concurrency
• Concurrency is simulated, but:
– The “granularity of concurrency” is an activity
– An activity must wait for another to finish
– The waiting activity may be higher priority
=> Priority inversion
A Direct Mapping
We may map each class to a separate task.
Cooking Step
Oven
Ready
Not Cooking
start startStep interrupt
start
Executing
Checking
finishStep finishStep
stop cook
Complete CookingStep
Cooking Oven
isOpen
R2 CookingStep
Oven
stepNumber
cookingTime
powerLevel
R3
Magnetron
R4
powerOutput
pulseTimer
Multi-Tasking Concurrency
For this mapping, we choose to allocate classes.
CookingStep
Door
stepNumber
isOpen
cookingTime
powerLevel
Oven
Magnetron
powerOutput
pulseTimer
More information for translation
• We need also to state:
– Priorities of tasks
– Which classes go in which classes
8
Separation
Application
Executing
Entry/
Select one magnetron
Executing
understand the application,
and
related by oven->[R4];
Magnetron. powerOutput=
self.powerLevel;
Generate powerOnto magnetron;
Complete
architecture
Checking
Checking Settings
Entry/
OpenShutter( 0.5 );
• Each evolves at its own pace.
MeasureLight();
Architecture
Mappings
• Mapping by hand:
– Is error prone
– Not repeatable
– Not scalable
– Not predictable
– Leads to integration problems
Mapping
vs.
Scale
• The cost of a design rises steeply as system size increases.
Integration costs
Reuse benefits
Number of classes
Reuse
• Designs are difficult to reuse.
Retargeting
• Designs are difficult to retarget.
Instrumentation and Diagnosis
• Designs are difficult to instrument and diagnose.
Optimization
• Large designs are difficult to optimize reliably.
Model Compilers
9
Model Compiler
• A set of rules: Translation
rules interpreted by a
generator against the Rules
repository
• An execution engine: A
limited set of reusable
components sufficient to
Reusable library
execute Executable UML
Purpose
• To generate code….
Miracle
occurs here
Model Database
Application Models
Class
Code for the
Class ID Name Descr'n
System
100 Oven .....
101 Door .....State
Class ID State # Name
101 1 Ready
101 2 Executing
Purpose
• ….traverse the model database and...
Rules
Application Models
Model Database
Class
Class ID Application
Name Descr'n Models
100 Oven .....State Generator Reusable Library
101 Door
Class ID.....
State # Name
101 1 Ready
101 2 Executing
• Libraries, Legacy or
• Hand-written code
Code for
the System
Model Compiler
• An architecture is an Executable UML model compiler.
– data
– control
– structures
– time
10
Models Execute on Instances
Execution Control
Execution
Coding with UML Models
11
Model it!
name name
name name
name name
Analyze the
performance
Not as good as
you need?
Re-Mark it!
Task A Task B
name name
Task A Task A
B Task A
B
name name
vs.
Testing
• Executable models can be tested early
Defect
Rate
Unscalable approaches
Number of classes
Reuse
Designs can be reused.
Application Models
Retargeting
Designs can be re-targetted by selecting a different
model compiler.
Instrumentation and Diagnosis
Designs are instrumented and diagnosed in one place:
the model compiler.
Optimization
Optimization is propagated throughout the system
reliably using automated rules.
Skills
• Application experts worry about the
application…