Showing posts with label Standards. Show all posts
Showing posts with label Standards. Show all posts

Thursday, September 8, 2016

Under the covers of the SELRCD function type


Hi,

This blog touches on the design challenges when using select record (SELRCD) function type and makes some recommendations for best practices.  Disclaimer:  These are from personal experience and may not cover all scenarios.  I would be happy to hear of any ideas/improvements that can be made to this post.

SELRCDs can cause quite a few issues if you are not aware of the quirks of how Synon generates the code.

Let's cut straight to the problem domain at hand.  In my sample model you will see that I have two files declared.  You will see that "Lee's File" Refer to "Lee's Reference File" which will mean that if I have a PMTRCD or EDTFIL etc over Lee's file we will be able to prompt for the reference data.


The functions I have over the reference file are as follows, I have removed the default EDTFIL and renamed the database primitive functions inline with our internal development standards.

 The main file has numerous test functions so I have filtered on Edit file only.


The screens (Edit File and Select Records) in the blog post have been tidied (ever so slightly) to ensure that all the fields fit nicely on the screen.

I have generated up the code for the EDTFIL.

Reviewing the generated code.

By default you will see that Synon has generated code to call the SELRCD function upon prompting the field and Synon has chosen my SELRCD based on the reference file.

You will also notice that the parameters for the SELRCD have been defaulted to fields based on the RCD context of the calling program.  In this instance it was an EDTFIL.


This is pretty standard and works a treat.

Now we will add a few additional SELRCDs, you will see these below.  Note the naming of these was deliberate in order to ensure that they appeared after 'Select Lee's Reference Fi'.


In terms of impact analysis you will notice that the SELRCD is showing no usages although we have generated code above that proves the object is called.


This is due to implicit code generation that is automatically added if the field is a result of a foreign key constraint AND is input capable AND a select record exists on the reference file.  If you deleted the SELRCD at this stage and generated the code again the prompt and call logic will not be generated.  Give it a try!


Above is a screen image of the default Synon setup.  Notice the two subfile options at the bottom of the screen.  S allows you to select the SELRCD that should be used, T clears this value and leaves the generator to choose the default SELRCD.


After taking the S option and selecting my SELRCD from the reference file you will see that this is indicated above.  Because we have made an explicit reference to the SELRCD in the device design it will now appear as a usage within Synon.


You will see below that the generated code is as before which is great :-)


In order to help with the blog narrative, please now deselect the SELRCD by taking the subfile option T for default behaviour.   This will clear the reference to the dedicated SELRCD.


Now we will create another SELRCD (again deliberately named).  You will see that it sits above the current (default) select record for the EDTFIL.


If we generate the EDTFIL again we will see that the outcome is no longer the same. The generator now puts a call into the higher ordered SELRCD on the reference file.  We didn't intend for this to happen and a developer doing a regeneration could easily pick this up without knowing.  Quite dangerous....


In this instance, as the keys on the SELRCD are identical there is NOT too much to worry about.  However, in the real world 2nd and subsequent SELRCD functions will typically be over an alternate access path with a different key structure or may have additional parameters or specialist action diagram functionality which may not be the preferred default behaviour.

In order to demonstrate this let's add some fields to the model which we will then associate with a new SELRCD function.


Create yet another SELRCD function over the referenced file.  Note again I have named it deliberately so it appears at the top of a refreshed EDIT FUNCTIONS panel.


I have extended the parameters for this SELRCD to add our five new fields.


Let's generate up the EDTFIL once again and look at the generated code.

Ouch!!  Houston we have a problem.

You will see below that all of the new parameters have been defaulted to CON.  This is because the fields were not found in context for the relationship. i.e. in this case, not part of the RCD context. And because this is a warning message only it may go unnoticed.  Preferably Synon should mark these as errors and only allow the correct context ones to generate correctly i.e RCD example above.

Also we have now picked up yet another SELRCD.  One can conclude that anytime a new SELRCD is added and it appears higher up in the EDIT FUNCTION panel the next time a referencing function is generated it will generate code to call the new SELRCD and not the previous one.  Imagine a highly reference file and the chaos this could bring.


We can do somehing to help here.  Whilst we cannot get at the parameters at the point the implicit call to the SELRCD is made, we can put these fields in the context and populate them accordingly.

Add the fields to the 'Subfile Record' format RCD.  You will notice I set these to hidden.


Then in the action diagram you can set these values using a standard *MOVE built-in function.



Generate the function once more and the generated code now shows the moved and also defaults to the RCD context meaning that you no the parameters are populated with your values and NOT CON blank or Zero.



But I remind you at this stage that these were warnings in the code only.  How many people check the generated source for warnings.  I don't, do you?

Another way to do this is to switch off default processing and take control of the prompting yourself in the action diagram coding.  Back in the EDTFIL function again set the relation checking to 'USER'.




Note: This switches off all referential integrity checking so in the real world you'll also need to add action diagram code for the OPTIONAL/MANDATORY as well as foreign key constraints.  For the purposes of this blog I am only focused on the prompting and calling of the select record.

You can then monitor for prompting on your field and call ANY SELRCD function you think is appropriate.


With this method you get a nice parameter interface for the SELRCD and more importantly it is obvious to another developer that you are initialising the fields for an explicitly called SELRCD rather than an implicitly called on.  Some comments might be useful if you choose the other method.


This highlights the many options you have for calling a SELRCD and should help you decide what is best for your model, team etc.

Once last issue with SELRCDs.  I mentioned earlier that Synon (by default) will chose the highest SELRCD based on the referenced file.  Due to no usages showing it is possible that code will be generated to call an object that hasn't been created or has been removed by a developer thinking it is not used.  This will mean you'll get a 'resolve to object' call error which isn't a good look.


Best tip is to generate up a standard SELRCD for each reference file and implement it at the time the file is created.  If you decide that a file doesn't need prompting, then remove ALL SELRCDs from the file so this code doesn't get generate implicitly.  As you can see from above the code will get generated if the function exists regardless of whether the object exists or not.

Best Practices Summary

  1. Come up with a naming convention for the default SELRCD so that it is first in the list on the EDIT FUNCTIONS panel.  We use '*SLT xxxxxxxxxxxxxxx'.
  2. Always ensure you generate up and implement ALL SELRCD functions.
  3. Always keep the default SELRCD keys the same at the RTV access path.
  4. Always name 2nd and subsequent SELRCD so they appear lower in the EDIT FUNCTIONS panel.
  5. It is recommended you set explicitly the SELRCD you want to call either by the 'S' option or via action diagram coding.
  6. Never delete any SELRCD objects without checking the generated source files or by exploring all file references.

Thanks for reading.
Lee.

Saturday, August 29, 2009

TLA to FLA and beyond

This week I discovered a few new TLA’s (Three Letter Acronyms). These are ACL, PCL and MCL. Unfortunately I also discovered that when used with terms like ‘ruptured’ and ‘torn’ it is not a good prognosis for a knee. Still I’ll get over it, get fixed up, get fit and once again start to play my beloved football (soccer to some of you).

You might recall that I wrote a blog some time ago about airport codes and the potential to eventually run out of codes. See link below.

Today. I am amused. Very amused. This must be the analytical in me.

Consider this.
We were all familiar with BBC, ITV, CNN, MGM, WWE or WWF. The techoids among us are familiar with terms like XLS, DOC, PPT for our office documents or RAM, DVD or CDR as components of our PC or media centers.

Has anyone else noticed that there appears to be a trend to using FLA’s (Four Letter Acronyms) these days. Have we ran out of these or is the world moving into IT mode and creating a naming standard 2.0.

Many of you have heard of terms like HDMI, HTML, XSLT, PCML and J2EE. Some may have heard of SaaS and HaaS. A few may have been using WDSc. What is it with the little letters? Are we witnessing the birth of the second naming standard. Our kids are certainly into these with text language LMAO, PMSL and WUU2. You can look these up yourself.

With this in mind we should be covered for FLA’s for quite some time. If we exclude numbers we have 26x26x26x26 combinations available. A staggering 456976 configurations from which to choose from. That should keep us going for a while but with patenting and copyright on the increase these might run out sooner than we think.

Then we will be heading towards Five Letter Acronyms. Or FLA’s.

“Hmmmm. Isn’t that TLA for FLA already taken?” I hear you say. We might have to skip to SLA or (Six Letter Acronyms) or is that Service Level Agreements.

Interesting times ahead I guess. I am quite fond of the Five letter Acronyms though, especially BURMA :-)
Thanks for reading.
Lee.

Sunday, June 7, 2009

2e Development Standards - Screen Functions (Part III)

Today we shall take a quick look at the Display File function (DSPFIL).

This is a very commonly used function type in 2e and if my notes are correct there may be a thing or two of interest in this post. However, I guess that this depends on whether you are an ageing old developer like myself or one of the new kids on the block in Bangalore.

But back to the action. Like many other function types the DSPFIL can be used to display data and interact with it in multiple manners. i.e. It can act like an intelligent Select Record and also allow multiple selects. It can also be used to show the contents of an array.

Hold on I hear you say.

"It's a display file and arrays are not files......"

That's true but there are methods to complete this. Nudge me with some comments and I might write up a few examples of code to show you how to achieve this.

Also as the DSPFIL has the CTL (header region) it can be used to provide an interface with a tab look 'n' feel.

Anyhow. Major tip. Take a look at the function options for this function type. In particular, the function option called Re-Process Subfile. Set this on and off and take a look at the action diagram. There will be additional user points and logic added if this is set to Yes. This is just another example of the PODA principle that is taught when you attend training.

PODA stands for Parameters, Options, Design and Action Diagram. The philosphy behind this is simple. The more correct decisions you make at the preceding level i.e. Paramters first, then options (function options) etc the less coding (action diagramming) you will need to do.

2e is quite a neat tool. You should be judging your developers based on the least amount of code required rather than rewarding on a LOC principal (Lines of Code). I think it is fair to say that anyone can write a bad program.

Below are two sections that provide some insight into the function.

General Considerations

The default scan limit is 500. This may not be appropriate for large files. If necessary set the scan limit in USER:Initialise Program to a higher value or even to Maximum. Note: That the scan limit is a model value. If you require a higher number by default (across your model) then I recommend you change the model value YSCNLMT.

Best Practice

Any subfile control selector fields not used should be dropped rather than hidden. This is for performance reasons and avoids the problem of unintentionally deselecting subfile records. To do this simply place enter ‘-‘ against the field from within the EDIT SCREEN FORMAT DETAILS screen.

Multi-part ACP key fields acting as positioners will automatically become selectors if low order fields have data and high order fields are blank. Ensure that you understand the type of data likely to be used for the screen.

Check that the operators used by subfile selectors are appropriate for the function design. Ensure you want EQ, LE, GT or CT for example. Don't assume the default role of these fields.

If a positioner or selector field has mod 10/11 check digit then it may be appropriate to replace with a function field without the check digit. The user does have to enter a valid number to position within a list.

Tip

There is no standard feature to stop the function loading records into the subfile under programmer control. The program continues until subfile page full, scan limit reached or hits end of file. However, you may trick the function to thinking its hit end of file by using a RTVOBJ over the same ACP using a very high key value. This positions the file cursor at end of file.

USER:Process Command Keys has got nothing to do with command keys. Command key processing should normally be added to USER:Process Subfile Control.

Subfile select status field is automatically set to blanks if subfile record processing completes without error.

Gotchas

If F4=Prompt is used on any subfile control selector STS type field then there is no automatic subfile reload and CALC:Subfile Control Function Fields is not executed. User then has to press enter to invoke appropriate selection logic. Function works OK if '?' is used. There is no known workaround for this bug. I would suggest that this is not actually a bug and it is harsh to judge it that way. It is simply because the enter key was pressed for the ? and not the F4 prompt.

CALC:Subfile Record Function Fields is executed before USER:Initialise Subfile Record and therefore you may process a record subsequently deselected. i.e. PGM.*Record Selected.

If any RST input parameter key is also input on device design, and its a file to file relation, then that file validation is deferred until the main validation cycle rather than take place during the load cycle. Any automatic virtuals from the 'Owned by' file will be blank when function is loaded.

An input function field added to RCD format will not automatically check for required value. Even if you set the value to Allow Blank ‘ ‘. This is because the DSPFIL template isn’t designed to have input fields and doesn’t generate the validation routine regardless of how the flag is set or any check conditions. Need to add the code procedurally via the action diagram to force input.

An input function field added to CTL format will not automatically check for required Value. Need to add the check procedurally.

Thanks for reading.
Lee.

Sunday, March 15, 2009

Why bad design sucks! - Part II

Hmmmm,

As I suspected a couple of weeks ago once you open your eyes to a subject and commence blogging about it you have it constantly in the back of your mind. My post on bad systems design and planning has had this affect on me.

I am minding my own business at my local quiz night when a question was read out by the quiz master or perhaps mistress as she is a lady. "What day of the week was Valentines Day in the year 2000?" Now as I am not the romantic type so I certainly couldn't recall this answer based on an event, although a friend 'H' was adamant he knew the day.

I decided the simple solution was the mobile phone calender so I plucked out the phone. It is a reasonably new Motorola Razor phone. So you know the routine, Menu, Organiser & Tools, Calendar. Voila.... The calendar is showing February 2009 (the current month when this event occurred).

"Excellent", I said (I remember the excitement), I can now work it out by counting back. Then I thought what about the leap years? So at this stage I decided to press the previous month button again and again and again working my way back in time faster than Marty McFly in his time machine and I didn't need a flux capacitor.

You get the idea, November 2008 came and went. July 2006 soon appeared but a few more key presses and my phone stopped working. It got as far as January 2005 and it stopped. No message, no nothing.

Bang. Another blog appears out of the blue. And a lot of questions.

Why did it stop at January 2005? How am I going to answer the question? Anyhow another of the team had an older phone that could go back further and we got the answer right in the end. fyi it was a Monday.

This got me thinking a little. What is the upper limit for this phone. After hundreds and hundreds of key presses (1007 to be precise) I got my answer NOVEMBER 2088. December 2099 I can understand as it would have covered a century but NOVEMBER 2088, what a strange limitation.

That works out at 83 years and 11 months or 30,650 days and I can't for the life of me think of a reason why my phone wouldn't be calculating this on the fly. It is not showing holidays. Leap years can be identified by a simple formulae. I certainly can't see a contraint in computing terms that would cause this to occur.

If someone can tell me why the programmer decided to restrict the dates in this way I'd be keen to hear your comments. It might be because they assumed that the phone was made after 2005 and therefore didn't need to go back for storing calendar entries. Fair assumption. But why put it in? Another unneccessary computer programmer/designer limitation I think.

Other friends on the night had different limitations on their phones and a colleague at work with a cool new blackberry had no issues at all with date range restrictions far in excess in both directions that he was prepared to sit around trying to find.

I don't think you have heard the last of the 'Why bad design sucks!' series....... It does worry me that people still impose design limitations.

Thanks for reading.
Lee.

Sunday, March 8, 2009

2e Development Standards - Screen Functions (Part II)

Part 2 in the series around screen function types will concentrate on the Select Record (SELRCD) function type.

This is often overlooked as a valuable function as it always appears to be generated on your behalf by 2e when you create a file. However, it has a few useful quirks that require a little thinking and I have often seen everly complicated logic added to them due to a lack of understanding where a simple workaround works quite nicely.

Below I summarise some of the key points when using the SELRCD:-
In general there should only be one SELRCD record per file, the default. I propose you rename your default select per for to '*SLT filename'. (See posts on naming standards). However, there may be occasions when it is necessary to select by a variety of different styles, or by a different key value. For example, where the primary key is a surrogate#.

These reasons may justify having more than one selection program, probably built over different ACPs. All other selects other than the default must be name SLT name and not *SLT name. This ensures correct ordering in the file. If using a different access path I would name them 'SLT By access path'.

The *SLT function is named this way as it will be used by the generator when building implicit field prompting code. The routine is also used to validate a record existence in relation checking. (The check restirction within functionaity). As such a default select must be first on the file and also never have its parameter interface changed unless the keys to the file changes.

CA:2E always regards the first SELRCD it finds on the model file as the default. If an alternative SELRCD should always be called for certain relation checks then that should be assigned via the Access Path relation settings. This situation might arise when a file refers to itself. E.g. Horse Refers to Horse for Mare and Horse Refers to Horse for Sire. At the relation level for the access path it is possible to set a default select record for each relation. Therefore the ordering considerations for the generator to substitute a select record are Function Level – Access Path Level – File Level (First on alphabetically on file).

The standard SELRCD should only perform a selection facility. That is, X=Select. However, a display option may be necessary in some cases as is F9 to Add a record.

Selection logic is usually performed one entity level at a time. Therefore if the SELRCD is for a lower level entity, e.g. 'Owned by', then the high order part of the key(s) will normally be RST.

The standard SELRCD should not pass back values other than the selected key. Validation and passing back of attributes is best left to standard RTVOBJ functions since the user may bypass a selection prompt and enter key values directly.

The SELRCD should not be modified to do anything unusual. If a user exits with *Exit key the default SELRCD will always exit program with return code Y2U0016='no value selected' and also send the same completion message. This processing should not be altered.

The parameter key values passed back should have NOERROR set. This is because CA:2E does not treat a 'no value selected' exit (Y2U0016) as an error when called implicitly. But it would be an error if called explicitly in an action diagram.

Closedown option should be set in the context that the program would be called.

If a SELRCD is not sufficient because of action diagramming restrictions then a DSPFIL may be used instead. But it should have a naming convention of 'SLT By or filename'. It should follow the same logic that a SELRCD would do, i.e. Same parameter definition and same action diagram style. This is often used if additional processing like F9 = Add is required.

The advantages of the DSPFIL method is it allows increased flexibility. But if you do choose this approach then this function will never implicitly be used and developers need to handle the output parameters. That said you could template this kind of function.
Tip

Using a Neither MAP input parameter does allow you to set CTL values for additional filtering.

Thanks for reading.
Lee.

Sunday, March 1, 2009

Why bad design sucks! - Part I

There are many areas of computing that have been let down by poor design.

Actually that may be a little harsh.

However, poor assumptions have definitely led to numerous designs that in hindsight could be considered questionable at best. These decisions have in turn led to systems that have suffered due to higher than anticipated volumes or longer than expected life spans.

A few examples that come to mind are:-

The millennium bug. Everyone knows this story. Developers designed systems in the 60s, 70s and 80s with 6 character dates ie DDMMYY or MMDDYY. The assumption being that storage is expensive and this system won't be around in 20 or 30 years. Well we all know how much effort was involved ensuring that airplanes never fell out of the sky in the late 90's, not to mention the contract rates for COBOL programmers that went with it. So I guess the lesson learned here is short sightedness.

http://www.trademe.co.nz/. Another example I heard about was for a very popular auction trading site here in New Zealand. The founders at a Microsoft TechEd conference a few years ago talked candidly about the early days of the business. They were describing growth of the business and unexpected challenges for the fledgling company.

The site was adding customers at a nice steady state when one day the system stopped working. No more new customers could be added.

They were a little concerned at first. After all they had just added their 32767th customer.

The issue was that in the early versions of their database they hadn't considered the domain of this particular field to carefully. i.e. the size. They had reached the limit for the integer field type on their platform. Now that the site is the most successful site in New Zealand and has made the creator a multi-millionaire, I am sure they have used at a minimum a long integer. The lesson learned here would be factor your wildest assumptions into your database designs.

www.Virtualrugby.co.nz. A sports predictions site here in NZ that has just rebranded again with another sponsor but suffered the ignominy of poor application performance and a whole host of players unable to access the site. On one occasion I was advised that the server was unable to make a connection because the limit of 111 connections had been reached. This is for a site that had over 100,000 active participants the previous year. I will go as far as suggesting the infrastructure suppliers arrangement may have changed as a result of the sponsorship change. Hopefully they'll get it sorted.

The lesson learned here. Never underestimate your audience and your processing peaks. Most of all ensure that your test systems have a reasonable subset of data to stress a mass participant application. Three guys in a room pressing the submit button as often as possible is not load/stress testing.

IPv6. Another in a long line of bad designs, or is it? It is alleged that we are to run out of IP addresses in the next few years. Some claim that this is the millennium bug of the 2000's. If it is and given the age of computing in general, we might have a few more yet. Sounds not too different to the 100 year storm scenario that happens every 4 years in these days of global warming.

I guess this one could have also been avoided but the caveat once again was when IP addressing got going the internet was quite young and connected devices were at a far lower number than they are today. Lesson earned! What do you think?

......

With all these though, IMHO it was human expectations that were at fault or shortcuts being taken to save a few bytes here or there. My advice to all application developers is to ensure that all your applications have database fields that are capable of supporting data sets beyond your wildest dreams. And to ensure that your application architecture is fit for purpose.

Bad design really does suck. Ask your end user(s).

Thanks for reading.
Lee.

p.s. I titled this Part I as I guess that now I have finally got this off my chest there will be other scenarios out there that will jump out shouting - BLOGGERTUNITY. Actually, one has just emerged but I will save that for another day.

Tuesday, February 24, 2009

*Arrays can be quirky in 2e

Hiya,

I have just become aware that *Arrays do not support the correct ordering sequence for negative index values. This has been referred to CA Support (2nd Level) for investigation.

My scenario is an array that is ordered based on a difference between two values. For the purposes of a meaningful example lets pretend that our array is a league table for the English football premier league (Soccer to some). If your game is rugby or another sport then you can draw your own comparisons.

The scenario is that after 2 games of the season I have 5 teams on 4 points. These teams are place 1 to 5 on the table. Let's further embelish this example and assume that my team, Tottenham Hotspur (Spurs) are at the top. :-)

TeamPointsGD (Goal Difference)
Tottenham4pts+78
Liverpool4pts+5
Everton4pts0
Wigan4pts-4
Chelsea4pts-8
......
Arsenal0pts-78


Apart from the obvious good start by Wigan and the strange GD for two games. I believe the example table to be a fair reflection of the real world. With Tottenham at the top. COYS. Blue and White army. Stand up if you hate Arsenal.

If I were to create an *array in DESCENDING order with the keys of Points and GD. My array would sort itself as follows:-

TeamPointsGD (Goal Difference)
Tottenham4pts+78
Liverpool4pts+5
Everton4pts0
Chelsea4pts-8
Wigan4pts-4
......
Arsenal0pts-78


The arrays doesn't handle the negative sign and although it preserves the negative sign it is unable to sort it. Note the order of Chelsea and Wigan.

Until this is fixed, a simple workaround I have used is to *ADD an arbitary figure to the GD to ensure it is a positive value. In order not to blow a limit (as over a season a team can be -100) I need to cater for a higher number so I chose 10,000 for the *array as an offset.

At the point of display which happens to be a DSPFIL I simply deduct 10,000. Simple workaround. Hopefully, simple solution that will be fixed some time in the future. Another option which I contribute to my colleague Chris Koloszar is to do the 10,000 offset for the key and leave the original value as an attribute of the array also.

My main concern is for those of you that have negative values but have yet to discover them.

I will post updates as I hear back from CA.

Thanks for reading.
Lee.

UPDATE HISTORY
==============

2:54pm (Same Day). I have had some quick responses from CA (Very impressed - Thanks Lynn). CA claim this to be working as designed. I am countering that it is a bug and was designed incorrectly. I hope that this will be fixed and I will keep you all updated.

What do you think?

Next Day - Referred to development not a trivial fix but I am confident it will be a good look over. Thanks.

Saturday, January 31, 2009

2e Development Standards - Screen Functions (Part I)

I guess the last couple of months have been a bit quite on the site. This was due to some holidays on my part and the visit of relative from overseas for 5 weeks. As you may know I live in New Zealand and the Christmas and New Year period is a time of relaxation and recouperation as well as a period of mass and I mean mass national holiday. Many businesses shut down for a compulsory two weeks.

I am now refreshed and ready to finish off those blog posts that I promised at the back end of last year.

Today I want to continue the 2e (Synon) development standards theme. I really want this site to be an extension to your technical libraries. So without further procrastination, I will get on with development standards, tips and gotcha's for 2E screen functions.

Today will shall concentrate on the single record function type PMTRCD. Future posts will cover the remaining single record function types as well as multiple record function types like DSPFIL etc.

If used as designed and thats a big 'IF', then this function should have fields on the screen that are prompts for the user to input some values which are then passed to another function for action. These would typically be a report or a processing program of some description.

But, like everything in 2e, the original design intention and actual use is only limited to the users creativeness. I have used these screen types for edit and display screens, prompts, information windows and even restricted subfiles. They are powerful for a number of reasons but for me the ability to DROP the relations and code a screen from a blank canvas is very satisfactory indeed.

General Pointers


A PMTRCD will typically be used in situations where an EDTRCD or DSPRCD is not applicable or too complex, or will have too much of a processing overhead or the traditional methods highlighted above.

For performance reasons any fields or file-to-file relations not needed should be DROPPED from the device design.

After USER:User Defined Action there is no check for any outstanding errors during the User Defined Action processing. If the function option Repeat=No then function may just exit and any errors will not be reported back to the user. Therefore it is a good idea to do a *Quit if PGM.*Return Code is not *Normal, or *Quit if *PGMERR.

Tip

If the function requires a complex set of fields or file to file relations which is not present on any existing file then consider creating an array with fields set to MAP for the PMTRCD. This is often easier and simpler than basing the function on an existing model file, then using lots of function fields and adding procedural based action diagram checking.

Gotcha's

If the function option Repeat=Yes is set then the PMTRCD just loops back to redisplay the detail screen. It does not execute USER:Load Screen. To make the function execute this user point again call user source 2E Force PMTRCD Reload






A PMTRCD behaves slightly different to an EDTRCD. During the validation cycle there is a *Quit if *PGMERR after USER:Validate Fields.

If the primary key relation check has not been turned off then an automatic prompt is generated to a SELRCD over the based upon file. But unlike other file to file relations there is no opportunity to choose which SELRCD is to be called. This I need to validate as I was unable to replicate at the time of writing.

Hope this helps?

Thanks for reading.
Lee.

Wednesday, November 12, 2008

2e Development Standards - (Composite Functions)

Todays topic is composite functions.

I have said before that there are many ways to skin a cat and with development regardless of tools and languages used, it is no different.

To date I have concentrated on the generic principles of development and also on the CA 2E tool from Computer Associates. I have put quite a few posts in place around 2E with many many more to go. To be honest I am less than 20% through what I intend to post from the technical perspective and I have barely touched the Plex product. Still good things come to those who wait.

http://www.dictionary.com/ has the definition of 'composite' as "made up of disparate or separate parts or elements". In 2E terms it means the linking of two or more functions to serve a business purpose. For example to clear a file using 2e function types you may either call a EXCUSRPGM and use the operating system or you may chose to use a RTVOBJ with no restrictor/positioner keys and then call a DLTOBJ for each record in the file. You could also call a SQL routine, embed the OS400 command in a message etc etc etc. You get my point. The composite in this example is the RTVOBJ/DLTOBJ combination.

There are other composite types that are more often encountered. Especially around creating or changing records in a database file (table for the SQLites amongst you).

I have created functions named CRT/CHG or CHG/CRT to solve a common problem of what do do if the record does or does not already exist in the database.

This lead me to consider is there is a preferred default method and are there any variations. Once again a big thanks to Ray for his contributions here.

CHG/CRT v CRT/CHG

There are times when if a CRTOBJ fails due to the record already being in existence or a CHGOBJ fails because the record does not exist. To solve these issues we generally create combination functions named either CRT/CHG or CHG/CRT. Or if you follow my recommended standards and if these are default functions then they would be named *CRT/CHG or *CHG/CRT.

In general you should select the one that is most likely to succeed, so depending on your knowledge of the environment and the data being processed, if the record is likely to not be there then you need to use the CRT/CHG combo.

There are some performance considerations over and above the availability or otherwise of the underlying record.

A CHGOBJ that contains a CRTOBJ if a record does not exist is inefficient as it generates the following code. This is particularly true for SQL generation.

Pseudo SQL Code

DECLARE CURSOR FOR UPDATE
FETCH
UPDATE if record found
INSERT if no record found
CLOSE CURSOR

Pseudo RPG Code

CHAIN
UPDATE if record found
SETLL & INSERT if no record found

An alternative coding style with a CRTOBJ calling a CHGOBJ if record already exists will generate the following code. The CHGOBJ must be an 'update style' that does not use a cursor.

Pseudo SQL Code

SELECT by key
INSERT if record not found
UPDATE if record exists

Pseudo RPG Code

SETLL
WRITE if record not found
CHAIN & UPDATE if record exists

A CHGOBJ with a little bit of grunt.

To create an 'Update style' CHGOBJ:-

For performance reasons we need to omit the prior SELECT generated for SQL CHGOBJs. This is mainly for CHGOBJs called repeatedly in batch type processing. But it can only be done if there is no requirement to read existing DB1 context fields. To do an immediate update we need to create a special version of a CHGOBJ called an UPDATE function. This will have following characteristics:-

1 - Ensure that there is no coding inside the CHGOBJ. Commonly we must transfer the timestamp coding from inside the CHGOBJ to input parameters and setting the timestamp fields directly on the CHGOBJ call.

2 - Ensure that the CHGOBJ parameters are defined in the default way using the UPD ACP structure. Fields that do not need to be changed should be made NEITHER parameters.

3 - The CHGOBJ function option for Null Update Suppression should be = No. This ensures that there is no attempt to perform an image check.

4 - UPD style CHGOBJs should ideally only have the attributes that are being changed. This is particularly important when calling a CHGOBJ from inside a RTVOBJ over the same file. Passing in DB1 context for those filed not being changed is not conducive to performance since the optimiser cannot differentiate between changed & non changed attributes.

Thoughts, opinions, concerns or fanmail gratefully accepted. Cash donations to charity please.

Thanks for reading.
Lee.

Thursday, November 6, 2008

2e Development Standards - (Hints and Tips DLTOBJ)

The humble DLTOBJ is the topic of this weeks post. This finishes of the series on the main 2e internal function types. I have covered the RTVOBJ, CRTOBJ and CHGOBJ so far. Next weeks post will be about the mertis of using a CRT/CHG or CHG/CRT combination function.

Following that I will be blogging about standards for EXCUSRSRC, EXCUSRPGM and the EXCINTFUN/EXCEXTFUN function types before moving on to a series on the screen function types.

So plenty to get though over the next few weeks. For those of you following the series, bare with me as I get these completed and published.

Back to todays topic. The delete object (DLTOBJ).

General considerations.

Only one DLTOBJ, the default (*DLT), should be present on any file. It will have no action diagram coding added.

If other associated files must be deleted or updated at the same time as the DLTOBJ. An EXCINTFUN or RTVOBJ should be created as a standard wrapper and named *DLT (Cascade).

You can use a DLTOBJ to clear an array. Simply create the DLTOBJ function over the array and remove all keys. Note this technique is not applicable for files. You should prefix the array clearing delete with CLR. I.e. "CLR Standards Sample" dropping the ARY prefix from the actual array. Note: If using the Cobol generator then this is inefficient and you are better to use the traditional RTVOBJ/DLTOBJ approach.

Auditing at record level. Remember that you no not need to add auditing records for any entry you are deleting.

Gotcha's

It is not possible to suppress the error message if the record to be deleted does not exist. Therefore if the DLTOBJ is conditional it should be called from a RTVOBJ based over the same file. Note: If called directly then the *Return code must be set to *Normal as deleting a record that is no there is generally not considered and trapped as an error.

Thanks for reading.
Lee.

Friday, October 31, 2008

2e Development Standards - (Hints and Tips CHGOBJ)

Another post about some of the finer points for the internals functions available in the 2e tool. I have covered off the RTVOBJ and CRTOBJ in some detail. I have left the obvious stuff for the user manuals and am really covering off best practices and gotchas in these sections.

Any observations and comments are gratefully received and a big shout out to Ray Weekes who passed on many of these in these sections from his experience.

The default CHGOBJ will have all parameters open except for Time Stamp and any other derived attributes which will all be made NEITHER. Action diagram coding added will only be for Time Stamp and derived data i.e. Audit records or calculated values.

Further CHGOBJ functions may be created where only subsets of attributes are to be changed or where special processing is applicable. All CHGOBJs should replicate the standard support for Time Stamp and derived data where appropriate.

Structuring your parameters. There are 2 methods for defining a CHGOBJ where only subsets of attributes are to be changed. The default method uses the UPD ACP RCD defined over the first parameter block line as the input parameter list. Database attributes not to be automatically changed from input parameter fields are set to NEITHER.

The second method uses the UPD ACP KEY as the first input parameter list line. The UPD ACP RCD is then optionally used on the second parameter line. This second approach suppresses any automatic update to the DB1 context and therefore requires a *MOVE ALL PAR to DB1 to be added to USER:After DBF Read. This KEY method has the advantage that no NEITHER parameters need be defined and no unnecessary coding is generated for NEITHER parameters.

It also protects the CHGOBJ from the effects of future attributes being added to the file.

The default RCD method of a defining CHGOBJ is sufficient for most small files or where most attributes are being replaced. The KEY method is preferred for large files where only a few attributes are being changed. It is also the preferred method on any file where existing database attributes are being incremented rather than replaced with new parameter input values since it makes the action diagram coding simpler. E.g. A CHGOBJ designed to get the next surrogate# to be used.

General pointers.

It is possible to suppress the default error message if the record does not exist by setting PGM.*Return Code = *Normal in USER:Record Not Found. Alternatively you may add a call to a CRTOBJ over the same file. But if the CRTOBJ is conditional then still set PGM.Return Code = *Normal where CRTOBJ is not called.

Any UPD ACP RCD parameter field defined as OUPUT or BOTH will be automatically moved from DB1 context to PAR context after the database update. This allows a CHGOBJ to also function like a RTVOBJ GET and to return current database values.

When using a CHGOBJ to increment values on a database remember to move the current DB1 values to a holding field as the PAR to DB1 move will overwrite the original values. Then in the Process before Update you do the *ADD arithmetic. A good standard could be to prefix the function like UPD nnnnnnnnnnnnnn.

Null update suppression is the preferred choice for all CHGOBJs. Model value YNLLUPD=*AFTREAD. This means that an image check takes place after USER:After DBF Read. The USER: Before DBF Update is only executed if the record image has been changed. Time Stamp logic and other derived processing must therefore be in USER: Before DBF Update.

In general do not use a CHGOBJ to change the primary key. Although this technique works in RPG it causes problems in COBOL. However, it may be used in RPG & SQL. SQL CHGOBJ requires the key fields to be set to MAP to force them into the SET clause.

Gotcha's

You must never *QUIT from a CHGOBJ since this may leave a lock on the record. Use PGM.*Record Changed = *Yes if any conditional processing is required inside the CHGOBJ.

Do not use a CHGOBJ or DLTOBJ over a PHY ACP because of a bug in the 2E SQL generator.
Next time the DLTOBJ.

Thanks for reading.
Lee.

Saturday, October 25, 2008

2e Development Standards - (Hints and Tips CRTOBJ)

Here we go again. Another in the series around 2e development standards. Today I thought I'd cover the CRTOBJ function type and share what I have gathered on the road over the years.

Cutting straight to the point.

Keep numbers to a minimum. In general there should only be one CRTOBJ, i.e. The default (*CRT), per file. This will have all or most parameters open and will not contain any complex processing. This makes the function reusable. The exception being surrogates that are generated inside the function and control fields like audit stamps.

These will generally be set to NEITHER and primed inside the function.

The exception to one per file would be for files that are archived or image copied. But this would not in general usage be the default *CRT. I.e. CRT Archive Image.

Shielding developers from the parameters. For simple files where records are only created under standard application control then time stamp fields may be set as NEITHER parameters and the DB1 context primed inside the CRTOBJ. Similarly, where an internal surrogate number is generated as part of the primary key then an appropriate function call over another file may be inserted. The surrogate number will normally be NEITHER, but it may be OUTPUT or BOTH if required for lower level files.

Wrappering the CRTOBJ with an internal. In some cases there may be a hierarchy of EXCINTFUN calls. Each call then performing some specific function at one level before calling the next level. This may be necessary, for example, because associated files have to be updated when a new record is created. Each main line request to create a new record will call the EXCINTFUN appropriate to the level of complexity required. If requiring just an image copy then it will call the CRTOBJ direct.

An EXCINTFUN designed to participate in the create process should have its parameters defined using the UPD ACP RCD, similar to a CRTOBJ.

Be aware of the probability of a records existence. Where it is not clear whether a record exists for a given primary key then it may be necessary to define a special CRTOBJ i.e. CRT/CHG, which suppresses the error condition and optionally changes the record. I will post a CHG/CRT v CRT/CHG vs RTV/CHG or RTV/CRT debate once I have covered off the intricacies of each of the four main internal function types.

Gotchas

To suppress the error message & error condition if a record already exists then a CRTOBJ may be created where the PGM.*Return Code is set to *Normal in USER:Record Already Exists.

Alternatively if a record already exists and it is appropriate to change attributes then a call to a CHGOBJ may be inserted in USER:Record Already Exists. In this case it is important to ensure that the parameters passed to the CHGOBJ are PAR and not DB1 context.

It is very important in any CRTOBJ to ensure that the DB1 context for any fields not directly input by parameters are initialised or primed with data inside the CRTOBJ. (They will not be input if they are set to NEITHER or if the parameter definition is changed to KEY). There is no automatic move from PAR to DB1 for NEITHER parameters and the DB1 context may contain old data from previous database functions.

By default a SQL CRTOBJ will not check for duplicate records if there is no coding in any action diagram user point other than ‘Processing Before Data Update’. However, there are times when you must or it would be better if you did check. This is accomplished by inserting code, such as comments, in ‘Processing if Record Exists’. This also suppresses the error message if the row already exists.
Next up. The CHGOBJ.

Thanks for reading.
Lee.

Monday, October 20, 2008

2e Development Standards - (Hints and Tips RTVOBJ)

I thought I'd have a break from the 2e naming conventions thread that has occupied most of the last month and launch into a series of smaller posts that talk about some of the hints and tips associated with the 2e function types.

Today's topic is the RTVOBJ. One of the most useful function types in 2e. One which is often misused or understood.

The following are some hints and tips I have learnt, taught, embellished and/or stolen over the years.

RTVOBJ Tips

Naming. Most RTVOBJ functions can be divided into one of two types. Single record GETs to bring back attributes for a given key value. Multiple reads to perform some sort of process logic or test. Different naming conventions, 'GET By ...' or 'RTV Last four transactions' will identify these two types. See previous post re:naming standards.

Getting Records. A GET will be based upon an ACP with a unique key, usually the RTV and pass in a fully RST key value. The function will only return database attributes + the xxx Record Found Y/N flag (optional for your site). The return code will not typically be explicitly modified. If the record is not found then output parameters must be cleared. Parameters, both INPUT key fields and OUPUT attributes should be defined using the same access path (ACP) that the function is based upon. Avoid using the individual field definitions unless they are not scoped by an access path.

On certain files with fixed key values the RST key may be set to NEITHER and primed inside the RTVOBJ at initialisation. Examples here are system tables that have one record.

GET's will return ALL attributes including spare fields. (A future post will talk about the benefits or otherwise of using spare fields). If the standard *GET will do, then use it!!!. There may be other ‘Get xxxxxxxx’ functions currently in your models which may have a subset of the fields. You can replace with a single *GET if preferred.

Other types of RTVOBJs will perform various processing requirements over multiple records these could be prefixed as RTV.

General Hints. When testing for certain conditions you should *QUIT the RTVOBJ for performance reasons once the condition has been found thus minimising I/O and decreasing function runtime. There are exceptions here for *Arrays. (future post).

In general try to avoid changing the default PGM.*Return Code setting, although there may be circumstances where this is justified. If you do need to identify a specific condition other than normal the user CND.*User Quit Requested appears to be a standard I have seen at many companies.

If the RTVOBJ is built over a RSQ ACP and uses RST/POS key fields then explicitly define the key fields using a KEY structure. This will allow the developer to zoom into the key structure and understand what the key fields are.

Do not leave the fields as MAP. There is no relevance for a RTVOBJ and it only confuses new developers. CA please change this. I know it doesn't generate anything!!!!!!

Default RTVOBJ's i.e. *GET should have parameters passed as RCD. Get By and RTV's over alternative access paths should use the KEY/RCD method.

If using a RTVOBJ to retrieve reference data. It is best to not do the call if the value is optional. Saves an unnecessary I/O.

Gotcha's

Best Practice

There is a well-known bug (feature) in a 2E generated RTVOBJ in that USER:Exit Processing is executed if no records are found and there is no coding inside USER:Record Not Found. Therefore if any action diagram coding is added to USER:Exit Processing then you must also code something (comment or *QUIT) inside USER:Record Not Found. This ensures that the function always behaves in a predictable manner.

If the data passed in as RST or POS parameter is of a different domain and is alphabetic for a shorter length then unpredictable results may occur. This is because the generated code is failing to clear fields when building the RPG key list. – I could not replicate in the latest release.

Best Practice

If you change the ACP that the RTVOBJ is based upon then also remember to change parameter definition. It is best to keep these consistent for developer readability.

Version 7.0 of 2E allows RTVOBJ's to be written over physical files. This reads the file in relative record number order. This is quicker than using a logical. This technique is useful when you need to read an entire file. A fix program would be a good example.

I will cover CRTOBJ in the next blog posting.

Thanks for reading.
Lee.

Sunday, October 5, 2008

2e Development Standards - (Further Naming Conventions)

So here we go. Another part in the CA 2E development standards series. Here I discuss/publish some naming conventions I have found useful with common functions in a 2E model.

I have worked at a few sites over the years that have varying levels of standards applied to the model and different approaches aiming to solve the same problem.

I have worked at sites that like to use an incremental prefix i.e. RTV56 etc, some that leave the defaults and others that follow naming convention prefixes. As with any standard it is not the actual standard that it is important. The area of concern for any development shop is the continued adherence of the standards.

What I have found works best for me is to use a common set of naming standards for the core functions in a model. Today we will discuss core functions and their naming conventions.

I will finish with a couple of examples of why I settled on my approach for 2E naming standards and as always I expect these to cause some debate in the community.

Default Create Object

I prefer that the default create object (CRTOBJ) on a file is named as '*CRT'. This function will have all the relevant processing that is appropriate to the most common use of the function. Some shops will have auditing and others use surrogate systems. The default will be named as above but other variations may be named 'CRT with Audit' or 'CRT (No Audit)'. However, if most of the time you only need to perform your sites default processing when creating a record, the '*CRT' is much easier for everyone to remember.

The important fact here in the *CRT means the default behaviour. The others are variations and are therefore not classed as default functions and will be named slightly differently. i.e. without the *. The CRT prefix should remain.

As only one function of any name can appear on any file, for *Arrays the standard is extended slightly to be '*CRT Array name' as all arrays share the same file. They simply use different definitions for the access path (sorry, array structure).

Default Change Object

Follows the same rules as the create object but will use *CHG and CHG prefixes as appropriate.

Default Delete Object

Follows the same rules as the create object but will use the *DLT and DLT prefixes as appropriate.

Also a *DLT (Cascade) can also be created. This will actually be based on a RTVOBJ and will delete all child records before deleting the parent key. Thus reducing orphaned records.

Default Retrieve Objects

As a retrieve object (RTVOBJ) can be used in many ways. I will refer to the two most common usages. The fetch of a record and the checking for a record's existence. Also remember that a RTVOBJ is also used for processing files. The next two default functions are based on a fully restricted key.

I have used the *GET naming convention for a full record being fetched. This function will be based on the default retrieval access path. Variations that bring back fewer fields or use an alternative access path will begin with GET. If using another access path use the standard of 'GET By Access Path Name'. If getting a subset of fields use the 'GET subset' - replace subset with a meaningful description. Once again I am highlighting the default usage of this function type.

I have worked at one site that prefers to bring back a Record Found Y/N flag rather than use the return code. This is site specific and I'll leave you to decide on the correct usage of the flag versus the *Return Code. See my other blog which provides further details.

Another usage of the RTVOBJ is for checking for the existence of a record. I have seen this implemented as either a *CHK or and *XST. Either are fine as long as you are consistent.

Again, note that for both of these functions types the array version will need to supply the array name as a qualifier.

There are a further two usages of the *GET and *CHK/*XST function type. This is only related to files that use the 'Qualified By' file relation to describe the key. You will know that the 'Qualified By' is used for file structures that may have a term or a date to identify a value in the key. i.e. A product price file might be qualfied by a field like 'Product Effect Date'. This saves you having to have a record for each day that a price is valid.

You will also know that this relation will automatically read backwards or forwards to find the correct record. Note this only works for the default retrieval access path. Therefore a *GET or the *CHK/*XST will generally find a record but your business logic is trying to determine if a record exists for the actual date. There are several ways to do this. You can either create an alternate RTV access path and write a 'GET By RTV 2' type function. This is perfectly reasonable.

However, and there always is one, I would suggest that a function named '*GET (Exact)' which is only used for files with a 'Qualified By' relationship will do additional processing to determine if the KEY is equal to DB1. This will help to identify to a developer when they are programming, that the file has a 'Qualified By' key but also negates the need for an unnecessary access path to be created.

This pretty much summarises my recommended standards for internal default functions. There are a couple of regularly used external function types that might also be useful and form part of my DBA recommendations of functions that should be created for every file.

The rule of thumb for creating default functions should be.

All Files - *GET, *CRT, *CHG, *DLT, *CHK/*XST and *GETEXT.
Files with a qualified By - *GET (Exact) and *CHK (Exact)/*XST (Exact)
Reference Files - '*SLT filename'
Parent/Child - *DLT (Cascade)

Default External Functions

The *SLT function is named this way as it will be used by the generator when building implicit field prompting code. The routine is also used to validate a record existence in relation checking. As such a default select must be first on the file and also never have its parameter interface changed unless the keys to the file changes.

The *GETEXT (An EXTEXFFUN with a parameter interfaces the same as the *GET) is often used for several reasons.

RPG Limits. Used to limit the number of subroutines or files in a compiled program, not a fully recommended reason. There are other specialist reasons why you would want to use this routine.
Cursor awareness. Wanting to re-read an access path whilst reading the same access path. , therefore not corrupting the cursor.
Externalisation or Program API. Externalising a RTVOBJ function for use within a non Synon environment i.e. CL Program.

If externalising based on another access path call the function 'GETEXT By access path'.

Best Practice

If creating these functions ask yourself this simple question. Am I creating this because of a file limit and if so, is this really the best section of code to externalise? Remember reducing a program from 51 files to 50 (so it compiles) only leaves a maintenance issue for the next developer, and it might be you. Afterall, there is nothing worse than seeing a string of externalised RTVOBJ functions.

Summary

I have generally preferred a prefix and/or suffix when naming functions. The prefix has been used to identify format of the function and the suffix as a sub group. This will become clearer as you see the examples build up on this blog.

You will notice that some are prefixed with an asterisk (*). This is usually reserved to indicate internal Synon objects in a model. I have chosen to indicate my core functions using this method because the * for default function types means that are all grouped them nicely on pick lists. This is done to ensure that they appear at the top of the list of functions. I am aware of other sites using numeric or other acceptable characters to attain the same result.

Note: If you choose to use this approach a known issue is that searching for a *CRT in the open functions screen doesn’t work. This is the only known limitation of this approach from a technical perspective. Other may well say that this encroaches on 2E objects. I fully agree that files should not start with * but the odd function that is core to your development model, no worries.

My next 2e naming conventions post will focus on ideas for other non-default functions.

Thanks for reading.
Lee.

Wednesday, September 24, 2008

2e Development Standards - (Extra Naming and General Standards Part 1)

Continuing with the series on 2E development standards.
A model-naming standard is very important, particularly for large models, to aid understanding and navigation. There are several types of naming standards to consider.

Model Names

A CA:2E data model has a 25-character object text names associated with files, access paths, fields, field conditions, functions and messages etc. The guidelines for each object type are detailed below. As a general rule:

Apart from files, try and only use 24 characters for the field, function, access path etc. This make it a lot easier to navigate around in the model and to use the ‘?’ prompting facility.

Capitalise all words except articles, prepositions, conjunctions, and the 'to' in infinitives. E.g. 'Currency of Invoice'

Avoid punctuation.

Try to establish a vocabulary of preferred names. Where abbreviations are necessary then they should conform to a common abbreviations list. It is recommended this list be generic across all of your development models and other languages and environments.

OS/400 Object Names

OS/400 object names and DDS names are required for actual implementation. CA:2E will assign names for all object types according to its own naming standard. Messages, DDS format names and fields will default to CA:2E assigned names.

If using a Multi-Version Multi-Model setup extra care needs to be taken to ensure that and new model objects are created equally if coding into multiple models i.e. Bug fixing a current and development release at the same time.

Queries can be written to keep tabs on objects and their names that do not cross reference satisfactorily. I.e. Model Name to Model Name as well as Implementation Name to Implementation Name. This forms part of a wider blog on model management techniques. Something for the future?

Some development shops have chosen to replace the 2e naming conventions for some objects in a development model. The Pro’s and Con’s of this approach are as follows:-

Pro's

Nicely named objects. Great for when calling programs from a menu or command line.

Encourages a standard form and reinforces the principle of the naming conventions.

Easy to detect if not renamed as 2e prefix is still associated to object.

Con's

After a while it is difficult to get a unique and meaningful object name, therefore, some names can seem ambiguous.

Extra work for a developer. Often forgotton.

Will generally require a mnemonic standard i.e. XXYYYYnnZ so may as well have the defaults.

Model Files

All new files and file changes should be managed by the Database Administrator (DBA) or a central owner for that model. This of course, depends on the size of your development shop but it good practice to separate the roles. This will allow good control of the model.

Implement a TLA?. I have implemented a Three-letter Acronym (TLA) following the name at some sites I have worked at. E.g. ‘My Sample File MSF’, The TLA will occupy the last 3 bytes of the available space for the file. Note this is the only model object type where I have deliberately use the last byte.

These 3 letters should precede all fields for that file.

File descriptions should represent a single instance of an entity, e.g. 'Customer' not 'Customers'. However, if the name describes many attributes of a single record then a plural may be ok, e.g. 'Account Parameters'.

Avoid using descriptive names like 'Details' or 'File'. E.g. 'Customer' rather than 'Customer Details File'. However, sometimes it may be necessary to differentiate between different levels of detail, e.g. 'Order Header' and 'Order Line'.

Short names will avoid truncation when assigned by CA:2E to default DBF functions or foreign key fields using 'For' text although the DBA processes of replacing or renaming of fields should negate the need for the developer to be to concerned.

Try to group Parent/Child file relationships by using common name prefixes.

Future blogs will expand on the area of model management and database administration guides.

Access Paths

Unlike files, access paths can be created by a developer with *PGMR access. It is recommended that you query the 2E model files and keep an eye on any new access paths that are created and their purpose. These should be reviewed from time to time to ensure that best practice has been considered when access path was created.

Do NOT create new access paths without thinking if there is an alternative e.g. Using one that is similar and/or doing selection within the functions. If in doubt, talk it through with your DBA or a senior developer.

Virtuals should, in general, not be used, and should NEVER be on standard access paths. There may be times when they are the best solution e.g. For resequencing a query access path rather than creating a work file.

The description should try and explain the purpose of the access path.

In general there should only be 1 UPD (Update) style access path per file.

In general access path relations should NOT be dropped. If this is used then the default access paths should be clean and an alternative RTV or RSQ created.

No Virtual Virtuals. Avoid multiple nested levels of virtual fields if you are going to use them.

It is highly recommended that default access paths should never contain Virtuals or have Select/Omit. Use an alternative RSQ or RTV if virtual fields are deemed necessary.

If creating an access path over an assimilated file from another model then care must be taken with the default naming of the access path.

Next time we will talk about functions and I will provide some recommendations for naming standards as well as some standards for default functions.

Thanks for reading.
Lee.

Thursday, September 18, 2008

2E - Development Standards (That damn *Return Code ;-))

Yet another post debating some of the finer points of application development using CA 2E (Synon).

Over the years apart from justifying my use of 4GL's and model based development tools for rapid development of applications (CA 2E and CA Plex) to the non believers. Oh the arguements that this has caused have been blogged before. See my series on the 3GL v 4GL debate.

The biggest single point of contention from within the 2e community itself is relating to the correct usage and trust factor of the simply named field, "PGM.*Return Code". It may as well have been named Devil's spawn with the amount of hot air I have seen it generate.

For those that don't know, the return code is a floating variable within a program that indicates the current state of the program at the time it is queried? Roughly speaking

When programming a RTVOBJ as a full record fetch type function or as a check existence style function the developer generally has two options. They can either use the return code that is set implicitily by 2e (this can be overrideen by the developer) or declare an explicit field like Record Found Y/N and pass back a value indicating success or otherwise depending if the record was found.

Below I indicate the Pro's and Con's as I see them.

PGM.*Return Code Method

Pro's

A return code is the default way to test for success or otherwise when calling a program.

Requires no additional developer intervention as nearly all the 2e function types automatically set the return code to the appropriate value.

Con's

A Return code is a global variable within the function and is only as accurate as the last line of code that set it. If additional code is added between the called program and the testing point then the original context of checking the return code is broken. Therefore developer beware.

Explicit Field Method

Pro's

Means you can save the value in a LCL field.

If other code is inserted into the action diagram. As long as the value is not overridden you can check this value later in the action diagram or pass the value into another function.

Con's

Adds extra work to default functions that previously required no extra coding. i.e. a record existence check.

If you have two or more calls the original call may need to be stored. If this is required then the flag can be set on by querying the return code anyhow.

This approach doesn’t work for execute messages or user programs which would generally use a return code so the practice doesn’t fit all scenarios.

But what do i think?

Personally. I always preach the KISS principle and to use the tools as they were designed.
Therefore, you will see me using the return code out of choice, but I would as always, follow any incumbent standards even if they are wrong but I would definately have a go at explaining why they are wrong.......

Thanks for reading.
Lee.

Monday, September 8, 2008

2E - Development Standards (Ad-Hoc Tips)

One of my new colleagues has been reading these posts whilst he is learning to program in 2E.

This part is a collection of some general tips in 2E around Format Relations, Function Options, Function Wrapping and Sharing Subroutines.

As always, any comments good and bad are welcomed as are requests for subject matter.

Format Relations Considerations

For certain function types relations can be dropped (PMTRCD and PRTFIL). This is useful to make your functions as efficient as possible.

For other functions you will generally have the option to influence the amount of default code and functionality that will be generated by the 2E code generators by detailing the level of referential integrity you wish the function to have.

Careful consideration should be given to setting the format relations to the desired level. These are MANDATORY, OPTIONAL, USER, NO ERROR and of course, DROPPED. I fully recommend the best practice of RTFM.

Function Options

Most function options are self explanatory and most of us the industry standard which don't deviate too far away from the model defaults. Some function options in particular are important to understand how they are used.

Close down program when set to ‘Y’ will close the program. If this program is likely to me called repeatedly in an iteration or a data loop (i.e. RTVOBJ) then consideration should be given to setting this to ‘N’

Reclaim resources is generally set for functions that are on menu’s.

Share Subroutine. See chapter on setting this value.

Function Wrapping

Function wrapping is the process of converting snippets of action diagram logic into a standalone function. This can be either an EXCEXTFUN or an EXTINTFUN. By copying the action diagram code into the developers notepad you have the option to convert the code into the standalone function.

At this point 2e will create parameter interfaces for each of the function contexts that are used in the code snippet and reference these as duplicate parameters using the PR1 to PR9 special contexts.

Whilst this works perfectly well you will notice that the function parameter interface is quite unwieldy. If this is the case sometimes you might find it easier to build the function yourself. You choose?, flip a coin.

To minimise this, the developer must manually make alterations.

Review the fields in the WRK and LCL contexts and determine if they are local to the code snippet only or need to be passed into the new function. If local;-

Replace all action diagram logic referring to the PRx contect of the fields with WRK or LCL.
Remove unused fields from the parameter interface.
If it turns out thar all fields are not needed then remove the parameter line entry for the context.

Note the restrictions of the EXCEXTFUN and EXCINTFUN function types when wrapping code. This chapter will be coming soon.....

Share and share alike – Subroutines that is

Any internal database function can be generated as a shared or reusable subroutine. The system option (YSHRSBR) will be set to NO, therefore the individual function option must be used to identify a shared subroutine. Additionally an EXCINTFUN can be implemented as a subroutine rather than inline code and thus subsequently also shared.

The decision to make an internal function shared is subjective. In many cases there will be no particular advantage because the generated code is relatively small or because the number of times the function is called is small. Sharing a function will also in itself add extra lines of code for parameter passing.

You should only consider using shared subroutines where there is an obvious benefit in reducing the number of lines of generated code.

The answer to a large function with many lines of code may be to redesign the call structure rather than to just use the easy option of using shared subroutines. Note that a function called many times may not be the best one to make as shared. It may be a higher level function in the call structure, which will provide the most benefit.

A shared subroutine cannot cope with specific indicators. Therefore, a shared subroutine function should not send error messages to a screen. It will be unable to identify the correct screen field error indicator so that the field cannot be highlighted and the cursor cannot be positioned.

It is good programming style that any function, which has output parameters, should always perform a logic path that initialises or sets output fields. E.g. A RTVOBJ to GET attributes should initialise or set all output parameters whether a record is found or not. A shared subroutine will always cause the output fields to be set with some value but this is not the case if the subroutine is not shared. Thus if a subroutine is shared and contains output parameters that are not set they may contain unpredictable data.

An EXCINTFUN may be made into a subroutine but not necessarily shared. This enables a *QUIT to be added. The *Quit will jump to the end of the subroutine.

As a matter of best practice a model file's default CHGOBJ, CRTOBJ or DLTOBJ should remain unshared.

Next time the great PGM.*Return code debate.........

Thanks for reading.
Lee.