Previous Page Next Page

Chapter 12
APPLICATION DEVELOPMENT: CASE STUDY

This chapter gives you a snapshot of the Smalltalk/V big picture.

We'll take a case study approach. A case of real world people, not whiz Smalltalk programmers. This chapter is intended for non-programmers, people with something they want their computers to help them do.

The Case Study: A State-Transition Perspective

Our case involves the prototype development of an office automation system, a sales communication application. In the general scheme of things, the case study is an analysis involving state-transition models where physical objects pass through a series of states according to a network of connections between the states.

The connections between states reflect the logical constraints and preconditions which order the transition from one state to another. The tokens which pass from node to node along the constraint network are objects experiencing the state changes. Objects going through state changes is a subject of broad interest. The objects might be:

State-transition models relevant to these objects include, respectively:

Smalltalk/V is ideal for developing applications based on state-transition and other highly graphical and data intensive models. Its screen graphics and rich data abstracting capabilities allow you to produce working prototypes of complex models in record time.

Our case study shows how some self-starters in an optical disk drive sales office develop a Smalltalk/V application to track and facilitate their sales communications. Their state-transition network--though they didn't know or care to call it that--is a flowchart of their company¡s approved sales strategy. The tokens coursing through this sales strategy network are their potential customers.

The Case Study Problem as a Smalltalk/V Problem

Where to begin? The Whizzard WORMS reps knew they had a sales communication problem. They knew they wanted to develop a Smalltalk/V application to facilitate these communications consistent with corporate marketing strategy. They had a sense of what the application interface would be like--inspired by things they'd seen and code they already had on hand. A lunchtime, napkin-based brainstorming session captured the problem.

On the first napkin they drafted a preliminary objective, their problem statement:

To develop a Sales Communication application (SalesCom) that will allow a rep to sit down to an interactive display where he or she will quickly and easily see what communication events are required for the day and see what the current load of customers is for each of the steps in the sales strategy. Further, the prototype version will print letters on a case by case basis and will facilitate making telephone follow-up calls. The prototype application will be built as much as possible from reusable code taken from the Smalltalk/V tutorial examples and system source files.

Looking over the rep developers' shoulders with the eyes of a generalist, the problem statement can be restated:

To develop a Smalltalk/V application using state-transition models to manage the movement of objects through a process. This application will have a multi-pane main window where a database of tokens moving through the process can be singled out for state inspection and manipulation. The application keeps a token state change event schedule. When moving a token through the process, the application prompts the user for preconditions or the result of state transitions where the network exhibits multiple alternate branches.

The reps, as far as WORM disk sales are concerned, see a world of "us" and "them." Inside are the Whizzard reps, and outside, a sea of current and potential customers. The rep's job consists of acting as an agent for Whizzard through a series of communication events with a customer which hopefully lead to a sale.

They sketched a diagram of their customer prospecting strategy as shown in Figure 12.1. It was a simple marketing strategy which involved a direct mail campaign, followed by a telephone contact with an attempt to get interested folks to attend a sales seminar.

Figure 12.1
SalesCom Sales Strategy

A Window for the SalesCom Application

The reps next sketched a rough picture of the ideal SalesCom application window as in Figure 12.2. Their objective was to take inspiration from the various tutorial examples and system features to formalize their vision of the proposed application.

Figure 12.2
Sketch of the SalesCom Window

There were two purposes for the display as far as they could see:

The first requirement suggested the ListPane and TextPane views in the SalesCom application window, the Master Customer List pane and Customer Detail text pane. The inspiration was the Smalltalk/V browsers where a clicked selection in a scrolling ListPane initiates a look-up of some associated detail information: the source code for a method in a Class Browser, for instance.

The second requirement begged for graphic representation based on an extension of the tutorial Network of Nodes example. The "hard" part of taking a network data structure and giving it a visual representation is done already. The reps needed only to give the nodes more representative names and new screen coordinates to transform the random network of Figure 9.3 to that of Figure 12.1.

The GraphPane of the SalesCom application (inspired by the animation pane of the Animal Habitat tutorial example) facilitates the salesperson's visualization of the communication process and the flow of customers through the sales cycle. Numbers appended to the label of each communication event node indicate the total number of customers currently pooled at that step in the strategy as well as the year-to-date total of customers having passed through the event node.

Menus Enrich the Window

The reps next addressed what the application would have to do to move customers through the marketing strategy. What "messages" would the user rep want to send to the SalesCom application object to control preparing letters and prompting phone calls?

They gravitated toward brainstorming about the menus of each of the SalesCom application subpanes. They found a pad of removable self-stick notes was useful for laying hypothetical menus along the menu bar. After much debate, the reps decided on the configuration in Figure 12.3.

Figure 12.3
Menus Enrich the SalesCom Window

The reps were excited. They finished lunch with a clear sense of direction on their development project. They were ready to start writing code.

Survival Tip #1: Don't over-plan. Yes, you need a decent statement of your problem and some sense of what the application's primary interface will look like. But you don't have to have all the answers to get going. To determine when to start, ask yourself, "If I write as much code as it takes to get a prototype to look and behave like the design so far, would it do anything interesting and useful?" When your answer is affirmative, go to it. Smalltalk/V is designed to work with you in an evolving, incremental process.

As they prepared to begin development, the reps took a couple of minutes to draft a list of the classes involved in the SalesCom application:

Getting There in Half the Time: Recycling Code

The reps set to work on a kind of scavenger hunt for reusable code to get the SalesCom application up and running as soon as possible. You can re-create their exploratory process by using the File menu Open item to bring up a window on the chapter.12 tutorial file.

As you do more Smalltalk/V programming you will see that you reuse code in two basic ways:

You will use both methods in creating the SalesCom application, starting with the inheritance approach, by creating SalesCom as a new subclass of ViewManager and ComEvent as a subclass of the NetworkNode class. You will then go on a copy and paste "raid" on the AnimalHabitatWindow class to borrow the basic window design for the three pane SalesCom application window.

If you have not done the tutorial examples in Chapters 6, 7, 9 and 10 and/or have not saved the image along the way, you should add the following classes by evaluating:

Object subclass: #NetworkNode
instanceVariableNames:
'name position'
classVariableNames: ' '
   poolDictionaries: 'WinConstants '

Then select and evaluate:

Object subclass: #Network
instanceVariableNames:
'connections'
classVariableNames: ' '
   poolDictionaries: ' '

then evaluate:

Object subclass: #AnimalHabitat
instanceVariableNames:
'animals scriptString script browser' 
classVariableNames: ' '
   poolDictionaries: ' '

and finally evaluate:

ViewManager subclass: #AnimalHabitatWindow
instanceVariableNames:
'habitat replyStream inputPane'
classVariableNames: ' '
   poolDictionaries: ' '

Then select and evaluate the following to file in the relevant methods for these four classes. This is to give you a starting point equivalent to where the sales reps started.

(File pathName: 'tutorial\network9.st') fileIn; close.  
(File pathName: 'tutorial\nodes9.st') fileIn; close.  
(File pathName: 'tutorial\class10.st') fileIn; close.   
(File pathName: 'tutorial\animal10.st') fileIn; close.  
(File pathName: 'tutorial\window4.st') fileIn; close.  
(File pathName: 'tutorial\window5.st') fileIn; close.

Update the class list pane of the Class Hierarchy Browser.

Re-working the Network of Nodes

The starting point of the Network of Nodes example can be seen in Figure 9.2.

As a first step, create a new pool dictionary, SalesStrategy, to hold objects that will be global to your new application. Initially you create two new pool variables: StratNet to hold the sales strategy network, and StratNodes to hold the nodes used in the sales strategy network. Evaluate the following:

SalesStrategy:= Dictionary new.
SalesStrategy
at: 'StratNet' put: Network new initialize; 
   at: 'StratNodes' put: Dictionary new

The network node of the SalesCom marketing strategy diagram requires a richer data structure than the simple name and position instance variables defined for the path computation and graphic display examples from earlier tutorial chapters. So you will create a ComEvent subclass of NetworkNode. In addition to a couple of new methods, a ComEvent has an info instance variable which is initialized as a Dictionary object. Info will be used to store information about the body of the letter or phone call script, the delay before the next event and a pointer to the next most likely event, etc. Select and evaluate:

(File pathName: 'tutorial\comevent.cls') fileIn; close 

You will be using the pool variables StratNet and StratNodes to build a sales strategy network. StratNet and its nodes are given new names, positions and connections which transform the prior random network graphic example into the structured diagram of the SalesCom marketing strategy. Evaluate the following to see the transformation:

#(('Kick-offLtr'   180 20) 
('Fol-Up Ltr'   180 120) 
('Phone Call'   180 180) 
('Wake Up Ltr'   295 180) 
('Exit Seminar'   57 240) 
('Exit Dead Leads'   280 240) 
do: [ :nodeInfo  |
ComEvent new initialize;
name: (nodeInfo at: 1) position: 
(nodeInfo at: 2) @ (nodeInfo at: 3) ] .
(SalesStrategy at: 'StratNet') initialize.
ComEvent
connect: 'Kick-off Ltr'   to: 'Fol-Up Ltr';
connect: 'Kick-off Ltr'   to: 'Exit Seminar';
connect: 'Fol-Up Ltr'   to: 'Phone Call';
connect: 'Fol-Up Ltr'   to: 'Exit Seminar';
connect: 'Phone Call'   to: 'Wake Up Ltr';
connect: 'Phone Call'   to: 'Exit Seminar';
   connect: 'Phone Call'   to: 'Exit Dead Leads'. 

To see what the sales strategy net looks like, evaluate the following:

(SalesStrategy at: 'StratNet') draw.

Your screen should look like Figure 12.4.

The current Network class draw method is "hardwired" to draw the sales strategy diagram in a single pane, turtle graphics window. What is needed is to draw the network so it can be displayed within a pane of a more elaborate window. You need to edit the draw method in class Network to produce an additional method drawOn: for the network. You can either directly edit this method using the Class Hierarchy Browser as indicated below (note the ** changed ** lines) or copy the method from the file chapter.12 and paste it over the new method template and then save the edited or pasted-in new version.

Figure 12.4
SalesCom Network Screen

The method drawOn: for class Network is:

drawOn: aWindow   "** changed **" 
"Draw the network.  For each node, it draws 
all the arcs and then the node.  All the nodes 
visited are remembered to avoid double drawing."
| visited pen |
pen := aWindow pen.   "** changed **" 
pen erase.
visited := Set new. 
pen drawRetainPicture:
connections keys do: [ :nodeA |
visited add: nodeA.
(connections at: nodeA) do: [ :nodeB| 
(visited includes: nodeB)
ifFalse: [
pen place: nodeA position; 
goto: nodeB position] ]

nodeA drawWith: pen] ] "** changed **"

This drawOn: method is more "generic" than the original draw method as it allows you to pass, as an argument, the window in which the network will be drawn. This revision of the draw method is particularly suited to use as the method name argument in a when:perform: specification in a window's open or openOn: method. Note, too, that the last line has been edited to specify that the pen to be used in the node drawWith: call is the pen of the window passed as the input argument to the network drawOn: method.

The draw method in Network could now be changed to use the new drawOn: methods, but we leave this as an exercise for you. (Hint: it can be done in a single line.)

To test the new method, evaluate the following:

| graphPane |
graphPane := GraphPane openWindow: 'StratNet'.   
(SalesStrategy at: 'StratNet') drawOn: graphPane 

That's it. You have roughed out one of the two main components of the visual presentation of the SalesCom application.

Take a moment to inspect the ComEvent class. Although the Net drawing of ComEvent nodes is visually similar to the random network tutorial example, notice the impact of the initialize and name:position: methods. While a ComEvent can be drawn by the same code that draws the original NetworkNode of the network tutorial example, a ComEvent has a much richer data structure:

initialize
"Initialize the dictionary data record of information about the 
communication event to be empty."
active := false.
info := Dictionary new.
info
at: '1.Strategy' put: 'NYS';          "not yet specified"  
at: '2.Type' put: 'L, P or F ';
at: '3.Message' put: 'Type your message here.'; 
at: '4.Next Step' put: 'NYS';
at: '5.Days Till NS' put: 'NYS';
at: '6.MTD' put: 0;
      at: '7.YTD' put: 0
name: aString position: aPoint
"Set the receiver's name and position." 
super
name: aString
position: aPoint x @ (aPoint y) truncated.  
   StratNodes at: aString put: self 

The next step is to integrate this graphic network display into the multi-pane window you are about to create with code copied from the Animal Habitat tutorial example. Divide and conquer. That's a big part of Smalltalk/V programming strategy.

Raiding the Animal Habitat

Before you can "borrow" some code, you need someplace to put it. While you can expect to call on many existing classes in the course of your Smalltalk/V development projects, you can pretty much count on adding a new class for the application's main window. This is the class which defines the user interface of your application.

To run your "program," you create a new instance of your application window class, then interact with it. In this case, evaluate the following to create the new SalesCom class as a subclass of ViewManager:

ViewManager subclass: #SalesCom 
instanceVariableNames: ' '
classVariableNames: ' '
   poolDictionaries: 'SalesStrategy'

The first and most important method in the SalesCom application is open which describes the window appearance. This method also associates a collection of methods with each of the panes. These methods are triggered as needed when the window or any of its subpanes are created or changed. These event reactions are specified in the when:perform: lines in your window opening method.

You will get much of the code detail and the overall method structure from the openOn: method of the AnimalHabitatWindow class. Use a Class Hierarchy Browser to locate the method, select all of the method's source code and copy it to the clipboard.

Return to the currently empty SalesCom class and add your first method by choosing New Method from the Methods menu. Select the entire default method template and choose Paste from the Edit menu. Change the method selector from openOn: anAnimalHabitat to open. The method source text pane should look like the code at the top of the next page upon the conclusion of this operation:

open
"Create a single pane window with the script 
of anAnimalHabitat as its initial contents."
habitat := anAnimalHabitat. 
self label: 'K E N N E L'.
self addSubpane:
(replyStream := TextPane new 
owner: self;
when: #getContents perform: #reply: ; 
framingRatio: (Rectangle leftTopUnit 
extentFromLeftTop: 2/3 @ (1/4) ) ). 
self addSubpane:
(AnimationPane new
owner: self;
when: #getContents perform: #pictures: ;
framingRatio: (Rectangle leftBottomUnit 
extentFromLeftBottom: 2/3 @ (3/4))). 
self addSubpane:
(inputPane := TextPane new
owner: self.,
when: #getMenu perform: #inputMenu: ;
when: #getContents perform #input: ; 
framingRatio: ((Rectangle leftTopUnit rightAndDown: (2/3 @ 0) )
extentFromLeftTop: 1/3 @ 1)).
   self openWindow

Choose Save from the File menu and you will get an "undefined" message explaining that the SalesCom class does not have the instance variable anAnimalHabitat defined (nor does it have habitat, replyStream or inputPane defined).

What a dilemma. You can't save the method without discarding the changes which, in this case, means losing the entire new method.

Survival Tip #2: When you are on cut and paste "raids" of existing methods, put the source method's class instance variable name(s) into the temporary variable declaration of the new method in your new class. You can then save the method and decide later whether your new class definition needs to be changed to incorporate the source's instance variables or whether you leave the temporary declarations.

Insert habitat, anAnimalHabitat, replyStream and inputPane into a new temporary variable declaration as follows:

| habitat anAnimalHabitat replyStream inputPane |

And Save again. This time it works. But you want a SalesCom window to open on a marketing network, not on a habitat. Edit the comment to reflect your design goal. You also determine that you won't be needing a temporary or instance variable called habitat, so delete habitat and anAnimalHabitat from the temporary declaration. Also delete the first statement setting habitat to the original input argument anAnimalHabitat.

Save the open method again. In resolving replyStream, which you added to the temporary declaration, you decide that it should be an instance variable. So click on SalesCom in the Classes list pane and add replyStream to the instanceVariableNames: declaration. Select Save to recompile the class. You will get an error because a temporary variable (in the open method) has the same name as an instance variable.

Return to the open method source code. With replyStream now declared as an instance variable, delete it from the temporary variable declaration. Next, edit the label: argument to reflect that this is a SalesCom window and not a Kennel. Finally, you know the drawing of the network is graphical, but does not involve the extra features of an AnimationPane, so change the second subpane declaration to a GraphPane and its getContents event selector to picture:. Save the now fully edited source code for the open method.

The SalesCom window opening method now looks like:

open
"Create a SalesCom window with a Network  
as its marketing strategy."
| inputPane |
self label: 'SalesCom'.
self addSubpane:
(replyStream := TextPane new 
owner: self;
when: #getContents perform: #reply: ;
framingRatio: (Rectangle leftTopUnit 
extentFromLeftTop: 1/3 @ (3/4) ) ). 
self addSubpane:
(GraphPane new
owner: self;
when: #getContents perform: #picture: ;
framingRatio: (Rectangle leftBottomUnit
extentFromLeftBottom: 2/3 @ (3/4))). 
self addSubpane:
(inputPane := TextPane new
owner: self;
when: #getMenu perform: #inputMenu: ;
when: #getContents perform: #input: ; 
framingRatio: ((Rectangle leftTopUnit rightAndDown: (2/3 @ 0) )
extentFromLeftTop: 1/3 @ 1) ).
      self openWindow

Use the same procedure to copy method initWindowSize from AnimalHabitatWindow to class SalesCom and save it.

SalesCom is shaping up. But will the window work yet? Evaluate:

Test := SalesCom new.
Test open

and click Yes to define Test as a global variable.

A Walkback window informs you that the SalesCom object, Test, does not understand inputMenu:. Close the Walkback and go back to AnimalHabitatWindow to copy the inputMenu: method and paste it in as a new method in the SalesCom class. Save it. It can be saved without modification, though a SalesCom object will not understand if you ask it to perform any of its menu selections related to the Animal Habitat application. The reps brought in inputMenu: to get the SalesCom prototype window running as soon as possible. They later used this method as a template to create a menu for each of the SalesCom window subpanes as required by their prototype design.

Next evaluate:

Test open

No big deal; another Walkback. A little more careful inspection of open reveals the need to copy the reply: method from AnimalHabitatWindow into SalesCom. Also, you figure that you may get some inspiration by reworking pictures: into picture: rather than starting this method from scratch. After pasting it into SalesCom, pictures: will look like this:

pictures: animationPane
"Initialize animation pane objects." 
animationPane contents: (
      habitat animals collect: [:animal | animal picture] )

Before saving, notice that the code relates to animals and not to your application. First edit the comment to say what you really want this method to accomplish. Then edit the code to do what is necessary. You can always leave the code incomplete and the comment will serve as a guide to finish it later. In this case, the actual implementation is very simple:

picture: graphPane
"Draw the network in graphPane."
   StratNet drawOn: graphPane

Survival Tip #3: When re-working a copied method, edit the "comment" first to make it reflect the changes you will be making. Let the edits you make in the comment direct you to lines in the code which implement that aspect of the method responsible for the behavior referred to in the comment. This technique can be so useful that you will develop an appreciation for and will, hopefully, write clear and complete comments. They aren't "training wheels." Comments are an integral part of the communication among the Smalltalk/V community of programmers.

Turning pictures: into picture: might seem like wasted effort since none of the code from the AnimalHabitatWindow method was useful. But it is often helpful during your initial development efforts to copy a method which is similar to what you know you need. Going from something to something else is often easier than going from nothing to something. Eventually you will feel comfortable writing new methods from scratch and you can avoid this extra "inspirational" step.

Next copy the input: method from AnimalHabitatWindow to SalesCom. Before saving it will look like this:

input: aPane
"Initialize inputPane with the string stored in the 
script of the owning window's associated habitat."
   aPane contents: habitat scriptString

You can see that this method accesses the content of scriptString, an instance variable of the AnimalHabitat stored in the window's habitat variable. And since you already decided that SalesCom objects have nothing to do with AnimalHabitats, you know this method won't work as it stands. So to "hardwire" a consistent response from this method until you decide what the SalesCom version of input: will need to do, change the method to read:

input: inputPane
"Initialize inputPane with a temporary input string." 
   inputPane contents: 'This is a test.'

and Save the method.

Survival Tip #4: Simplified, interim versions of methods are an excellent way to "divide and conquer" a Smalltalk/V programming problem. Most often this involves writing an expression that produces a specific instance of the kind of object which will result from the more complex computation that a method is planned to perform. This is especially useful for separating development progress on the interface from progress on the internal manipulations of the involved data structures.

Now select and evaluate:

Test := SalesCom new.
Test open

You've done it. You have the first incarnation of a recognizable SalesCom object as seen in Figure 12.5. The pizzaz of the strategy network GraphPane hints at the developing interface. The window resembles but certainly isn't an animal habitat anymore. The two TextPanes are the targets of the next phase of your SalesCom prototype development project.

Figure 12.5
SalesCom Window Phase One

Customers and Events: A Matter of State

The reps realized they were on track now. They saw two areas of SalesCom that needed attention:

You incorporate many traditional database management operations into the SalesCom application simply by making the global variable Customers a new Dictionary object. The dictionary keys will be the customer company names. The value associated with each company is an array, its elements the 'fields' in the customer 'database.' A comment identifies each element in the first case entry. Select and evaluate:

Customers:=Dictionary new.
Customers
at: 'ABC Inc.' put: # (   "Key is company name" 
'Fred Smith'   "Field 1 is Contact Name."
'123 Maple St.'   "Field 2 is Address."
'Boston MA 02055'   "Field 3 is City State and Zip"
'555-4321'   "Field 4 is Phone."
'Kick-off Ltr'   "Field 5 is Current Event scheduled."
'Feb 14, 1980'   "Field 6 is Prep Date forCurrent Event."
( ));   "Field 7 is an array for the contact history." 
at: 'DEF Co.' put: #('Jane Doe' '321 Poplar Terr.'
'Hicksville MD 21202' '555-3476' 'Fol-Up Ltr''Feb 15, 1980' 
('Kick-off Ltr: Feb 7, 1980'));
at: 'GHI Ltd.' put: #('Clive Davies' '999 Oak Ave.'  
'Tustin CA 92680' '555-7890' 'Kick-off Ltr' 'Feb 14, 1980'
( ));
at: 'JKL Inc.' put: #('Bert Jenks' '667 Sycamore St.' 
'Irvine CA 92600' '555-4734' 'Kick-off Ltr' 'Feb 14, 1980'
( ));
at: 'MNO Co.' put: #('Bill Rasp' '345 Apple Ave.' 
'New Vista CA 93232' '555-5678' 'Fol-Up Ltr' 'Feb 20, 1980' 
('Kick-off Ltr: Feb 6, 1980'));
at: 'PQR Corp.'put: #('Ellie Small' '423 Sassafras Ave.'  
'Tustin CA 92680' '555-2064' 'Phone Call' 'Feb 20, l980' 
      ('Kick-off Ltr: Feb 1, 1980' 'Fol-up Ltr: Feb 8, 1980'))

To see the mini-database which you just created, evaluate:

Customers inspect

or simply double click on the word 'Customers' and select Inspect it from the Smalltalk menu. To inspect a customer--to review and modify the fields in a customer's "record"--select a customer name in the left hand list pane of the Customers Dictionary Inspector. Pull down the Inspect menu and select the Inspect item to pop up an Inspector on the selected customer, or more simply, double-click on the name in the customer pane to automatically open an Inspector on the selected company. Each element, or field, of the customer record is a selectable line in the new Inspector list pane. Remember to select Save (from the File menu) for the TextPane whenever you make field changes that you want to keep.

To explore the many things you can do with Customers, turn to the Dictionary class entry in the Smalltalk/V Encyclopedia of Classes, towards the rear of this manual . Try "talking" to the Customers Dictionary to explore its database-like behaviors.

The reps used the Encyclopedia of Classes like a foreign language phrase book throughout the development of SalesCom. The reps got the customers to jump through hoops with keysDo:, includes:, occurrencesOf: and at:put: messages. Check it out. Flip to the Encyclopedia and explore the things you can do to Customers.

Survival tip #5.- Study and understand the format of a class entry in the Encyclopedia of Classes. And learn to actively use the Methods Index to direct your cross-referencing exploration of the behavior of the many classes which make up the Smalltalk/V environment.

With customer objects in hand, the reps turned their attention to the communication events.

The reps used the same basic object inspection technique to fill in the required information in each of the ComEvent network strategy nodes. This included typing in the body of the letters and phone call scripts that will eventually be merged with customer information. To save you time, evaluate:

(File pathName: 'tutorial\comevents.in') fileIn; close

To view the new data contained in the ComEvent nodes, select and evaluate:

(SalesStrategy at: 'StratNodes') inspect

Open an Inspector on one of the nodes. All these data management and multi-window editing features of Smalltalk/V Dictionaries are already a part of the capabilities of the SalesCom application. The reps realized this was as sophisticated a data management facility as they needed for the prototype.

SalesCom consists now of two databases, Customers and StratNodes, a network of ComEvents. It will be up to new and original methods to manage these objects' interaction and updating. You will do that by enhancing the behavior of the multi-pane SalesCom window.

Methods and Messages: Bringing the Prototype to Life

The reps' next objective was to get each TextPane working with the Customers Dictionary. The inspiration was the browser type of window, so they poked around relevant methods, especially open, in the browser classes and determined that they needed one pane to be converted to a ListBox. Selections in the ListBox would then trigger a method for the remaining TextPane to display the data record for the selected customer.

The reps edited open to reflect the following changes:

To see the many changes that the reps made to SalesCom during this next phase of prototype development, evaluate:

Test := nil.
(File pathName: 'tutorial\class12.2in') fileIn; close.  
Test:= SalesCom new open

You may get a Walkback saying has instances.

Survival Tip #6: Finding lost instances is a skill you will need occasionally during initial application development. If you have instances of a class that you cannot find, they are probably in some global variable. This usually happens when you are debugging a new window. Remove these instances by executing the expression:

Notifier reinitialize

All open windows close and the Transcript window reappears.

SalesCom's basic behavior is evolving. Note the reps are using a "divide and conquer" approach to bring the prototype up in stages with the interface taking the lead. The customers: method returns a typical list of customer names and viewCust: simply clears the Customer Detail pane and displays a few lines of sample text.

Once they got the synchronization between panes and the stream to the Customer Detail pane working, they "attached" the Customers Dictionary to the SalesCom application by a quick rework to the customers: method:

customers: customerPane
"Set the contents of the customer pane to the keys
of the Customers dictionary as a Sorted Collection."
   customerPane contents: Customers keys asSortedCollection

And an enhancement of viewCust: was all that was needed to bring the Customers Dictionary "on-line":

viewCust: aCust
"When the Customer List pane is selected, the Customer 
Detail pane is updated to show the currently selected customer. 
| custData custHist prepDate |
curCust := aCust. 
custData := Customers at: curCust. 
custDetInfo := WriteStream on: String new.  
1 to: custData size - 1 do: [ :index | "Don't print the history array."
custDetInfo
nextPutAll:  (custData at: index);  
cr.].
custHist := custdata at: 7.  "Print the history line by line after a header." 
custDetInfo nextPutAll: '----- HISTORY -----'; cr.  
1 to: custHist size do: [ :index |
custDetInfo
nextPutAll: (custHist at: index);  
cr].
   self changed: #custDet: 

You can edit the methods to reflect these changes or paste them in from the tutorial chapter.12 file. Once these two methods are changed, you have reached another plateau in the SalesCom prototype development project. Both the customers and communication events databases are up and accessible interactively in the SalesCom window as in Figure 12.6. Evaluate the expression SalesCom new open to see it.

Figure 12.6
SalesCom Window Phase Two

Menu selections foreshadow but don't yet deliver the full SalesCom environment. Menu selections result in message not understood Walkbacks. The rest of the prototype development consisted of writing small methods to perform the actions requested by each of the menu items.

It's Getting Better All the Time: Evolutionary Development

The reps were on a roll. Every method they wrote gave them new insights and ideas for the next. They found that Smalltalk/V lent itself to "team development" as they took turns, one on the keyboard, the other scouring the manual. By experience, they came up with another tip.

Survival Tip #7: Keep moving. Write the methods that "jump out at you" and practically write themselves. If you get stuck on a method, put its body in comment quotes and save it. Then go on to the next method you need to write. Something you pick up solving another method's implementation or sometimes just some "creative gestation" will bring you back to unfinished methods. Eventually the toughest methods seem to give way when they are the only thing standing between you and your application running.

To see what the reps were able to accomplish with SalesCom on their first Smalltalk/V development project, evaluate:

(File pathName:'tutorial\class12.3in') fileIn; close.   
SalesCom new open

While they have a long wish list, the reps now had a prototype that met their original SalesCom development objective, shown in Figure 12.7. With the pop-up mail merge and phone call script windows, SalesCom was a lot more sophisticated a program than the reps ever thought they could have written in such a short time.

Figure 12.7
The Full SalesCom Prototype

Spend a few minutes taking SalesCom on a shake-down cruise. Add a customer and update somebody's contact information. Print a few letters. Make a phone call or two. Push that initial bunch of prospects through a hypothetical sales campaign. Sell a couple of WORMS. Lose a couple to the Dead Leads bin.

Notice how the node highlighting pinpoints the position of the selected customer in the marketing campaign. Track how printing a letter or making a call updates both the customer and communication event records.

To see what makes SalesCom tick, poke around the methods which you have just filed in. Note that while a method like viewCust: now looks complex with all the data handling that has found its way in to support the additional interface features, viewCust: became complex in stages. The reps wrote simple methods that became more sophisticated a line or two at a time.

For the record, over the course of the prototype development project, the reps were able to get all the behavior you see exhibited in SalesCom by:

The reps began using SalesCom the day after they finished the prototype. They had a long list of anticipated changes but they found that use helped focus their subsequent development. Rather than add features that they thought would be useful, they wrote those that daily use convinced them they needed.

Where to Go from Here

Like many Smalltalk/V applications, SalesCom begs extension. While the prototype was fully functional and positively impacted the reps sales performance, over the next few months they intend to do the following:

To take SalesCom to an even higher level of sophistication, the reps (or you) might consider an extension into the realm of discrete event simulation. Use the multi-tasking capabilities provided by the Process and Semaphore classes of Smalltalk/V to add an Event Driven Simulation component to SalesCom. Such an extension would take the SalesCom databases' current states and use what it knows about response tendencies to generate simulation data to evaluate the future impact of current marketing decisions.

As you can see, the potential of SalesCom is great and will be reached by a process of evolutionary development--from prototype to bigger and better. With Smalltalk/V the limits are those of your imagination and the time and energy you have for development.

What You've Now Learned

In this chapter, we introduced the Smalltalk/V application development cycle. In this chapter, we've shared a number of tips to help speed your application development:

Keep these tips in mind as you tackle your first Smalltalk/V programming project. The remaining three sections of this manual are provided as reference tools. Part 3 of this manual covers in greater detail all the material explored in these tutorials

If you want to review any of the topics covered in this tutorial, you can repeat the corresponding section of the tutorial or refer to the detailed description in Part 3.

Previous Page Next Page