The Baker’s Dozen of Use Cases

Rule 11 – Don’t abuse «include»

A use case contains all the steps (transactions) needed to describe how the actor (our stakeholder) achieves their goal (or doesn’t; depending on the particular conditions of the scenario). Therefore a use case is a stand-alone entity – it encapsulates all the behaviour necessary to describe all the possible scenarios connected to achieving a particular end result. That’s what makes use cases such a powerful analysis tool – they give the system’s requirements context.  Use case are also an extremely useful project management tool. By implementing a single use case you can deliver something complete, and of value, to the customer. The system may do nothing else, but at least the customer can solve one problem with it.

Occasionally, two use cases contain a sequence of transactions common to both sets of scenarios. This sequence may not necessarily occur at the same point in each use case (for example, the beginning) but will always be in the same order.

image

 

UML provides a mechanism for extracting this common information into its own use case. The mechanism is called the «include» relationship. The semantics of the «include» relationship mean that the base use cases are only complete if they fully, and completely, contain the contents of the included use case.

image

Included use cases (if you must use them)

This relationship can sometimes be useful, particularly if a sequence of transactions is repeated many times.

However, misunderstanding of «include» tends to lead to a very common abuse: functional decomposition of use cases.

Many use case modellers use the «include» relationship to split a complex use case into a number of smaller, simpler use cases. This can lead, in extreme cases, to an explosion of use cases, with leaf-node use cases capturing trivial functional requirements (for example “Capture button press”).  

These trivial use cases often have no meaning to stakeholders, who should be focussed on what they want to happen, rather than how it happens.  Also, there is a huge overhead is creating, reviewing and maintaining this vast number of use cases.

I call this approach “Design Cases” to differentiate it from a use case.

 

image

Design cases in action

Rather worryingly, several organisations actively promote Design Cases for requirements analysis.  The appeal is obvious:  functional decomposition is a familiar concept with most developers (and if it isn’t they really shouldn’t be developing software!); and it allows the developer to settle back into the comfortable territory of solving problems (rather than defining them)

Remember, use cases are an analysis tool for understanding the system. A simple, coherent set of use cases, reflecting the usage of the system from the customer’s perspective is far more effective than demonstrating, to the n-th level, how the system will operate. That’s what design verification is for.

My advice is to avoid «include» wherever possible.  Prefer repetition of text within the use case description, over trying to identify and extract commonality.  In this way each use case remains separate and complete; and there is no temptation to fall into the functional decomposition trap.  That way lies madness (or at least analysis paralysis).

 

<<Prev     Next>>

Posted in Design Issues, UML | Tagged , , , , , , | 1 Comment

void main(void)–the argument continues…

For, what must be, years now the perpetual argument among programmers in various forums  resurfaces about the legality, or not, of the use of void as the return type for the main function.

I generally try and ignore these arguments as it seems such a trivial point, but maybe it’s because yet another birthday has just passed it’s time to put my two-penneth in.

Before we start, hopefully we all agree that the following code is an abomination:

main() { }

You would probably be more shocked if I told you that this comes from a fairly recent book (2008) Programming 32-bit Microcontrollers in C. Shame on you all.

The argument against the use of void has weighty backing, notability the creator of C++, no other than Bjarne Stroustrup himself. The following is taken from his very useful C++ Style and Technique FAQ:

The definition

void main() { /* ... */ }

is not and never has been C++, nor has it even been C. See the ISO C++ standard 3.6.1[2] or the ISO C standard 5.1.2.2.1. A conforming implementation accepts

int main() { /* ... */ }

and

int main(int argc, char* argv[]) { /* ... */ }

He then goes on to state;

A conforming implementation may provide more versions of main(), but they must all have return type int. The int returned by main() is a way for a program to return a value to “the system” that invokes it. On systems that doesn’t provide such a facility the return value is ignored, but that doesn’t make “void main()” legal C++ or legal C. Even if your compiler accepts “void main()” avoid it, or risk being considered ignorant by C and C++ programmers

Ouch; ignorant, moi. I take that as a personal insult Winking smile

Unfortunately, what Prof. Strousturp is failing to recognise (or possibly acknowledge) is the hundreds, if not thousands, of embedded programmers out there. For example, in the text above the key line is:

The int returned by main() is a way for a program to return a value to “the system” that invokes it.

Deeply embedded systems don’t have a “system” that invokes it, so there is nowhere for it return to and thus having an int return type is actually misleading.

However, I hear you shout, the standard says it must be; not so.

Both the C and C++ standards define two types of execution environments

  • Freestanding
  • Hosted

To quote the C standard (5.1.2.1):

In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation defined.

and the C++ standard (3.6.1)

It is implementation-defined whether a program in a freestanding environment is required to define a main function

So there you have it your honour, embedded systems are freestanding, and as so I can call the startup anything, therefore void main(void) is perfectly legal.

So I would argue, not understanding that void main(void) is perfectly acceptable in for freestanding environment is in risk of being considered ignorant of the finer details of embedded programming.

I know this won’t be the end of it but next time someone starts down this line, just ask them to explain the difference between a freestanding and hosted environment (makes a nice interview question as well!).

Posted in C/C++ Programming | Tagged | 8 Comments

The Baker’s Dozen of Use Cases

Rule 10:  The magical number seven (plus or minus two)

Psychologist George Miller, in his seminal 1956 paper "The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information", identified a limit on the capacity of human working memory. He found that adults have the capability to hold between five and nine ‘chunks’ of information at any one time. A ‘chunk’ may be a number, letter, word or some other cohesive set of data.

What has this to do with use cases? One of the primary functions of writing use cases is requirements validation – that is, are we actually building the correct system? The use case model is a technique for presenting the system requirements such that the customer can say either yes, we have a correct understanding of how the system should work; or no, we have misunderstood the system.

When presenting information to our (probably non-technical) customer it makes sense to keep the information content manageable. Try to keep the number of transactions in any one flow (that is, a sequence of use case steps between a trigger event and a conclusion) to between five and nine. This gives your customers the best chance of comprehending what you’re writing.

This means that the use case stops being a list of all the system requirements and becomes a précis of the system requirements. Each transaction may therefore equate to more than one system requirement. In practice this is not as over-simplifying as it sounds: requirements are often ‘clustered’ around elements of data and their production and manipulation – effectively what each use case transaction describes.

The skill in writing good use cases is the ability to précis requirements together to minimise the number of use case steps, without creating simplistic use cases.

The ‘seven, plus or minus two’ rule is not hard and fast; more a guideline. If your description has ten steps, this is not a problem; however, if it has thirty then there’s a chance you’ve over-complicated the step. The same is true at the other limit: three steps is fine; one step means you may have over-simplified and lost detail.

 

<<Prev     Next>>

Posted in Design Issues | Tagged , , , | 1 Comment

C++ Overheads

Recently IAR have finally released full support for C++ (adding exceptions and RTTI) to their family of cross compilers. Initially the kickstart (free) version had not had exceptions and RTTI enabled, however with the release of version 6.10.2 this has now been rectified.

We currently use the IAR compilers on our training courses, targeting an NXP LPC2129 (ARM7TDMI) based systems. As part of verifying that the previous version’s (v5.41) projects still work with v6.10, I decided to investigate the potential overheads of full C++ in this environment (I’m pleased to say all projects worked under v6.10 without modification – phew).

Here are my preliminary findings and I’ll add to them as I investigate further:

First off, I created a project based on the C++ main project, giving the following code:

int main()
{
return 0;
}

[Yes I know, return 0 isn’t necessary and it’s perfectly legal to have “void main()” in C++]

First off, the default language selection is still “Extended Embedded C++”, so I needed to change this to full C++. All build numbers are based on a Debug setting and I/O set to semi-hosting (I/O via debugger terminal window).

image

The build then gave (in bytes):

  • code – 296
  • const – 1
  • data – 8704

The data size surprised me, but by checking the default settings in the Linker configuration file, the default stack size was set to 0x2000 (8192). By changing this to 0x400 (1024) the data requirement dropped to 1536 bytes. I haven’t, as yet, dug down to where the other 500+ bytes are coming from (for another day).

Continue reading

Posted in C/C++ Programming | 10 Comments

The Baker’s Dozen of Use Cases

Rule 9 – Build yourself a Data Dictionary

Transactions between the actors and the system typically involve the transfer of data.  This data has to be defined somewhere.  If you’ve built a Domain Model ( see Part 5 – here) most of the data will be identified there; but even then the class diagram is not always the most practical place to capture the sort of information you need to record.

Another way to capture this information is in a Data Dictionary.  A data dictionary defines each piece of data in the system, and attributes about that data.  Typically, a data dictionary holds (but is not limited to) the following:

  • An Identifier.  This is how the data will be referred to.  Remember to use a term that has meaning in the problem domain.
  • Definition.  What does this data represent?  (And remember: a good definition consists of a genus – what type of thing I’m defining – and a description)
  • Units of measure; if applicable
  • Valid range; again, if applicable
  • Resolution.  That is, what’s the smallest difference I can measure?  This can become important if your implementation may use fixed point number schemes (for example).

This information is all vital to the developers who must design and code interfaces, etc. but it also has benefit when writing use case descriptions – it decouples the behaviour of the system from its data.

Just as we should decouple user interface details from the use case description (see Rule 8) so should we decouple the data transactions.  Describing the data requirements of a transaction in the use case description is cumbersome and leads to a potential maintenance problem (what if the resolution of a data item changes?  Or its units of measure?  Ask the team that developed the flight systems software of the Mars Climate Orbiter about getting units of measure confused!)

Data Dictionary

As you define your data dictionary, you can refer to data items (by their name) in the use case text.  Use some typographical convention (I use italics) to identify a data item from the data dictionary; or, you could hyperlink it. 

If the data requirements change you shouldn’t need to change the use case – unless it leads to a change in behaviour.  Similarly, you don’t need to elaborately detail exception flows for invalid data.  The data dictionary defines what is valid; the use case defines what should happen if we receive invalid data.  A simple, clear separation of responsibilities.
 
The Data Dictionary is not a new idea.  Twenty years ago, when I started developing software, a Data Dictionary was always created, and was considered a vital part of the design.  Unfortunately, it seems to have gone out of fashion, or been forgotten, in many software development circles.

 

<<Prev     Next>>

Posted in Design Issues | Tagged , , , , , | Leave a comment

The Baker’s Dozen of Use Cases

RULE 8: Don’t describe the user interface

For many users the user interface is the system.  Prototypes and mock-ups of the man-machine interface (MMI) are a fantastic way of eliciting requirements and use case behaviours from your stakeholders.  And when defining use case descriptions adding MMI ‘screenshots’ and images can help illuminate the behaviour of the system to your customers.

UI prototyping the use case

 

It is very tempting to describe use case transactions in terms of MMI elements, in an attempt to make them more understandable to the customer.  However, be aware: this is a very high maintenance solution.  The one thing that can almost be guaranteed in the design of any system is that the MMI will change.  A lot.  By writing your use case descriptions in terms of user interface elements you will be constantly going back and revising your use case text (and reviewing, and doing impact analysis… you do these, don’t you?!)

To minimise the maintenance effort of a regularly-changing user interface we must uncouple the user interface from the functionality of the system.  We must separate the effects of information flowing into and out of the system – What the information content is and how the system responds to it – from the presentation of that information to the user.

The use case description defines the desired requests and responses to the system; the MMI defines how those requests and response are manifested.

An event-mapping table can be used to map functions of the MMI (or indeed any interface specification) to the system event (transaction) it invokes or is in response to.  Using an event-mapping table de-couples the interface from its function. 

 

UI to Event mapping

Events are typically one of the following:

COMMAND
A control input to the system
Used to control the behaviour of the system

INPUT
Normally represent a change in the environment
May be an analog or digital signal
The system may or may not respond to the change

OUTPUT
A signal to the environment from the system
Used to effect changes in the environment
May be an analog or digital signal

STATUS
Feedback data from the system
Contains information about the current system state

The mapping table allocates some user interface operation (which could be as simple as a drop-list selection, or as complex as a whole sequence of button pushes or mouse clicks) onto a system behaviour.

In our simple example, pushing the big green button is our UI action.  We’ve mapped this onto the ‘START SYSTEM’ command.  Similarly, when the system is ready, this ‘READY’ status event is mapped onto the illumination of the LED.  Now, if the user decides they don’t want a ‘ready’ LED but instead want a 16 x 2 character display, we can simply re-map the ‘READY’ status event onto a displayed message (something creative like "System Ready")

In this way you only need to change the use case description when the functionality of the system changes (hopefully, far less often than the MMI!)

Doing this separation also alleviates that all-to-common problem of poorly-written requirement specifications: the User Interface Specification contains half the functional behaviour of the system; and the System Requirements Specification contains half the user interface detail!

 

<<Prev     Next>>

Posted in Design Issues, General | 3 Comments

C-201x

The last few years have been dominated by the development of the new C++ standard (still generally referred too as C++0x  but now expected in 2011). This will be the second edition of the C++ standard (ISO/IEC 14882) ignoring any TC’s and alike (useful C++0x FAQ here).

However, in parallel and generally under the radar, there has recently been publish a committee draft for the third edition of the C standard (ISO/IEC 9899). This should not really be a surprise, as my understanding is that all standards must be revised or retired every ten years (or thereabouts). But I still find that in the embedded community many people are unaware of the second edition (usually called C99, with the first edition being C90). The support for C99 features has been slow in coming; for example the release notes of the for recently released IAR v6.10 states:

The product now uses the current C standard defined in 1999, known as C99, as the default C language

It is also noteworthy the MISRA_C:2004 still uses C90 (okay C96 if you want to be pedantic) as it’s Rule 1.1 requirement.

So why hasn’t C99 been widely adopted? When asking the question of a someone I know very well, who has been involved in various commitees over the years, I thought I’d share his response :

In short:-

C90 was needed and it harmonised current compiler practice.

C99 then added a “wish list” of Good Ideas ™ that some people wanted because they were cool. (the ideas not the people 🙂 However the industry in general did not want the new features, many of which had not been thought through as regards implementation. So the compiler companies did not bother. Only adding things when enough people wanted them. E.g. // for comments.

C1* (formerly C0*) is more of the same. People adding Cool features that the industry is not crying out for and compiler vendors have not added. Though some “Cool Ideas” ™ have already been dropped. Fortunately.

I haven’t yet had time to trawl through the standard, but a couple of key changes that sprung out straight away are:

  • support for multiple threads of execution including an improved memory sequencing model, atomic objects, and thread-local storage
  • static assertions
  • support for bounds-checking interfaces (optional)

Once I’ve had opportunity to investigate these further I shall report back.

The product now uses the current C standard defined in 1999, known as C99, as the default C language
Posted in C/C++ Programming | 2 Comments

The Baker’s Dozen of Use Cases

RULE 7: Describe ALL the transactions

A use case, as the name implies, describes the usage of the system from the point of view of some beneficiary (our Actor). It is NOT (as I seem to spend my whole life telling people) is just the system function, organised as some sort of graphical ‘sub-routine’. This means the use case description must include the expected behaviour of the actors as well as the expected behaviour of the system.

This can sometimes appear counter-intuitive to use case newcomers. If the use cases define the functional behaviour of the system, then surely we can’t impose requirements on our users (the actors)?

In fact, this is not the case (and stop calling me Shirley).

The use case describes what we (or, more correctly, our customers) would like to happen when they use the system. It describes the typical interactions between stakeholder and system, such that the stakeholder achieves their goal. If the goal of the use case is beneficial to the stakeholder (see Rule 5) then the stakeholder has compelling reasons to behave as we describe in the use case. In other words, if the stakeholder wants the end result, they should comply with the behaviour described in the use case.

For example, if the system requests some information from the actor it is reasonable to expect them to respond with the information. In effect we are imposing requirements on the stakeholder (“when the system requests information, you shall respond”). Of course, there’s nothing to stop the obtuse user from not responding, walking away, or doing any number of other bizarre and inexplicable things; but these behaviours are a fantastic source of exceptional flows.  This approach moves the use case writer away from describing system functions and instead focuses them on the transactions between the stakeholder and the system.

The use case description defines the system behaviour as a sequence of atomic transactions between the actors and the system. Atomic is used in the sense of indivisible. This means that, in the context of the problem domain the transaction cannot be broken down into smaller transactions. (See also: Rule 9).  There are four basic transactions, and the use case description will be made up of sequences of these transactions:

  1. The actor supplies information to the system. Information could be an event (such as the trigger event) or data; or both.
  2. The system does some work. Remember to describe the results of the work, not how the result is achieved
  3. The system supplies information to the actor. Again, this could be requests for information, output signals, etc.
  4. The actor does some work. As mentioned above this is unenforceable, but reasonable behaviour on the part of the actor.

The fundamental transactions of a use case



Writing style

I suggest writing each transaction in a simple, semi-formal, declarative style. For transactions involving information exchange into or out of the system (that is, ‘Actor supplies information’; ‘The system supplies information to the actor’) I use the following style:

[Source] [Action] [Object] [Target]
For example: “The Navigator supplies the Airfield Altitude to the NAV/WAS system”

Source: The Navigator
Action: Supplies
Object: Airfield Altitude
Target: NAV/WAS System

For descriptions of work being done (either by the system or by the actor) I use the following form:

[Subject] [Action] [Object] [Constraint]

For example: “The ARS rewinds the hose at 5 ft/s +/- 0.5 ft/s”

Subject: The ARS
Action: Rewinds
Object: The Hose
Constraint: 5 ft/s +/-0.5 ft/s

If a transaction contains more than 3 punctuation marks it’s probably too complicated and should be restructured to make its meaning better understood.

Weak phrases
Weak phrases make for comfortable reading of a use case but are apt to cause uncertainty and leave room for multiple interpretations.

Use of phrases such as “adequate” and “as appropriate” indicate that what is required is either defined elsewhere or, worse, that the requirement is open to subjective interpretation. Phrases such as “but not limited to” and “as a minimum” suggest that the requirement hasn’t yet been fully defined.

Typical weak phrases include:

  • As applicable
  • As appropriate
  • But not limited to…
  • Effective
  • Normal
  • Timely
  • Minimize
  • Maximize
  • Rapid
  • User-friendly
  • Easy
  • Sufficient
  • Adequate
  • Quick

The truth is, in general engineers have poor writing skills. By providing a framework for how use cases should be written you are limiting the scope for ambiguity, wooliness and inconsistency.



<<Prev     Next>>

Posted in Design Issues | Tagged , , , , , | Leave a comment

Importing IAR EW 5.4 Projects into Parasoft C++test

Background

Recently I have been experimenting with Parasoft’s C++test tool for static analysis of C and C++ code. As part of this I went through the process of importing an existing C project developed in IAR’s Embedded Workbench toolset. Even though importing a project and checking it against MISRA-C isn’t too taxing, I though I would share my notes for doing this.

Continue reading

Posted in C/C++ Programming, Testing | Tagged , , , | Leave a comment

The Baker’s Dozen of Use Cases

RULE 6: If it’s not on the Context or Domain models, you can’t talk about it

(If you haven’t already read it, I’d suggest having a quick look over Part 1 of the Baker’s Dozen to familiarise yourself with the fundamentals of use case descriptions.)

Engineers love to solve problems. It’s what they do. A use case model though is not a design model – it’s an analysis model. Use cases describe what the system should do, and in what order. What use cases shouldn’t do is say how the system should achieve these things. That’s what design is for.

Stopping analysts (particularly if they’re developers) from writing implementation details in the use case descriptions is difficult.   One safe way of doing this is to limit the concepts written in the use case descriptions to only those defined on the Context or Domain models.

Both the Context model and Domain model describe things beyond the scope of software implementation. That is, they describe the problem domain, not the solution (software) domain.

The Context model defines the physical parts of the system – external systems, users, interfaces, communication channels, etc.

The Domain model describes the informational context of the system – what artefacts exist, are produced, are inputs or outputs; and how these elements relate to each other.

(See Rule 4 for more on these models; and more.)

All the data in these two models will exist irrespective of what software solution is developed. If they change then our understanding of the problem has changed.

When reviewing use cases look for concepts that are not defined on the Domain or Context models. These concepts are very likely to be implementation details. Look for items like ‘database’, ‘Hardware Abstraction Layer’, ‘Observer’, ‘RTOS’, etc. These are an indication your requirements are actually describing the solution rather than the problem.




<<Prev     Next>>

Posted in Design Issues, UML | Tagged , , , | Leave a comment