Soft-coding is writing source code that allows someone to change the behavior of a program without modifying and recompiling. It makes programs more flexible by allowing users to change programs to meet their needs without calling on you.
Soft-coding helps you handle exceptions. For instance, suppose you want all expense reports to automatically go to a specific printer, except for Joe Smith's expense reports, which are to go somewhere else. Maybe you want some purchase orders to go to an output queue to be printed, but you want other purchase orders to go to an output queue where your fax software will read them and send them.
You may be able to benefit from soft-coding techniques if any of these situations applies to you:
? Users tell you they want a program like someone else's, but with some "small" modifications.
? You have cloned programs that differ only slightly from the original.
? Users cannot change the way they do a job without coming to you to change and recompile a program.
? You cannot rename a library or combine two libraries into one, without your applications crashing.
Problems with Hard-coding
Hard-coding creates more work for you, because users have to involve you when they need to make changes. For instance, suppose Joe needs two copies of a report, but everybody else needs one. You might write CL code like that in 1.
Hard-coding creates more work for you, because users have to involve you when they need to make changes. For instance, suppose Joe needs two copies of a report, but everybody else needs one. You might write CL code like that in Figure 1.
This code works fine, but you will have more work to do in the future. When Betsy decides she wants two copies as well, you'll have to modify and recompile the program.
Wouldn't it be nice if each user could tell the program how many copies he needs? Wouldn't it be marvelous if each user could change his mind as often as he likes and never have to notify you? Well, that's what soft-coding is all about.
Soft-coding stores information in objects the programmer creates, such as files, data areas, and user spaces, rather than in program code. Programs can then access these objects at run-time to get information about how they are to do their job.
Let's look at another approach to users needing differing numbers of copies. You can create a file with three fields?user ID, report ID, and number of copies?uniquely keyed on USER and RPTID. You would use this file to store information about reports.
Next, you would need a simple RPG program, like the one in 2, to retrieve information from the file.
Next, you would need a simple RPG program, like the one in Figure 2, to retrieve information from the file.
Instead of using hard-coded values, the CL program (see 3) calls the RPG program to find out how many copies the user needs.
Instead of using hard-coded values, the CL program (see Figure 3) calls the RPG program to find out how many copies the user needs.
Now you can change how many copies of a report a user gets with a file maintenance program or a utility like DFU. If you write a program that lets users change their own records, the users can control their reports without coming to see you.
You can soft-code information that is common throughout an application. Let's say "ABC Incorporated" appears in your report headings and at the top of your displays. Your plant is sold and renamed "XYZ Corporation, Eastern Division." If you hard-coded "ABC Incorporated" in your output specs and DDS, you groan and kiss the weekend good-bye. However, if your programs retrieve "ABC Incorporated" from a data area, you only have to execute one Change Data Area (CHGDTAARA) command.
Suppose you need more than one "environment" for each user of a single application: say, a training environment and a production environment. Suppose also that, as part of the payroll system security, you restrict each payroll clerk to a certain member of file PRTRAN, set aside for his use alone.
You could write a different front-end program for each payroll clerk. Each program would have a Change Current Library (CHGCURLIB) command to change the current library to the library containing the payroll files. Each program would also have to add a member for that user to file PRTRAN, unless the member already existed, and override file PRTRAN so that all programs would use the member.
To change from the training environment to the production environment, you'd have to modify the CHGCURLIB command in that user's CL program and recompile the program. To add a new payroll clerk, you would copy one of the existing programs, modify it as needed, and compile.
Alternatively, you could set up a control file keyed on user ID. In this file, you would store a value for the user's current library. Then you'd only need one CL program to front-end your payroll system, no matter how many payroll users there were. The program would retrieve the user's record from the control file, then use that file's data to set up the user's working environment.
The control file would consist of only two ten-character fields?USER and LIBR. The file, which we might call PRCTLF, would be uniquely keyed on USER.
Each user would run a CL program like that in 4 to start the payroll application.
Each user would run a CL program like that in Figure 4 to start the payroll application.
Soft-coding lets you switch a user from one environment to the other with one simple change to his control record. You can give other users access to the payroll system simply by adding a record to this file.
It is possible to soft-code your calculations to some degree. For example, employees can have several types of income, such as base salary or wages, overtime pay, tips, vacation pay, bonuses, and severance pay. Some of these pay types are taxable; others aren't. Some of these pay types are included in Worker's Compensation wages; others aren't. The two lists are somewhat different.
Suppose you're writing a report program to show Worker's Compensation gross wages. You could hard-code such pay types into your program (see 5).
Suppose you're writing a report program to show Worker's Compensation gross wages. You could hard-code such pay types into your program (see Figure 5).
Another option you might consider is setting up a table file. Group the codes for each of the pay types into income groups. Set up one income group for W-2 gross income, another for Worker's Compensation gross income, and so forth. 6 illustrates how you would load such a file.
Another option you might consider is setting up a table file. Group the codes for each of the pay types into income groups. Set up one income group for W-2 gross income, another for Worker's Compensation gross income, and so forth. Figure 6 illustrates how you would load such a file.
7 contains code fragments from an RPG program that uses this technique. The EMPINC (employee income) file has a separate record for each income type an employee receives (e.g., regular pay, overtime pay, vacation pay). The INCGRPF file is being used to read only the income types that are grouped under Worker's Compensation gross wages. The program reads the records for these income types, sums up the amount fields, and prints a total line for each employee.
Figure 7 contains code fragments from an RPG program that uses this technique. The EMPINC (employee income) file has a separate record for each income type an employee receives (e.g., regular pay, overtime pay, vacation pay). The INCGRPF file is being used to read only the income types that are grouped under Worker's Compensation gross wages. The program reads the records for these income types, sums up the amount fields, and prints a total line for each employee.
Now the payroll clerk can change the types of income included in Worker's Compensation wages instead of calling MIS to make the change. Also, only one file needs to be changed instead of multiple programs.
Extra files mean more I/O, and unnecessary I/O is expensive and inefficient. You can reduce file I/O by reading codes or code groups into a table, array, or user index at program initialization time and using table lookups to retrieve the information. In this program, array CDE replaces continuous input operations from INCGRPF.
Soft-coding with OS/400 Objects
OS/400 makes heavy use of soft-coding techniques. Think about what the system goes through to determine which output queue to place a report into. The default value of the Create Printer File (CRTPRTF) command's OUTQ parameter is *JOB. This value specifies that the generated output should go to the output queue of the job running the program. Jobs get their values from job descriptions. The default value of the Create Job Description (CRTJOBD) command's OUTQ parameter is *USRPRF. This means that many jobs retrieve their output queue values from the user profile of the user who initiates the job. The Create User Profile (CRTUSRPRF) command's default OUTQ is *WRKSTN, which says that printed output goes to the output queue assigned to the display the user is working from. A display's default output queue is the output queue of the printer specified in the Create Device Description Display (CRTDEVDSP) command's PRTDEV parameter. PRTDEV's default is *SYSVAL, which points back to the system value QPRTDEV. In other words, when a program opens a printer file, the system might search the printer file, a job, a user profile, a device description, and a system value before it can determine which output queue to send the report to.
Clearly, you can specify an output queue name in several places, depending on what you're trying to do. A common way of handling this type of thing is to assign output queues to user profiles. This makes all output for a user go to one place by default. If a user's output queue is not attached to a writer, the user can review printed output and delete it or assign it to another output queue for printing.
If you have reports that you want to send to a certain output queue, no matter who generates them, you can specify the output queue on the CRTPRTF or Change Printer File (CHGPRTF) command. Let's say that you want purchase orders to go to a printer on which preprinted purchase order forms are always mounted. You can change the OUTQ parameter of the purchase order printer file to point to that printer. Other reports generated by the purchase order print job would go to the output queue assigned to the job, but the purchase orders themselves would go to the printer with the preprinted purchase orders.
If you have users who work at various places and want their reports to print out nearby, leave their user profiles with the default value *WRKSTN. Assign a nearby printer to each workstation.
Common soft-coding values used in OS/400 commands are *JOB, *CURRENT, *USRPRF, *WRKSTN, and *SYSVAL. Most soft-coded parameters eventually trace back to a system value.
The Library List
You can enhance your soft-coding techniques by letting the system scan the library list when looking for objects, rather than hard-coding library names in your code. For example, let's say that three factories use your system and that they use the same software. You need to print the plant name at the top of a certain report. You could make three copies of the report program and hard-code the appropriate plant name in the page headings of each one. The problem with that approach is that you have three separate programs to maintain.
Another approach is to create a common library for the objects used by all plants (e.g., programs, display files, and printer files), but have separate libraries for data objects, such as database files. Each user's library list includes the common program library and the data library for the factory he works in.
To put the plant name on displays and reports, you would create a data area called PLANT_NAME in each of the three data libraries and store each plant's name in its data area. The report program would read whichever copy of the data area it found by scanning the library list, and it would print out whatever it found.
Another advantage to using the library list is that you can easily reorganize the objects on your system. If you don't hard-code library names in your programs, you can rename libraries and move objects from one library to another. If you do hard-code library names and have to rename a library, resign yourself to another long weekend at the office.
If a command will not read the library list?for example, the FROMLIB parameter of Create Duplicate Object (CRT-DUPOBJ)?precede it with a Retrieve Object Description (RTVOBJD) command to find the library name. 8 illustrates how you would do this.
If a command will not read the library list?for example, the FROMLIB parameter of Create Duplicate Object (CRT-DUPOBJ)?precede it with a Retrieve Object Description (RTVOBJD) command to find the library name. Figure 8 illustrates how you would do this.
Hard-code library names in as few places as possible. A better approach is to maintain library lists through job descriptions and the system value QUSRLIBL. An alternative is to create a file, keyed on user ID, that contains the library list in a character field 275 bytes long. When a user signs on, his initial program retrieves his record. Then it executes a Change Library List (CHGLIBL) command through QCMDEXC to set the library list of his interactive job and any batch jobs he submits. One nice thing about this approach is that you can easily find out which users have a certain library in their library list by using SQL or Query, or even Display Physical File Member (DSPPFM).
If a user has to use different library lists for different tasks, give him menu options to let him choose the environment he needs. Let the programs behind those menu options, not the application programs, change the library list.
Disadvantages of Soft-coding
Soft-coding also has its disadvantages. First, soft-coded programs are harder to document and understand, because some information is external to the program rather than in the program code. A programmer has to look in more places to decipher a program. There may also be more steps in the program, since you must include code to retrieve and interpret the externally stored data.
Soft-coding is harder to program, or at least it requires more thought. Soft-coded programs are not usually the type that you can write "on the fly."
Soft-coding requires more user training if you plan to turn maintenance of your soft-codes over to your users.
The advantages, however, far outweigh the disadvantages. Soft-coding lets you spend less time doing tedious maintenance programming and more time developing new programs.
Don't Be Hard-headed! Soft-code!
This is not meant to be an encyclopedic reference of soft-coding techniques, but an introduction to the philosophy of soft-coding. You may think of other techniques you can use in your environment.
Change is a law of life. Employees come and go; product lines and prices change; organizations reorganize. Do yourself a favor. Try to write software that allows users to respond to change without programmer intervention.
Ted Holt is an associate technical editor for Midrange Computing.
Sharon Cannon is a programmer/analyst with Drexel-Heritage Furnishings in Drexel, North Carolina.
Tools from the Trenches
Figure 1: Hard-coded Printer Override
DCL VAR(&USER) TYPE(*CHAR) LEN(10) RTVJOBA JOB(&USER) IF COND(&USER *EQ 'JOE') THEN(OVRPRTF + FILE(AR100RP1) COPIES(2)) ELSE CMD(OVRPRTF FILE(AR100RP1) COPIES(1))
Tools from the Trenches
Figure 2: Program to Retrieve Printer Override Values* Retrieve number of copies a user gets of a report * FPRTOVR IF E K DISK I SDS I 254 263 SUSER C *ENTRY PLIST C PARM PUSER 10 User ID C PARM PRPTID 10 Report ID C PARM PCOPIE 30 Copies * * If no user specified, assume current user * C PUSER IFNE *BLANKS C MOVELPUSER USER C ELSE C MOVELSUSER USER C ENDIF C MOVELPRPTID RPTID * C KEY1 KLIST C KFLD USER C KFLD RPTID * C KEY1 CHAINPRTOVRR 11 * * If user has no record for this report, look for default values * C *IN11 IFEQ *ON C MOVEL'*DEFAULT'USER P C KEY1 CHAINPRTOVRR 11 C ENDIF * C *IN11 IFEQ *OFF C Z-ADDCOPIES PCOPIE C ELSE C Z-ADD1 PCOPIE Assume 1 copy C ENDIF * C SETON LR
Tools from the Trenches
Figure 3: Soft-coded Printer OverrideDCL VAR(&USER) TYPE(*CHAR) LEN(10) DCL VAR(&COPIES) TYPE(*DEC) LEN(3) RTVJOBA JOB(&USER) CALL PGM(RTVPRTOVRR) PARM(&USER AR100RP1 &COPIES) OVRPRTF FILE(AR100RP1) COPIES(&COPIES)
Tools from the Trenches
Figure 4: Payroll Front-end ProgramPGM DCL VAR(&CMD) TYPE(*CHAR) LEN(256) DCL VAR(&USER) TYPE(*CHAR) LEN(10) DCLF FILE(PRCTLF) RTVJOBA USER(&USER) /* Read the user's record */ CHGVAR VAR(&CMD) VALUE('OVRDBF FILE(PRCTLF) + POSITION(*KEY 1 PRCTLFR' *BCAT '''' *TCAT + &USER *CAT ''')') /* Execute the override */ CALL PGM(QCMDEXC) PARM(&CMD 256) /* Read file */ RCVF DEV(*FILE) MONMSG MSGID(CPF0000) EXEC(DO) /* (User is not in file; send msg & exit program) */ ENDDO CHGCURLIB CURLIB(&LIBR) ADDPFM FILE(PRTRAN) MBR(&USER) SHARE(*NO) MONMSG MSGID(CPF5812 CPF7306) OVRDBF FILE(PRTRAN) MBR(&USER)
Tools from the Trenches
Figure 5: Hard-coded Payroll Calculations for Worker's Compensation ReportC INCCDE IFEQ 'BASPAY' C INCCDE OREQ 'OVERTM' * ... etc.
Tools from the Trenches
Figure 6: File INCGRPFIncome Group Income Code (INCGRP) (INCCDE) W2WAG BASPAY W2WAG OVERTM W2WAG BONUS : : WCWAG BASPAY WCWAG OVERTM (etc.) (etc.)
Tools from the Trenches
Figure 7: Soft-coded Payroll Calculations for Worker's Compensation ReportE CDE 99 5 * C PAYKY KLIST C KFLD EMP# C KFLD INCCDE 5 * ... (more code) C Z-ADD1 X C X DOWLECOUNT C MOVE CDE,X INCCDE * process all records for this employee and pay code type C PAYKY SETLLEMPINCR C PAYKY READEEMPINCR 53 * C *IN53 DOWEQ'0' * ... (code to process one record) C PAYKY READEEMPINCR 53 C ENDDO C ADD 1 X C ENDDO * C WRITETOTAL 51 * ... (more code) * C *INZSR BEGSR * * Load payroll codes for workman's comp into array CDE C MOVEL'WCWAG' GROUP C OPEN INCGRPF C Z-ADD1 X 30 C GROUP SETLLINCGRPR C X DOWLE99 C GROUP READEINCGRPR 53 C *IN53 IFEQ '1' C LEAVE C ENDIF C Z-ADDX COUNT 20 C MOVE INCCDE CDE,X C ADD 1 X C ENDDO C CLOSEINCGRPF * C ENDSR
Tools from the Trenches
Figure 8: CRTDUPOBJ with Soft-coded Library NameDCL VAR(&LIB) TYPE(*CHAR) LEN(10) RTVOBJD OBJ(XYZ) OBJTYPE(*FILE) RTNLIB(&LIB) CRTDUPOBJ OBJ(XYZ) FROMLIB(&LIB) OBJTYPE(*FILE) TOLIB(xxx)