Hello,
I'm not sure that I understand why you use SQL instead of F-specs.
Assuming that you mean "embedded SQL", that is... both embedded SQL
and F-specs are global to the module. Both of them have a means of
saving data into variables that are local to the subprocedure.
don't get me wrong -- there's absolutely nothing wrong with using
embedded SQL for your file access. I just don't see how it solves the
"there's no F-specs in procedures" dilemna, since it works exactly
pretty much exactly the same as F-specs do from a global vs. local point
of view.
Using qualified data structures for your database results (whether they
come from F-spec native I/O or SQL, either way) would be a good idea, IMHO.
For your #4 note... there's only one LDA per *job*. So, obviously,
you can't have a separate LDA for each subprocedure. Consequently, I
see no disadvantage to reading the LDA from the global D-specs instead
of in a subprocedure.
Are you at risk of two JOBS that use the same service program corrupting
each other? Assuming that I can take the word "job" literally (meaning
the unit of work that i5/OS calls a "job") then no. Jobs create
separate activations from other jobs. This is true of both *PGM and
*SRVPGM objects. They'll also have separate access paths to the databases.
In fact, I think it's helpful to remember that a service program
(*SRVPGM) is pretty much identical to a regular program (*PGM) in every
way. There's really only one difference: a *SRVPGM lets you call all
of it's subprocedures independently, and a *PGM does not. In every
other way, *SRVPGM and *PGM are identical.
Don't overcomplicate things by thinking of a *SRVPGM as some alien tool.
It's just a program where the subprocedures can be called
independently -- nothing more, nothing less.
However, if instead of a "job" you really mean that you have two
different programs in the SAME job that are calling the same service
program, then the answer will depend on your activation group strategy.
Just like a *PGM, one copy of a *SRVPGM can be called by many other
programs on the system. If that *SRVPGM isn't stateless, then one
program might change something that another program expected to be
unchanged.
For example, I once saw an application where a sales rep got a subfile
listing all of his customers. He could move the cursor to a given
customer and press ENTER to drill down into details for that customer.
When he hit F12 from those details, it'd return to the higher-level
listing. This was implemented as two programs, one that did the screen
logic for the list of customers, and another one that was called to
display the details of each customer. A service program named CUSTINFO
was used by these programs to get the customer information. CUSTINFO
had a "start list" routine that started the list of customers by running
SETLL on the customer file. It had a ReadNextCust routine that would use
READE to get the next entry. It also had a CustDetails procedure that
would chain to a given customer record and get the details. The
problem was, the first program (the one that displayed the list of
customers) would load one page at a time into the subfile, then at the
user's instruction, call the 2nd program. When the 2nd program loaded
the customer details, it's CHAIN operation would change the position of
the customer file. When the user exited the details screen and hit page
down, ReadNextCust would read the record after the CHAIN instead of the
record after the last entry that had been loaded into the subfile. This
resulted in the paging not working properly.... they couldn't figure it
out, so they called me in, and I pointed out the problem. Both the
"list of customers" program and the "customer details" program were
sharing a single activation of the service program, so the CHAIN, SETLL,
and READE were all changing the cursor of the same database file.
I wouldn't exactly refer to that as "corruption". But, it's the sort of
problem you run into when you begin using service programs and haven't
yet learned to make them stateless. By "stateless", I mean one call to
the service program doesn't rely on something to have been "set up" by a
previous call to the service program. Or to put it another way, the
service program doesn't need to be in a particular "state" when a call
is made.
But that situation would never have happened if the two programs were in
different JOBS -- the problem only happens when programs in the same job
share a service program, and the service program isn't stateless.
As luck would have it, I'm actually planning to publish an article TODAY
(assuming the folks over at Penton aren't having technical difficulties)
that includes information about how I like to write service programs.
I'll post a link when the article is available to the public.
nike@xxxxxxxxxxxxxx wrote:
Hi All,
We have just recently started using service programs and procedures for a
lot of our new development. While a couple of us have some experience, in
many ways we are still winging it.
In a meeting with one of the other programmers, a few interesting
questions came up. Mostly along the lines of 'why does this even
work?'... We have adopted some practices that are working but we are not
100% confident that there is not something ugly waiting to bite us down
the road.
Here are a few of the things we are doing -- If any of them are major
no-nos I would appreciate a heads up:
1 - Because we cannot use F-specs in a procedure (yet) we use SQL for all
data access. One of our programmers mentioned that we were the first shop
he has seen using SQL in service program procedures.
2 - Because SQL host variable names must be unique in a source member, our
service programs use a list of 'global' D-specs for things like Customer
Number (sqlCusn). Any procedure in the service program that uses Customer
number as an SQL parm now uses sqlCusn.
3 - We are grouping related procedures in single members - for example,
there are about 10 or so EDI related procedures in a single source for the
EDI Service Program.
4 - We have a Test and Live environment, with unique library lists. In
normal RPG we would test the LDA to determine the environment, but in
procedures we cannot. We have experimented with adding the LDA to the
'global' D-specs and it seems to work...
Encapsulation is our main concern. Are we at risk of two jobs that use
the same Service Program corrupting each other -- SQLCOD or sqlCusn
overlaps, crossed LDA values, etc?
Sorry for the long post, but sometimes I get scared when things work and I
am not sure I understand why. When I first started coding I was advised
that if your program compiles without error on the first try then scrap
the code and start over...
Let me know your thoughts,
Thanks!
JD
As an Amazon Associate we earn from qualifying purchases.