Showing posts with label Hint. Show all posts
Showing posts with label Hint. Show all posts

Synon 2E - Technical Deep Dives

Synon 2E - Technical Deep Dives

Below are some long form posts targeting specific areas of the Synon 2E tech stack.

I thoroughly enjoyed writing these 'back in the day' and hope that they help some of you.

The generic data driver is a method to output *Arrays into PRTFIL's or DSPFIL's without having to define a structure file etc.  Very, very useful and I have used numerous times.  The only design consideration is the array size depending on which RPG generator is being used. 


Performance tuning batch jobs?


Pet hates?

Some things that I don't like seeing in 2E coding.  Call them standards?, call them being a fusspot?

Code reviews, love them or hate them, they share knowledge and create better developers.

General Synon 2E topics, hints, tips, 'How to' guides.  They'll be a gem or two in here for most of you.

This should be standard in all shops

Nice little tips here

A personal favourite

Really useful, especially with the new webservices push and unpack and package up input and output arrays.

Thanks for reading the
Synon 2E and Plex Emporium by Lee Dare (A developer blog)
Lee.

Synon 2E - Standards posts all in one page

Synon 2E - Standards posts all in one page


Many of these were written years ago and google is gradually forgetting them.

Here is a summary of some of the technical posts I've made with lots of helpful hints, tips and development standards for Synon 2E, CA 2E and now Broadcom 2E.

This one is useful if you want to write performance code of reduce generator code bloat
https://leedare-plex2e.blogspot.com/2008/07/2e-development-standards-performance.html

Some general 2E coding standards


Some coding standards around action diagramming and usage of contexts
https://leedare-plex2e.blogspot.com/2008/08/2e-development-standards-ad-contexts.html
Naming Conventions?

More hints and tips, diving a little deeper into certain function
https://leedare-plex2e.blogspot.com/2008/10/2e-development-standards-hints-and-tips.html
Standards and hints for CHGOBJ/CRTOBJ composite functions

Screen function types and some standards to assist with solid development
https://leedare-plex2e.blogspot.com/2009/01/2e-development-standards-screen.html
Little tip with using cursor with subfiles
https://leedare-plex2e.blogspot.com/2019/01/a-little-trick-with-set-cursor.html

Thanks for reading the
Synon 2E and Plex Emporium by Lee Dare (A developer blog)
Lee.

Synon 2E *MOVE ARRAY 2E date and time fields

Synon 2E *MOVE ARRAY 2E date and time fields


UPDATE: 06/12/2025 - Linked to a summary post dedicated to deep dive long form posts.

Every 2E model has functions that are no longer required, yet they persist and continually get reused.  A good example of this common issue is the continued usage of legacy date conversion routines that exist in most 2E data models.

How many of you have the following functions (or very similar) in your model?

Function screenprint


The reason why is quite simple!
 
They were probably written long before 2E supported the date fields indicated.  After all, the DT8 (Date 8) and DT# (Date ISO) were added relatively late in the tools evolution.

I recall working at a company in London (pre 2000), who had solved the Y2K problem by transitioning their date fields from DTE to an user defined field type CDT (Century Date), this was basically a DT8 i.e. YYYYMMDD but implemented way before 2E had supported it.  I believe 2E were quite late to the party and implemented DT8 support around 1999.  Synon Inc started supporting the DT8 field specifically for people transitioning their models from DTE to DT8 and to help overcome any potential Y2K date rollover issues within their code.  There was even a model analysis tool that helped people identify these issues.

The problem is..... Many sites had already solved their issues (as above), whilst others stuck with the DTE format and its limitations and perhaps only targeted certain field like DOB.  I reckon there are dozens of sites around the world that continue to define dates as DTE out of habit!  I would be guilty of doing so for sure.

Anyhow, for those that have moved on and are defining DT8 or DT# or TS# (ISO Timestamp), I still believe that many programmers will be using the self coded legacy functions to perform date conversion.  I know I have too been guilty of this crime from time to time in the heat of coding.
 
The thinking goes something like this?

  1. Navigate to your system functions or date functions (scoping file DFN).
  2. Filter on Date or Convert (cnv) and pick the function that suites your needs.
  3. Test function and everything works fine.
  4. Great, Job done!

However, there is one small flaw with this.  You didn't need to use the legacy date conversion functions anymore.  Remember, these were likely written before 2E supported the source or target date format or have been written more recently by a developer who didn't realise that 2E already handles automatic date conversion between its (shipped) data types.
 
As long as you are moving data from a field type that is supported and that it has 'date like' data in it, 2E will automatically handle the conversion for you.

The table below (directly from the 2E online documentation) helps showcase all the automatic conversions that are handled by 2E and below that a table highlighting the limitations or rules.

 Synon documentation 1
 
* Conversions for the shipped D8# and the user-defined DT8 (8-digit internal representation) data types are identical.
 

Synon Documentation 2

What does this look like in the code?  Well let's take a look at some generated code to find out.

The following 'mock up' function is trying to covert the DTE (*JOB DATE) to a DT# (ISO) and DT8 format.

Synon AD

The source (RP4) for this is generated as follows:-

Synon to RPG

The ISO conversion is a little more complicated and is also generated into a subroutine so that it can be called for any date conversions from DTE to DT#.  The DTE to DT8 conversion is something I am sure you have done many times in code using the *ADD etc these are generated inline and not passed to a subroutine due to the small number of lines of code.

The subroutine code for ISO is below.

ISO Date DT#


A final point to note is that if you have a number field of 7.0 length masquerading as a date, you can move it into a date field DTE date.  Same with 8.0 to DT8, which will be more common if interfacing to data derived from more modern databases that never had a history of supporting dates like DTE or Julian.

You can then apply 2E date functions as usual.

Synon AD function

Finally, we are not limited to dates, times and their myriad of formats are also interchangeable.

Thanks for reading the
Synon 2E and Plex Emporium by Lee Dare (A developer blog)
Lee.

A little trick with *SET CURSOR

Neat trick to reposition on a record in a DSPFIL post page down and edit of said record.


Update: 05/12/2025 - I have created a page for all standards related posts.

A quick little post to kick off 2019....

A colleague of mine had an issue today where he was trying to stop a user having to page down dozens of pages when inserting data via a DSPFIL/PMTRCD W/W (Work with) suite.

He asked me how he can reload the subfile (show the new data) but position the page at the point he (the user) was at, rather than refreshing and defaulting back to the first page again....


The solution is quite simple and as the title of the blog says.......

You use the *SET CURSOR function and set it to a field on the subfile record you wish to remain in focus.  In our case we chose the *SFLSEL field.

Synon Action Diagram

Thanks for reading the
Synon 2E and Plex Emporium by Lee Dare (A developer blog)
Lee..

Synon 2e You have 'Function Options' you know....


Synon Action Diagramming guide relevant to function options


UPDATE: 06/12/2025 - Linked to a summary post dedicated to deep dive long form posts.

PODA PODA PODA PODA PODA PODA

One of the first things that are discussed when you did (if you did) the Action Diagramming course for 2E is PODA.

PODA is an approach to effective function design.

  • P is for parameters and the interface.
  • O is for options (Function Options)
  • D is for device design (Screen/Print)
  • A is for action diagram.

The concept being that these all influence the function and getting them correct will mean you’ll write less code and won’t be wrestling with the template (prototypes/patterns).

Bare this in mind for the rest of the blog post.

I was at work the other day and was maintaining some code where once again I could be heard saying, “Whoever wrote this should be shot!".  It’s my preferred (go to) phrase when I see badly written/designed/architect-ed code.

Anyhow in this instance the code was quite simple and generic so I can share it here.

Action Diagramming

The reason for my comment above was why is this code inside a subroutine called Subroutine?  The actual function ‘Perform Substitution’ was itself and EIF (Execute Internal Function).

I thought to myself, it is okay someone probably wanted to be able to *QUIT from one of the case blocks below…..  NO!!!

Hmmmm.......Perhaps someone was being a dunce!

Anyhow, depending on you model default and EIF can be generated as either inline code or as a subroutine.  I am thinking that this code might be quite old or that someone simply doesn’t understand how the code is generated in 2E. (Probably the later).

Most of you know that you can share subroutines and reduce code bloat using the ‘Share subroutine’ option.  And EIF also has an additional option called ‘Generate as subroutine’.

Synon Function Options

In the instance above we could have achieved the same result with omitting the sequence block and simply setting the value.

Let’s explore the generated code for a much simpler example.  I have an EEF (Execute External Function) calling and EIF.  The EEF is setting the local context for LCL.*JOB DATE to JOB.*Job Date and then calls the EIF which in turn set the WRK.*Job Date to JOB.*Job Date.

AD Code 1

AD Code 2

With ‘Generate as subroutine’ set to No we get inline code. (See below).

Generated RPG

Taking the original example (see top), if I put the internal code inside a Sequence block I’d get a subroutine. 

Ad Code 3

See code mock up below.

RPG Code

So although this code looks a little neater, it still isn’t perfect.

Setting the option Generate as subroutine’ to Yes generates slightly difference code.

RPG Code

Overall, in this instance it didn’t matter too much as there were NO *QUIT’s to worry about and the routines weren’t (or couldn’t) be shared etc.  But it does highlight that following PODA can make your programmer life easier, not to mention mine..... as I mop up after you....


Thanks for reading the
Synon 2E and Plex Emporium by Lee Dare (A developer blog)
Lee.

Synon 2E CHGOBJ It's not depressing so get suppressing!

CHGOBJ and NULL UPDATE SUPRESSION - What, Why and When to use!


UPDATE: 06/12/2025 - Linked to a summary post dedicated to deep dive long form posts.

Would you do work you didn’t need to do?  NO would be the obvious answer right!!!  That said there are probably thousands of 2E programs out there that are doing unnecessary updates to a database using a CHGOBJ.

Many of these programs have been working seamlessly for years and years, however, they are like a volcanic field.  Stable for years, centuries or even millennia but then one day……BOOM!!!!

This isn’t because they are really badly coded.  After all, we should only be updating one record at a time etc.  Most CHGOBJ’s are probably inline (i.e. a screen or a single instance business transaction). 
Mass bulk updates being the lesser spotted usage for a CHGOBJ.  But it does happen!

Recently we had an issue where a long standing bulk update processing program (EOD) went from executing in  sub 1 minute (so it didn’t get too much love in the maintenance department) to almost 30+ minutes (overnight).

Upon first inspection, the program hadn’t changed.  This points to an environmental based solution.  The dataset or data volume hadn’t significantly changed either….  The subsystems configs hadn’t changed and there was no system resourcing issues or spikes…..

The simple reason for the increase was that a new trigger (2E) was added to the file being updated, this trigger had a little business logic and this was required processing.  There was limited tuning to be done in the trigger program.

However, I did notice that the data was summary statistical style (reporting categories for data like current balance etc).  This was being recalculated each night and updated on an account by account basis.

On closer inspection of the rules around the categorisation it was obvious that the vast majority of accounts stayed in their categories for years and years and only with major events in the accounts lifecycle did they switch.  This mean that the activity was effectively calculating the same values each night and then updating the fields in the file every night with the same values.  This in turn NOW triggered additional functionality with a real-time trigger.

Option 1.

It was quite obvious by now that we needed to stop the execution of the trigger.  We didn’t have the option of removing and reading the triggers after the process.  The simplest method was to not perform the database update in the first instance.  This can be done by simply comparing the newly calculated values with the those on the database record and NOT call the CHGOBJ.

This method works and is relatively easy for a developer to read the action diagram and ascertain what is happening and on the surface seems like a good option.  I have seen this done in many functions.

However, the developer must (potentially) do a read to compare to the database.  This data may itself be old (retrieved much earlier in the cycle).  The developer needs to do this everywhere the CHGOBJ is used.

Option 2.

Code could be added inside the CHGOBJ to exit if DB1 and PAR are the same.  I’ve seen this approach too.  This is a bit cleaner but for any functions creates since 6.1 of 2E (last century) this is also the incorrect approach.

Option 3.

The correct approach in this instance is to switch on a function option on the CHGOBJ and utilise the built in suppression code relating to Null Update Suppression. (See highlighted options below).



Function Options


The options are quite simple.
M -  is the default model value.  In this model it is ‘N’ so this implies NO suppression will occur.
Y  - means that the DB1 will be checked against PAR twice.  Once upon initial read of the data from the file and then once the record lock is in place and that data is about to be written.
A  - (After read) only does the first part (see above).

The generated code

The diagram below gives a visual of the code that is generated for each of the options.

Code generation


NULL Update Suppression works regardless of how you define CHGOBJ’s

Work with
Works with:- 
  • Default CHGOBJ's
  • Neither dropped CHGOBJ's
  • KEY/RCD dropped CHGOBJ's
  • Shared Subroutines.

There really isn't an excuse not to implement these options.

Benefits of the suppress option for CHGOBJ.  
  1. Record level audit stamps won’t get corrupted with unnecessary update.
  2. Performance.
  3. Triggers won’t get fired unnecessarily.
  4. Encapsulated.

Null Update Suppression

Thanks for reading the
Synon 2E and Plex Emporium by Lee Dare (A developer blog)
Lee.