As programmers, we write these monster RPG programs (sorry Cobol fans) and hope the compiler helps us out. But how can we be lazy with the code itself? What can we do to make sure the programs are written to take advantage of ALL the features of the OS/400 so they finish at about the time that we want to take a nap? Here are just a few things we can do.
New program or modification
Making a modification
Say you need to go into the monster accounting program and insert a new function. How do you do that? That accounting program is so huge and daunting! Well, what you can do is prototype your change into a SMALL RPG program, compile that baby, and ISOLATE your testing to that small routine.
Write the routine generically enough, and COMMENT everything NOW with BUSINESS concepts, not code. Some people document code, and that's really not what that's all about.
Once you've tested this 50/100-line mod and have gotten the debugger to REALLY like it, throw EVERYTHING at that little module. At that point, you can insert a program call into your program or cut and paste the routines into the program. Once there, you're nearly home free. Next, see if your new mod is interfering with the original program. Note, however, that calling the program isn't that much of a hit performance-wise if you use the program as a routine. That means NOT setting on Last Record or LR. You need to really outthink how that program starts clean vs. how it starts after it's been run once, so be careful. For your information, the system takes about 200 microseconds to load the program into memory. The second time the program is run, it is accomplished in a fraction of that time, as long as Last Record has not been set on.
Creating a new program
Need to write a new program instead? If so, then make sure that NO constants are left in the program. That's because if they are external to the program, you don't need to recompile things to accomplish tasks that should be simple.
Do you have to deal with a corporate name change? No big deal -- you removed that name and placed it in a file someplace. Just change it there.
Do you need to program for first quarter results? Pass that date selection into the program -- don't calculate that based on ANYTHING -- these business rules ALWAYS change. The user doesn't care HOW you accomplish something just as long as it's done right. Report selection needs to be expanded, then adding records to a file will save you from checking out the original, making the modification, testing and then reinstalling the program. Edit the file, and you're done.
With either of the above scenarios, remember to run through the source-level debugger FIRST to get an idea of how the program is running before turning it over to the Q/A department.
Process a LARGE amount of records from a fileSo, you need read thousands of records. How do you do it? First, ask yourself the following:
- Can SQL do this and get away with it?
- Can Query handle the report?
If you can answer yes to either question, then proceed using that technique. But if neither method is possible, then you need to write a program. RPG is great at handling thousands of records at a time. Start with the following techniques firmly in mind.
a. Position to the first record for the whole shebang
i. Use SETLL for this
ii. Have some REALLY clever Keys created over files so you can RE-USE them for other things
1. I don't like using "selects" or "omits" unless it's absolutely necessary, but I like keying OFF the Status field and positioning on the right status. Want to find unposted transactions quickly? Position to status "U" or whatever floats your boat!
b. READ -- (NOT READ EQUAL!!!) the records
i. Why -- READ EQUAL performs many similar functions to the Chain command, but this also does ONE other thing -- it reads ONE record at a time. The READE can't tell where it's going next, so NO buffering. With READ you can let the system buffer the records for you, increasing speed remarkably.
c. Until END of Set OR End of file!
i. Remember untested else positions
2) The Chain to the record, do while equal to the stuff I want, process the info, then fall out of the list thingamabob!
a. Chain to the record
b. If it satisfies the DO/While test Process
c. Perform business logic
d. Read the next record -- let the DO/WHILE logic help control program flow.
e. LEAVE and ITER are our friends -- USE THEM WISELY -- and yes, they are goto's, but they are CONTROLLED goto's.
i. The "LEAVE" opcode positions to the next "ENDxx" statement in loops.
ii. The "ITER" opcode positions to the TOP of the DO/FOR statements, making a "Do-Over"
3) The FOR/NEXT read only the amount of records you need to whoseswhatsis!
a. Anyone using FOR/NEXT for filling subfiles yet? This is a FABULOUS tool within your programs -- don't ignore it!
Now that you have your programs functioning at high speed, make sure you don't perform calculations for year reversal using the OLD methodology of multiplying 100.00001. Why? This slows down processing because it's actually overflowing the calculation to perform it and lopping off the digits to the left to display. It's a cool trick, but since the program is in an exception state, it causes extra cycles to simply recover from overflowing the field. Placing your date into data-structures and then moving the fields takes up more code, but it performs at lightning speeds because the moves are simple.
Remember, kids, salt these tips to taste. These scenarios may be complicated by many other factors I'm not listing. Writing the solutions in RPG with SQL can be MANY of the solutions (the business logic is far easier to spot in SQL than RPG -- a huge consideration) especially since they can be tested quickly using the SQL engine built into the iSeries. Once properly functioning, you place that SQL into your program.
Let's be careful out there and practice safe computing!
About the author: Andrew Borts is webmaster at United Auto Insurance Group in North Miami, Fla. He is often a frequent speaker at COMMON and is past president of The Southern National Users Group, an iSeries-AS/400 user group based in Deerfield Beach, Fla.