Welcome!

PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder, Java IoT, Industrial IoT, Microservices Expo, Agile Computing

PowerBuilder: Article

Make Your Design Ideas Speak: Using UML in PowerBuilder Projects

UML has become the de facto standard graphical notation for software projects

PowerBuilder Developer's Journal

A picture is worth a thousand words. We all have heard this saying a countless number of times. But what if you don't understand what is drawn in the picture? I was approached once with a request to review requirements specifications for some module. The document contained a scheme that represented the place of the module within the system. The picture was mainly made of rectangles and arrows. The rectangles had labels and I figured out that they represented other modules in the system. But I couldn't understand the meaning of the arrows. When I asked the author about them, the answer was "Well, they are just arrows." After a pause, "They show that there's some connection between the modules" was added.

Nowadays, the UML has become the de facto standard graphical notation for software projects. There are many books and training courses on the subject and everyone can become familiar with the notation quite quickly. On the other hand, UML is a huge language. Because of this, or for other reasons, it seems that it's not widely used in PowerBuilder projects. However, there's a way to use UML despite its complexity for the benefit of those who are involved in your PowerBuilder projects.

Which UML?
Martin Fowler, in his wonderful book UML Distilled, suggests that there are three ways of using UML: sketch, blueprint, and programming language. For me it's always been most important to communicate design ideas about the project no matter when it happens - before any actual programming takes place, during development, or after everything's been programmed. Hence I use the UML as a sketch to express those design ideas visually and (hopefully) clearer. The latter two ways is where the main complexity of UML lies, but with sketches you can use a very limited subset of the UML, which is easy to learn but still allows you to describe the key aspects of software design effectively, especially for the applications written with PowerBuilder. You will see, as we go further, that since we're not going to create a complete design description of our projects, literally a handful that are available in UML notations can be used for an effective and clear presentation of PowerBuilder application design.

What to Draw
When we describe how a software system is built and working, no matter how big it is - whether it's a comparatively small sub-module or a whole application - we are dealing with two aspects of its design: static and dynamic. The former one is about the structure of the system including both its internal structure and its external environment or neighborhood. It says which classes comprise the system and their relationships (the internal structure) and which classes that are not part of the system have relationships with the system (the neighborhood). It's called static because it does not change during runtime. The dynamic aspect of the system design is something completely opposite of this. It describes how the parts of the system interact with each other when the application is running, what happens inside the system during runtime, and how it works.

For the description of the static aspect of the system design, most of the time I use only two types of the UML Structure Diagrams: the Component and Class Diagrams. As for the dynamic aspect of design, I find the Sequence Diagram is used most often. Sometimes two other UML Behavior Diagrams, the Activity and State Machine Diagrams, are useful.

Component Diagram
It's often important to depict dependencies between different parts of the software system. It may be about how the module we are going to describe depends on other modules in the system and vice versa. In case the module being described has a complex structure, we may need to describe the dependencies between its sub-modules.

Probably, a short word is needed about what I mean by dependency here. I like using this term in the general sense that if a change in module A may lead to a change in module B, then module B is dependant on module A. In fast-growing systems, paying attention to dependencies is one of the key points of the creation of applications that are easier to maintain and extend - the fewer dependencies we have between the modules, the more resilient to changes inside each module the system is.

There are probably two main kinds of dependencies between modules that can be found in PowerBuilder applications. The first one is derived from the provided and required interface relationship between classes. The second one is based on data use: one module produces some data that are consumed by another module. Although dependency via data is often important, I rarely depict it in diagrams not going beyond mere text remarks. What I focus my attention on is the provided and required interface relationship between modules, and here the component diagram comes in handy. Although there are no explicit means in PowerBuilder to limit the visibility of class names of the module to classes from other modules and programmers can use whichever class they want, it's up to the designer to establish which classes should be used to call for the functionality that the module provides.

Let's have a look at Figure 1. The UML Component notation is used for depicting modules and sub-modules. The ball or lollipop represents the provided interface (the class that is to be used for accessing the module functionality). The socket represents the required interface - the class that is going to be used by other modules (here, Module B). In most cases, the names of the provided and required interfaces are the same, but they can be different if they belong to the same inheritance hierarchy and the required interface is more general (it's higher in the hierarchy) than the provided interface.

As a simple illustration of usage of the component diagram, a data-centric application can be taken. Suppose the module being described is responsible for entry of particular data. Let's call it Capturer. The module is accessed by opening one of its windows, w_capturer. If we want to draw this as the component diagram, it would look something like Figure 2.

If w_capturer expects parameters passed to it and the n_capt_parm object contains all the data needed by w_capturer, it may be drawn like the diagram shown in Figure 3.

However, n_capt_parms might as well be omitted. Whether to draw it or not depends on many factors such as the context of the diagram (e.g., if all windows in the system are opened with the same parameter's object, there's no need to draw it for each window), whether n_capt_parms contains only input parameters or is also used for output parameters (as for me, I omit the objects that are only used as input parameters more easily), whether drawing n_capt_parms makes the diagram too cluttered (we want to create as clear and readable diagrams as possible), and so on.

In the UML, only classes may be used as the provided and required interfaces. However, I use the notation with certain freedom; it happens that the access point for the module functionality is a global function and I draw it as the provided interface. If w_capturer is opened by other modules indirectly calling the global function f_capturer, it might be drawn as shown in Figure 4.

It's important to remember what kind of classes we draw on component diagrams - the classes that act as interfaces between modules.

Class Diagram
The UML Class Diagram is the main means for presenting the internal structure of the software system and is used more often than other types of diagrams. Quoting from Martin Fowler's book:

If someone were to come up to you in a dark alley and say, "Psst, wanna see a UML diagram?" that diagram would probably be a class diagram.

This type of the UML diagram offers a lot of notations, but I find that PowerBuilder applications can be described using just a few of them: class (with properties and methods), generalization, association, composition, and dependency.

Let's start with classes. To avoid ambiguity, I must remind you that the names we give objects in PowerBuilder painters can play two roles in most cases - they can be a class name and an object name. When we draw class diagrams, we always assume only the former role of object names despite referring to "object names." I'm following this traditional naming and use the terms "class name" and "object name" interchangeably where possible when speaking about class diagrams.

The general view of a class in the class diagram is shown in Figure 5.

The box with three compartments is a complete form of the class representation. The first one contains the class name (in the UML, it should be written starting with a capital, but I personally often don't do this). The second compartment contains instance variables, controls (visual objects), and non-visual objects inserted into the class. They are called attributes in the UML. The last compartment contains events and functions of the object. They are called methods in the UML. If the object has no methods, the third compartment can be skipped. If the object has no attributes but has methods, I draw the second compartment empty. If you don't want to present the class in detail on a particular diagram, you may draw just a box with the object name.

Although the UML has a special notation for attributes and methods, I use something in between this notation and the PowerBuilder declaration notation for variables, events, and functions. For attributes, its full form looks like this:

access name : datatype

For access, the following abbreviations are used: + for public, - for private, and # for protected. As in PowerBuilder notation, in case of arrays, the brackets and dimension follow the variable name.

The similar notation is used for events and functions:

access name( parameters ) : datatype

As you can see, I don't make any distinction between functions and events. It's easy to explain why. Usually the method names have prefixes - ue_ for events and of_ for functions -so it's clear from the first sight what is what. Although the standard events do not have a prefix, their names are well known, so no problems arise in this case either. Parameters are presented as the list of their datatypes (simple datatypes or class names) delimited by a comma. Datatype is specified if the method has a return value.

Now let's look at the example in Figure 6.

The custom DataWindow control dw_customer is presented. It has a protected instance double variable customer_id, the public function of_retrieve that accepts a double and returns a long, the public user event ue_save that returns a boolean, and a script written in the standard rowfocuschanged event.

Actually, this picture contains some unnecessary things. We know that events are always public, and most programming teams use prefixes for variables denoting their datatype. In reality I'd draw dw_customer as it's shown in Figure 7.

To depict that one object is inherited from another, use the generalization UML notation. Let's look at Figure 8.

It shows that dw_customer is inherited from a DataWindow. The rule of thumb for drawing the generalization notation is that the head of the arrow points at the ancestor.

There are two other ways of showing attributes that are objects: association and composition. The alternative ways of drawing this are shown in Figure 9.

On the left side, both in_parms, an instance variable of the n_capt_parms class, and dw_sheet, a DataWindow control placed on the window, are shown as attributes of w_capturer. On the right side, the same relationships are shown using the association notation for in_parms and the composition notation for dw_sheet. Note that the names of association and composition placed on the arrows are, in fact, the names of the attributes.

You may ask why in_parms is depicted using association and dw_sheet is depicted using composition. I won't discuss the theoretical difference between association and composition. This simple rule tells ypu when you should use what is considered ownership of the referenced object. If the object that contains the attribute object is the only one having a reference to it (the object owns the attribute exclusively), use the composition notation. Another rule that helps to identify composition is how and when the referenced object is created and destroyed. If the object creates the attribute (very often on its own creation) and destroys it on getting destroyed itself, use the composition notation. These two rules help identify compositions very easily. For example, use composition for all controls; although other object may have references to them, the object that contains them creates and destroys them. The same applies to the inserted non-visual object - use composition if you want to draw them separately from the owning class.

For all the other attributes use the association notation. The rule of thumb for drawing both notations is that the arrow head points to the object that is the class of the attribute. The label of the arrows is the name of the attribute.

The last (but not the least!) notation is dependency. Draw it for the objects that are used as local variables and arguments to methods. For example, if w_frame opens w_capturer in some of its scripts and does not store the reference to it in its instance variable, this relationship can be drawn as it's shown in Figure 10. The head of the arrow points to the object that is used by the other one.

Creating sketches is very subjective and this is especially true for class diagrams; it is the author who decides what needs to be drawn and what may be omitted. You want to create diagrams that are as clear and legible as possible but that still effectively communicate the design decisions. Even with this limited set of notations, quite wordy and cluttered diagrams may be created. For example, the fact that a window contains a DataWindow control is more accurately presented in Figure 11 (if you have any doubts about this, take a look at the script generated by PowerBuilder when you place a control on a window).

Do you need to show your design in such detail? It's up to you and it depends on many factors. You need to clearly understand what is the key point you want to emphasize and what is insignificant for the sketch detail (that may be more or less obvious in terms of realization if you discuss design of a future module or may be easily and quickly looked up in the code if you're dealing with the design description of an existing system). With this understanding, you'll be able to decide whether to use attributes or associations and compositions, whether to show all attributes and methods or only some of them, whether to show access for attributes and methods or not, and so on so forth.

Sequence Diagram
When trying to understand how a module works, probably the most important question for me has always been what the sequence is of an object methods calls. What object calls for what objects, which methods invoke which methods? It is why I believe that explaining this aspect of the module behavior is a crucial point in effectively communicating your design ideas. The UML offers a special kind of behavior diagram to show this - the Sequence Diagram.

If you are familiar with this type of UML diagram, you can guess that the most common notations I use describing PowerBuilder applications are objects (with their lifetimes and activation bars) and synchronous messages. A simple scenario where the DataWindow control is retrieved on the opening of its parent window is depicted in Figure 12.

The boxes represent the objects that are participants in the interaction within the scenario. The full notation for the object name is:

object name : Class name

It's often clear from the context which class the object belongs to, so I often omit class names. If the particular instance of the class is of no importance, the object name can be omitted; keep the colon and write only the class name. The vertical lines represent the object lifetimes and the bars indicate that the object gets the control flow. The arrows are synchronous messages. I use them for the events and functions whose calls are triggered (in contrast to those posted). The open event is shown using the found message notation. It means that the sender of this message is unknown or external in the sense that either the message is system-generated (as in the case of the open event) or the sender is out of the scope of the diagram. The first message on any sequence diagram is usually a found message and is the starting point of the scenario being described.

There's a special way to represent a self-call, shown in Figure 13. The ue_retrieve event is triggered to w_capturer from its open event script.

The ue_retrieve event script then calls the retrieve DataWindow function.

When the activation bar for ue_retrieve ends, the control flow goes back to open.

Sometimes it's important to show when objects get created and destroyed. There's also the possibility of showing a return value from a call. If the system has an object responsible for fetching different options for the modules, and w_capturer needs to get its particular options in the form of another object, it could be drawn as shown in Figure 14.

Most of the time I don't draw return calls, using it mainly for showing the correspondence between the returned object and the one that receives message calls. As you can see, ln_capt_options is the one created by of_get_capt_options and then used and destroyed in the open event script.

The last thing about drawing sequence diagrams is showing methods that are posted. I use the asynchronous call along with found message UML notations, although the PowerBuilder posted methods are not precisely what is meant by asynchronous calls in the UML. If the ue_retrieve event is posted and I am to draw it all in one diagram, the result would be similar to Figure 15.

It's clear from the diagram that after posting of ue_retrieve, execution of the open event script is not interrupted. It's also clear that ue_retrieve starts executing only after open has finished its work. From the notation point of view, the difference between the synchronous and asynchronous calls is in the arrowhead.

As is the case with class diagrams, it's easy to create cluttered, difficult-to-read diagrams by drawing every possible detail. It's important to stay focused on the key points of the interaction you are describing.

Other Behavior Diagrams
Apart from sequence diagrams, I sometimes use the State Machine Diagram and Activity Diagram. Activity diagrams are helpful if you want to describe a complex logic or workflow. State machine diagrams help you to show the states of the object and the transitions between them. There's nothing specific in using these types of diagrams for PowerBuilder applications. You may find information on the available notations in these diagrams in any book on the UML.

This May Not Be Enough
As you can see, despite the fact that the presented subset of the UML is quite small, it's capable of describing the design of PowerBuilder applications in most cases. However, it's possible that you will find it too limited in your particular case. For example, you may want to show dependencies between sub-modules that are derived from inheritance, or to show loops and conditional executions on sequence diagrams, etc. Although I find it sufficient in most cases to place a remark either in the text or directly in the diagram, nothing keeps you from going beyond the presented subset and using other notations and diagrams available in the UML.

Tools and Resources
There are many books on the UML available. As an introduction to the topic, I highly recommend Martin Fowler's book UML Distilled. As for the tools for the creation of UML diagrams, there are plenty of them on the market with the whole range of functionality from simple drawing to code generation. In using the UML as a sketch, I find MS Visio tool quite handy. I don't use its standard stencil and palette for the UML though. The package designed by Pavel Hruby is much more convenient for me. You may download it free of charge.

More Stories By Konstantin Goldobin

Konstantin Goldobin is a senior developer living in Voronezh, Russia. He has been working with PowerBuilder since 1995 version 4.0. Visit his web site at www.vsi.ru/~kgold.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.