Ask Reuben
Genero Coding in 2024 (Reuben’s Commentary)
I can see the slides to a presentation at WWDC, what did you talk about?
At WWDC24, I gave a presentation titled “Genero Coding in 2024”. The abstract for the presentation was … One of our customers hired a Genero developer and commented that the coding style was reminiscent of the 90’s. So what does Genero code look like in 2024? Reuben will run you through some of the syntax that has been added to Genero that will make your development teams more effective and improve your Genero applications. In this article, I’d like to expand on some of the key points in that presentation. I would suggest opening the presentation, link here. or open it from the page , and have it open in another window as you read this article. I didn’t include this section in every presentation. I was never too sure how well it would travel in an English as a second language environment. I did initially look to include it at the end of the presentation but felt it might be better at the beginning to open developers minds to the story it tried to tell. For a long time I have been looking to take the grandfather’s axe story (or Triggers Broom as someone in the London audience pointed out) … … this is my grandfather’s axe and has served my family for many generations, we have replaced the blade X times, and the handle Y times … is this really your grandfather’s axe? … with an equivalent story that has many more dimensions to relate to the fact that your Genero System is made up of many facets … … and that one of the benefits of Genero is that you can modify or change out one of these components and you don’t have to rewrite or replace your entire Genero application. There are Genero customers that in the last 25 years have changed their user interface from TUI to GUI (Desktop) and now to GUI (Web), have changed from Informix to another database such as PostgreSQL and SQL Server, have changed operating systems from Linux to Windows, have changed their interfaces to other systems from flat files being passed backwards and forwards to using RESTful Web Services, and their Core Business Logic has been adapted for new business and government requirements. I found the Ship of Theseus after noting that the Wiki page for grandfather’s axe redirects to this page on the Ship of Theseus. To summarise the story of the Ship of Theseus .. How does this relate to Genero?, if no repairs were made to the Ship of Theseus it would one day not be able to participate in the parade and one day it might sink. If no changes are made to your Genero application, it will one day become irrelevant. Over time you need to be prepared to enhance the code base of your Genero application so that it stays relevant. The value proposition of Genero is that you can make those changes without having to rewrite your entire Genero application every time you want to change one of these components. A second introduction story I used for this presentation was a conversation I once had with a customer whereby the points of that conversation were … … afterwards I was thinking … is it Four Js responsibility to train the pool of Genero developers, or is it a companies responsibility to train and ensure the developers they hire code in the style applicable for their organisation? With regards to new syntax, features and best practices, we certainly have ability to … A number of customers have a quantity of lines of code that can be measured in millions, these lines of code should be an asset, but are in some places are a liability because they have not maintained the code base over time. For a number of the concepts introduced, I would show a simple snippet of code in the older style syntax, and then the same code using a newer syntax. In this syntax I was looking at functions and how they could be more explanatory using newer syntax… … there were two things to note here from syntax that was added in Genero 3.10. I would expect that in the 7 years since 3.10 was released in September 2017, that as part of maintaining your code base and keeping it modern, fresh and upto date, that your coding standard is to always use the fully-typed function parameter syntax and usage of the RETURNS clause. A secondary point in this area was to use the TYPE syntax that was added in Genero This was added in Genero 2.00. When passing complex data structures between two functions, you should not be defining the data structure independently in the caller and the called module. Instead use TYPE to define the structure the same in the caller and called module. As part of this introduction, a key concept to the ideas I will present is that if you mandate their use in your code base, how do you enforce that mandate? I like to tell the story of how where I worked before I joined Four Js I setup a daily build and smoke test. This ran in the early hours of the morning when the server was not being used and would … … it was typically the same developers whose desk I would visit in the morning to get them to rework the code they had checked in the day before to meet our coding standard. In those days I utlised sed, awk but they were limited in that they could only operate on a line of code, how did you check code standards that applied across multiple lines of code. In 2024, I would utilise the same technologies that our Code Quality tool uses. It produces an Abstract Syntax Tree (AST) and then uses XML methods to check that the resulting XML tree has the appropriate ancestors, descendants, and attribute values. What I would have shown is how the Code Quality tool uses fglcomp -Tx … (as seen here … … to produce this AST I would take a small code example that compiles and execute fglcomp -Tx on this .4gl and look at the resulting output. With Slide 13, you can hopefully see that a RETURNS clause adds a Symbol element with name=”ReturnsCl”. If this is mising as a child of a Symbol element with name=”Function” then we know that a RETURNS clause has not been specified. In two events, it was suggested can we add warnings to fglcomp, and have a refactor option to help adding RETURNS clauses to every FUNCTION in your code base which are sensible suggestions. I introduced this topic by putting up a small code sample and asking what is wrong with it? … the answer is that if you are to create a Web Service API to do the same data entry the user is doing via a screen, how can the Web Service resuse this code? It can’t, you end up with duplicated business logic, one for the program with the INPUT statement and one for the Web Service API. The better solution is seperate the User Interface and Business Logic code to something like the following … … now when creating your Web Service API, the web service program can call fieldname_valid(), and you only have the business logic defined in one place. I joined Four Js in 2008 but the company I worked for before then already had this separation of user interface and business logic in place, in fact it was there before our transformation to Genero. The other place where we had this separation was in our form definitions. We would not allow the usage of DEFAULT and INCLUDE in form definitions like this … … instead if it was expected that 100% of defaults and 100% of field validation was done via 4gl code so that it could be reused by API code. This made working on the programs a lot simpler as their was only one place you had to look for field default values and business rules. It also catered for the fact that business rules expressed as 4gl can be more complex than the rules defined by restricted syntax available in the .per (can you define the default value for a date as end of the current month in the .per, can your include validation rule to be 1,2 for normal users, and 1,2,3 for administrative users etc) Even NOT NULL, you had to be careful. If you relied on NOT NULL to force a value to be entered, you would not have that test in the 4gl, so it was a case of making sure the business logic code contained the test that a value was populated. NOT NULL was only to be used to change the characteristics of the GUI widget ie CHECKBOX two-state or three-state. This separation of user interface and business logic became an exercise in coding standards. The User Interface code, and the Business Logic code could be identified by their name (one contained _ui_ …) and the coding standard became that certain syntax was only allowed in 4gl filenames that matched that standard. For example, ERROR was only to be seen in 4gl whose filenames match *_ui_*.4gl. DEFAULT and INCLUDE were not allowed in .per etc. A goal when writing a Genero application is to consider the fact that with every piece of CRUD table maintenance it is feasible that not only will you want to do this CRUD table maintenance via the screen of a Genero application, you may also want to create a Web Service API to do this maintenance. Similarly every piece of transactional data entry, not only do you want to do this via the screen of a Genero application, you may also want a Web Service API to enter the transaction. This section was intended to the main focus of this presentation. The two previous section were a warm up to this section. The concept is that you should no longer be linking 4gl modules together but using IMPORT FGL. These concepts are out … These concepts are in … Why? Genero 2.00 involved a change that meant you no longer required to make a runner. Now in 2024 using Genero 5.00, you no longer need to link. The change in your codebase is that instead of relying on a Makefle or a .4pw or some other custom script in your build environment to say what modules are linked together to produce a Genero application, in a .4gl file, you add an IMPORT FGL statement to indicate that the symbols of this imported .4gl can be referenced inside your current 4gl Whilst not mandatory, it is suggested that where your code references these imported symbols, that the module that is imported is explicitly specified. This helps in the cases where a symbol is defined in two or more modules. In applying a change across your code base you have many helpers. Note the rules on implicit compilation and note the existence of –make and –output-dir options with fglcomp. if using Genero Studio, study the Genero and Genero (No Link) language options and study the build rules to see what commands these use. If you have not already I would certainly suggest you investigate moving to a model where you are 100% IMPORT FGL and no longer need to use the linker to produce a 42r. This and Responsive are the two areas I’d consider an upto date customer would be tweaking their codebase for currently. What we find is that Genero sites do a lot of work on the User Interface as part of their initial Genero transformation but there is little follow-up as we have added new UI features to Genero. If you have not already moved to Universal Rendering, then there will be some review required as part of the use of Universal Rendering and I’d suggest you take the opportunity to incorporate some newer User Interface syntax I could’ve include a lot more, TREE, Clickable Images, FOCUSONFIELD, Collapsible Group, Aggregates, Accordion, the list goes on. The point is to continuously review your application and the syntax we add with each release, and look to keep your application looking modern and fresh. Your application does not have to look legacy. The danger of looking legacy is that it will work against the retention of your application. Perception is everything, look modern it will be seen as modern, look old and your applications head will be on the chopping block. Even for ISV, although you don’t have the pressure to look modern in order to sell, you still have to earn the respect of your users so that they push for your applications retention. Similar to User Interface, we have over time made additions to the 4gl language. … when you could code … Not only will this use less memory but it also means that you don’t have to litter your code with code to handle the case if the user somehow generates a QBE with more than 1000 characters. Ideally your coding standard should be that any use of DEFINE … CHAR(X), you need to be able to justify the value that X takes. when you could code Again a DYNAMIC ARRAY will use less memory and you don’t have to litter your code with code to handle the case if you end up with more than 1000 rows in the array. Similarly you should be able to justify any static array with why it has that number of rows. Good examples might be 7 for days of the week analysis or 12 for months of the year analysis. The point is just as reviewing and using UI to keep your application looking modern and fresh, the same can apply to your code base. Keep reviewing it and adapting it so that your code looks modern and fresh.. If you see some code that looks long, clunky, unwieldy, repeated, chances are we have added some syntax to help you out. For some customers what I have said in this section, this is old news and they transformed their code years ago. For others, your code still looks like it could have been written last century. I didn’t really have time for this section but I wanted to cover it quickly to raise awareness. I know we have some customers who struggle to upgrade simply because of the volume of code they have to maintain, not helped in some circumstances because each of their customers has their own code base. Ask a Genero customer, how many lines of code they are responsible for, a typical answer will be expressed in millions. The more lines of code you have, the more difficult it is to make changes across your entire suite. There are a number of coding techniques you can use to reduce the maintenance effort involved in making changes across your entire Genero application. Code Generation is all about recognising these patterns and making the code base and the UX of these applications that fit each design pattern the same, so that you can quickly create another one and know that you can develop it quickly, and for the user to have the same experience. Then when you want to change something across all the programs with the same design pattern, make the change in the generator once, regenerate all programs and you are done. One point I didn’t cover in a slide was for ISV’s and how to reduce lines of code by not having a seperate code base for each customer. There are techniques ISV’s can use to reduce number of lines of code they have to maintain. These areas are my favourite topics, don’t be afraid to reach out to me if you feel you have too many lines of code. It is easy to talk about all these code changes you can make but how do you do it with minimal disruption to your customers. Like with us there are some things that can and only should only change in a major release. I won’t start without the following … I like to script changes, I don’t want to type the same thing 100 times if I can help it. With these scripts I find changes fall into some categories When I have done the work indicated by the TODO I remove the TODO. What I also do is give a change reference number next to each TODO. I can sum up the TODO’s to get an estimate of the work still required. When we make code changes we need to make sure that our hard work is preserved. Hence code standards need to be in place, adhered to, and controlled to make sure that old habits don’t make their way back into the code base. The second to last point I made was that the less lines of code you have to maintain, the easier it is to make code changes. Use Code Generators, Preprocessors, Generic Code to reduce the number of lines of code and apply changes quickly and consistently across your code base. Remove unused functionality, unused programs from your code base. Final point to finish was that a picture says a 1000 words. Who has a print out of their database structure, their program dependency on their office wall? Do you know that those Genero Studiuo diagrams can be printed onto multiple pages so you can make big posters? Who has a Style Guide that contains pictures of their applications and what the UI is supposed to look like. In this presentation I covered a lot of ground. I don’t expect you to do everything all at once, but hopefully I have opened your eyes. I do hope that you look after your code, treat it as an asset, sometimes that asset needs a polish, sometimes it needs some maintenance, and sometimes it can be left alone. If I look at customers who do well, I see a user interface that looks modern and code that is well maintained and kept upto date. If I look at customers who perhaps struggle, their User Interface looks old, and then when I look at their code it looks old as well.
Ship of Theseus
Introduction – A Conversation
Self Documenting Functions
#! old.4gl
FUNCTION add(a,b)
DEFINE a,b INTEGER
-- versus --
#1 modern.4gl
FUNCTION add(a INTEGER, b INTEGER) RETURNS INTEGER
...
gslintanalyse.4gl:133: CALL channel.openPipe(SFMT("fglcomp -Tx %1 \"%2\"", commandLineOptions, path), "r")
Seperate User Interface and Business Logic
INPUT BY NAME rec.*…
AFTER FIELD fieldname
IF rec.fieldname < 0 THEN
ERROR “Field must be positive”
NEXT FIELD fieldname
END IF
#! user_interface.4gl
INPUT BY NAME rec …
AFTER FIELD fieldname
CALL fieldname_valid(rec.fieldname) RETURNING ok, error_text
IF NOT ok THEN
ERROR error_text
NEXT FIELD fieldname
END IF
#! business_logic.4gl
FUNCTION fieldname_valid(fieldname…) RETURNS (BOOLEAN, STRING)
…
IF fieldname < 0 THEN
RETURN FALSE, “Must be positive”
END IF
RETURN TRUE, “”
END FUNCTION
EDIT f01 = formonly.field_name, DEFAULT=“Y”, INCLUDE=(“Y”,”N”), NOT NULL;
Building Projects with IMPORT FGL
User Interface
4GL
SELECT sin(x) INTO l_sinx FROM systables WHERE tabid = 1
to do trigonometry. If you still have clever hacks like that in your code, consider using the util.Math equivalent.
DEFINE where_part CHAR(1000)
...
CONSTRUCT where_part ...
DEFINE where_part STRING
...
CONSTRUCT where_part ...
DEFINE arr[1000] ARRAY OF ...
DEFINE arr DYNAMIC ARRAY OF ...
Advanced Concepts to Reduce Code
How To Make Changes
Summary