Serengeti logo BLACK white bg w slogan
Menu

A Trilogy on Breaking Free from Hardcoded Conventions

Boris Pavlović, Lead Developer
13.12.2023.

If The Lord of the Rings and The Hobbit could go into three installments, and even the original first three installments of Star Wars, why shouldn’t my story about hardcoding be a trilogy, so to speak. Or in sports language, especially in American sports, we go for the 3-peat.

The first blog is about Euro Introduction From the Perspective of a Developer and the second one talks about The Post Euro Conversion Syndrome Which Isn't.

The project I'm currently working on is related to the upgrade of the Oracle database, where it goes from version 12 to version 19, and that means some changes in the modules themselves, the way they work, and the like, so here I'll briefly refer to one thing I'm working on that should have worked and is currently working, which is the use of the directory as an object in the programming itself. Specifically, this is about the analysis and refinement of several hundreds of objects (packages, procedures, functions) in which paths to the file system were used (in the vast majority of cases, these same paths were hardcoded), where everything had to be changed in such a way that they no longer read paths, but directories.

And then we come to the main topic of this story, the hardcoded paths to countless places, which I have already written about in large part of the previous two installments of this trilogy of mine.

Let's take just this example, where not only is the variable not defined by a parameter, but it is also placed inside a subfunction in the package:

l_path := ‘/home/ftp/base/notifications’;

Now that we have a situation where such a variable appears in the package itself (package.pkg) in several subfunctions and in one such project, we come to a situation where this must be changed in several places multiplied by n times by n number of modules. If this was done in one place, where a global variable is defined at the package level, in its header, it would be enough to replace this hard-coded path with a parameter value and everything would be easier and simpler.

Considering that everything is easier to explain, and especially to understand with an example, let's start from the creation of the directory to its parameterization and integration into the package itself.

We will arrange the directory and the rights of who can access it and how:

CREATE OR REPLACE DIRECTORY

DIR_NOTIFICATION AS

'/home/ftp/base/notifications;

GRANT READ, WRITE ON DIRECTORY DIR_NOTIFICATION TO USER1;

GRANT READ, WRITE ON DIRECTORY DIR_NOTIFICATION TO USER2;

Enter the values ​​for the specified directory in the parameter table:

RBR := 1; NAME := ‘DIR_NOTIFICATION’;   PATH := ‘/home/ftp/base/notification;

Let's put together a function, for example, param_function, which will return the name of the directory for the received input value of the serial number, and essentially fill the global variable I wrote about with that function in one single place in the package itself (in its header):

g_path := param_function(1); -- ‘/home/ftp/base/notifications;

Since the new version of the database no longer knows how to work, so to speak, with paths, but has to work with directories, when calling the utl_file.fopen function at first glance, everything will remain the same, we replaced the variable l_path with g_path:

fh:=UTL_FILE.FOPEN(g_path, l_filename, 'w');

The only difference now is what happens 'under the hood', the new way is to go through the directory and no longer go through the hardcoded path, which in our case was still well written, if you can say that because it was defined in a variable. Let's consider the cases where the variable did not exist at all or was only partially defined, so we could have for correction examples like this where the utl_file call is also in several places:

fh:=UTL_FILE.FOPEN(‘/home/ftp/base/notifications, l_filename, 'w');

Well, let's say a subdirectory call with the connection of a variable in which there is a path with a hardcoded value:

fh:=UTL_FILE.FOPEN(l_path||’/out’, l_filename, 'w');

Conclusion

From this smaller example, you can see basically how many things have to be taken care of, how many seemingly small things can be encountered, things that need to be corrected because everything was done with hardcoded values. Even when it is taken into account that all this needs to be tested on one huge system, with several hundreds of these refined modules, we come to a project that is big and demanding and in which you need to pay special attention to seemingly small details, so I would finish this trilogy of mine as I started it, with one reminder so to speak.

Since I have learned many things the 'hard' way in my long career (you do something like this and then later you have more work to correct it than if you had done it right at the start), I will take the opportunity to state this as a reminder to myself and everyone engaged in this work that in these situations, we use more parameterization and domains wherever possible and as much as possible.

And yes, since I prefer trilogies to a frantic pile-up of sequels on the same topic, I'd say this is the end, or at least close to the end, of hardcoding and my writing about it. Of course, this does not mean that I will not continue to deal with these things in my professional life, correcting, changing, and parametrizing, but only that I will not write about it anymore, I hope. But since there are films whose fourth sequels have delighted me (Mad Max 4, for example, but I would still put it in the domain of the exception that proves the rule), I will remember the saying never say never and leave the window open for a possible fourth sequel.

Let's do business

The project was co-financed by the European Union from the European Regional Development Fund. The content of the site is the sole responsibility of Serengeti ltd.
cross