Newsletters Subscriptions Media Kit About Us Contact Search Home

Stuff
OS/400 Edition
Volume 2, Number 19 -- September 25, 2003

Service Programs with a Smile


by Joel R. Cochran

So you've finally turned that old subroutine into a subprocedure (you know, the one that was copied into every piece of code your shop ever wrote) and have compiled that subprocedure into its own free-standing *MODULE object. You've replaced all the EXSR op codes with calls to your new subprocedure, and you've recreated all the programs and bound the new *MODULE to each one. All seems sweet in ILE-land, until you encounter the first bug in your subprocedure and the maintenance problems that entails. But fear not, that's why IBM gave us service programs.

Serving Modules a la Carte

The process I have just outlined is what I call the a la carte approach, because you pick and choose which modules to include every time you create a program. Let's assume you created your program by using a command like this:

CRTPGM PGM(MYLIB/MYPGM) 
   MODULE(MYLIB/ENTRYMOD MYLIB/PROC1)

This simple version of the Create Program (CRTPGM) command creates a program in MYLIB called MYPGM, where PROC1 is the new subprocedure. Since this subprocedure replaced a subroutine that is used globally, let's further assume that you repeated this procedure several hundred times. You have now bound your single module to all of your programs. Good for you. ILE, here you come! Unfortunately, your celebration is cut short when you realize there is a bug in PROC1. The good news is that only the logic needs to be changed and not the parameter list (which I'll discuss later). So you change the source member and recompile the *MODULE object, and what have you fixed? Nothing. To effect any changes, all the programs that bind the module need to be updated.

"No problem!" you say. "I'll just issue the UPDPGM command," like so:

UPDPGM PGM(MYLIB/MYPGM) MODULE(MYLIB/PROC1)

Sure enough, when you issue this command the *PGM object is updated to use the new version of the module. Now you must repeat this command for each program that uses the module, a tedious and annoying process. And what if the module in question was used frequently but not globally, as in our example? You would need to identify which programs to update. Of course, there is a command that could help:

DSPPGM PGM(MYLIB/MYPGM) DETAIL(*MODULE)

This gives a list of all the modules bound in MYPGM. Now check every program to find the ones that need to be updated. Add the complexity of several hundred subprocedures, and you see that this approach quickly becomes unwieldy.

Fortunately, a good ILE implementation does not have to suffer such a maintenance nightmare. Service programs provide a facility for housing and organizing modules and updating the programs that are bound to the modules within the service program. When properly used, service programs virtually eliminate the problems I've outlined. The rest of this article introduces you to the creation, use, and maintenance of service programs.

Serving Modules Buffet-Style

Service programs consist of one or more modules. By referencing a service program at the time a program is created, any module that is defined in your service program export list is available to your program for binding. As a result, you end up with a "buffet" of procedure choices without the added complexity of listing them each individually on the CRTPGM command. Any collection of *MODULE objects can be used to create a service program, including "main" modules, but even so, neither a service program nor any of its procedures can be called directly; instead, they must be bound by a program. A service program has an object-type of *SRVPGM, and, like a *PGM object, once it has been created the constituent *MODULE objects can be deleted.

Let's return to the original example, only now we have four modules to bind together in order to create the program. Our command now looks something like this:

CRTPGM PGM(MYLIB/MYPGM) 
   MODULE(MYLIB/ENTRYMOD 
      MYLIB/PROC1 MYLIB/PROC2 MYLIB/PROC3)

As you can see, the command just gets longer and longer, but we are about to change that. Let's assume that PROC1, PROC2, and PROC3 are all subprocedures and that they are used extensively throughout our software. Instead of maintaining them individually like this for each command, you want to put them into a service program. Here is a command that will do so quickly:

CRTSRVPGM SRVPGM(MYLIB/MYSRVPGM) 
   MODULE(MYLIB/PROC1 MYLIB/PROC2 MYLIB/PROC3) 
      EXPORT(*ALL)

You now have a *SRVPGM object called MYSRVPGM. By specifying EXPORT(*ALL), you are making all of the modules listed on the CRTSRVPGM command available to any program that references the service program at creation time. Before I continue I must point out that this is not how I recommend managing the objects in your service programs, but is invariably where everyone starts and is a crucial step toward understanding service program maintenance. You can view the module contents of the service program by running this command:

DSPSRVPGM SRVPGM(MYLIB/MYSRVPGM) DETAIL(*MODULE)

Run this command without a DETAIL attribute specified, and you can scroll through 11 different displays and get a great deal of information.

Now when you want to create the program, the command looks a little different:

CRTPGM PGM(MYLIB/MYPGM) MODULE(MYLIB/ENTRYMOD) BNDSRVPGM(MYLIB/MYSRVPGM)

Hopefully, you will agree that this command is much cleaner to use, especially if you had 30 modules instead of three. While this is nice, the greatest benefit comes when you need to change a module. In the first example, you had to execute the Update Program (UPDPGM) command for every program that uses the module, which was not a pretty maintenance picture. With service programs, you only have to issue one command, UPDSRVPGM, like so:

UPDSRVPGM SRVPGM(MYLIB/MYSRVPGM)  
   MODULE(MYLIB/PROC2)

Doing so updates not only the service program itself but also all of the programs that have bound PROC2. This automatic update is perhaps the best argument for using service programs, but it can also cause its own set of problems.

Unpredictable Results May Occur

You now have some real maintenance power at your finger tips, but power can be dangerous. The most significant danger occurs when a procedure's prototype changes. For example, say PROC2 has a PR, like so:

d PROC2           pr                  
d  parm1                         5i 0 
d  parm2                        50a   

And you change parm1 from numeric to character:

d PROC2           pr                  
d  parm1                        10a   
d  parm2                        50a   

You then issue the Update Service Program (UPDSRVPGM) command and receive no errors. So all is well, right? Wrong. At this point any program calling PROC2 is still using the original prototype and will continue to do so until it is recompiled. The updated PROC2 is expecting the new prototype. Since this little mismatch doesn't affect the service program itself, the UPDSRVPGM command will not throw an error, so, as they say, unpredictable results may occur. Your programs will be updated because the prototype and calls specified at compile time still match, but at runtime you can expect to see errors.

Even worse, you may not see errors, at least not immediately. Increasing the size of a character parameter, for instance, will still appear to run normally, but in fact the parameter in PROC2 will be appended with additional memory space information and can produce horrid results. This is a nasty flaw in the UPDSRVPGM routine, but until the language gets overloaded procedures or true procedure signatures, it is something to be cautious about. Of course, not changing procedure parameters is the best way to handle this problem, but if you must change the PR for a subprocedure, be aware of the ramifications of making such changes and be prepared to recompile and update the programs that use that particular procedure.

A Not-So-Final Word

We've come a long way by putting our modules into service programs, but there is still plenty of work left to do. Before you go and rework your entire system, you should know that while the method I've outlined thus far will certainly work, it is not the best way to do things. This method works fine for service programs that never need their EXPORT lists to change, but it does not handle service program additions very well and, as a result, creates some new maintenance problems of its own.

In the next article I will show you how to use Binder Source Language to relieve almost all of your service program woes, and I will discuss single versus multiple procedure modules in service programs, and will outline some of the different approaches to service program design. So until next time, happy coding!


Joel R. Cochran is the director of research and development for a small software firm in Staunton, Virginia, and is the author and publisher of www.RPGNext.com. E-mail: joel@rpgnext.com


Sponsored By
ASNA

Why we chose ASNA Visual RPG for .NET:

"I choose AVR for .NET over WebSphere because learning new programming techniques and methods can be a daunting task, but ASNA makes it much easier with the quality of support and examples that are provided. Add ASNA training and the combination is unbeatable. A HUGE savings in development cycle is very probable, even with the time it will take to become proficient in .Net."
--Dean Bathke, Mid-Continent

Learn more about AVR for .NET today!
www.asna.com/infoavrdotnet.aspx


THIS ISSUE
SPONSORED BY:

Lakeview Technology
ASNA
WorksRight Software
Profound Logic Software


BACK ISSUES

TABLE OF
CONTENTS
Putting User Spaces in Your Toolbox

Service Programs with a Smile

Back to Basics: The Copy Screen Feature

OS/400 Alert: Security Is More Than Staying Current


Editors
Shannon O'Donnell
Kevin Vandever

Managing Editor
Shannon Pastore

Contributing Editors:
Howard Arner
Raymond Everhart
Joe Hertvik
Ted Holt
Marc Logemann
David Morris

Publisher and
Advertising Director:

Jenny Thomas

Advertising Sales Representative
Kim Reed

Contact the Editors
Do you have a gripe, inside dope or an opinion?
Email the editors:
editors@itjungle.com


Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.