Question Standardize procedure and function

Hi Guys,

I'm actually working on standardize our code. And I already have some procedure/function that a use on many apps.

I'm thinking of unite them in one code to simplify the maintenance & reduce the number of programs.

I just don't know if I have to go for an include or a class type.

This is some exemple of function:
1. Display the time in function of the windows regional parameters (just a display, never save in the db)
2. Center text in FILL-IN

Do you have any advice ?

Also I want to do it for a bette integration inthe code.

Best-Regards,

- BobyIsProgress -
 

Cringer

ProgressTalk.com Moderator
Staff member
If you're doing a standardisation project then you might as well make it as future proof as you can, no matter what state the rest of the codebase is in.

Have a read of OO Design principles. In particular SOLID: SOLID Principles: Explanation and examples

In particular the single responsibility principle. It's completely pointless to build a library that does all sorts of things. Build a number of them that have a specific job.

And build classes. Includes are old fashioned, and hard to maintain. And if you include an include in code, you have no control over how much of it is included. You have to include it all. This leads to code bloat and hard to maintain monoliths.
 
Thank you @Cringer I will start to read this article. :)
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
I second Cringer's points. I strongly suggest you use classes rather than includes to encapsulate code. Includes can make it difficult to understand dependencies, to decompose a monolithic application into separate functional groups, and to do impact analysis.

We now have a rule that we only use includes for definitions of temp-tables and datasets.
 

TomBascom

Curmudgeon
It depends a bit on how old a Progress release you need to support but the OO 4gl is pretty solid for this purpose at least back to oe10.2.

If you need to go back deeper than that then you should use persistent super procedures rather than include files for library code.

Include files have not been the preferred option since roughly 1990 -- if I recall correctly version 5 introduced internal procedures which was the beginning of the end for include files. Persistent procedures came on the scene with version 7.3. After that no new include files should have been created to encapsulate behavior (shared definitions were still a reasonable thing to do).

Just for the record -- I have violated these rules and created include files that I should not have, so I am a bit of a hypocrite. But FWIW I regularly regret those decisions.
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
Just for the record -- I have violated these rules and created include files that I should not have, so I am a bit of a hypocrite. But FWIW I regularly regret those decisions.
You're certainly not alone there. ;)
 
Hi,

On the same subject. I want to create an external (don't know if procedure are class) that will run this code:
Code:
DEFINE VARIABLE cFld  AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cFile AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE saved AS LOGICAL     NO-UNDO.

     cFld = OS-GETENV("HOMEPATH") .
    
     cFld = cFld + "\Desktop":U .
     MESSAGE cFld
         VIEW-AS ALERT-BOX INFO BUTTONS OK.

    SYSTEM-DIALOG GET-FILE cFIle
        INITIAL-DIR cFld
        FILTERS "Csv File (*.csv)":U "*.csv"
        TITLE "Fichier d'enregistrement"
        SAVE-AS
        UPDATE saved .
    
    IF NOT saved THEN RETURN. /* Si retourne false alors l utilisateur a choisi de ne pas sauvegarder */
    
    
    FILE-INFO:FILE-NAME = cFile.
    
    IF NOT FILE-INFO:FULL-PATHNAME EQ ? THEN DO:
        MESSAGE "Le fichier existe déjà." SKIP
                "Souhaitez-vous l'écraser?"
            VIEW-AS ALERT-BOX INFO BUTTONS YES-NO UPDATE saved.

        IF NOT saved THEN RETURN.
    END.
The aim of this is to have a standardize way to extrat data to a file.

What are your advice on this ?

Best Regards,

- BobyIsProgress -
 

Cringer

ProgressTalk.com Moderator
Staff member
You'll probably want to create a FileHelper class which only has static methods in it. That way you can use it without having to NEW the class.
 
Do you have some example of a FileHelpre class, I'm struggling to find some :s
 

Cringer

ProgressTalk.com Moderator
Staff member
FileHelper is the name of the class. You can call it what you like. The key is that all the methods are static. Then you can just do
my.path.FileHelper:SaveFile ()
Or similar, without having to NEW the class.
 
So I write this class :

Code:
/*------------------------------------------------------------------------

  File: cxFileHelper.cls                                                             
 
 #Groupe : CLASS
 
 #Parent :
 
 #Enfant :
 
 #Type_application:
 
 #Table_consulté :
 
 #Champs_modifié :
 
 #Variable_Environnement :
  
------------------------------------------------------------------------*/

CLASS cxFileHelper :
    DEFINE PUBLIC VARIABLE path   AS CHARACTER NO-UNDO.
    DEFINE PUBLIC VARIABLE action AS LOGICAL NO-UNDO.

    METHOD PUBLIC VOID openFile ()  : /* Ouverture des fichiers  */

        SYSTEM-DIALOG GET-FILE path
            INITIAL-DIR homePath()
            FILTERS "Csv File (*.csv)":U "*.csv"
            TITLE "Fichier d'enregistrement"
            SAVE-AS
            UPDATE action .

        IF NOT action THEN RETURN.

        testfile() .
            
        
    END METHOD .

    METHOD PRIVATE CHARACTER homePath () :
        DEFINE VARIABLE fldpth AS CHARACTER   NO-UNDO.

        fldpth = OS-GETENV("HOMEPATH":U) + "\Desktop":U .

        RETURN fldpth .
    END METHOD.

    METHOD PRIVATE VOID testFile () :
        FILE-INFO:FILE-NAME = path.

        IF NOT FILE-INFO:FULL-PATHNAME EQ ? THEN DO:
            MESSAGE "Le fichier existe déjà." SKIP
                    "Souhaitez-vous l'écraser?"
            VIEW-AS ALERT-BOX INFO BUTTONS YES-NO UPDATE action.
        END.
        
    END METHOD.

END CLASS.
And in another procedure I want to try out my class. But i get error message 12886 .

Code:
USING cxFileHelper.* .

DEFINE VARIABLE maClass AS CLASS cxFileHelper NO-UNDO .
My class is located there: "C:\Silvercs.Mak10\specif\dev\vignal"
And this my list of Propath: "PROPATH=.\specif,.\specif\dev,.\specif\src,.\specif\group,.\patch,.\patch\src,.,.\src,C:\PROGRESS\DLC10,C:\PROGRESS\DLC10\bin,.\winfiles"

Do you have an idea?

Also is my class ok ?

Best Regards,

- BobyIsProgress -
 
Hi again, I found my issue so now:

My class:
Code:
/*------------------------------------------------------------------------

  File: cxFileHelper.cls                                                             
 
 #Groupe : CLASS
 
 #Parent :
 
 #Enfant :
 
 #Type_application:
 
 #Table_consulté :
 
 #Champs_modifié :
 
 #Variable_Environnement :
  
------------------------------------------------------------------------*/

CLASS src.classes.cxFileHelper :
    DEFINE PUBLIC VARIABLE path   AS CHARACTER NO-UNDO.
    DEFINE PUBLIC VARIABLE action AS LOGICAL NO-UNDO.

    METHOD PUBLIC VOID openFile()  : /* Ouverture des fichiers  */

        SYSTEM-DIALOG GET-FILE path
            INITIAL-DIR homePath()
            FILTERS "Csv File (*.csv)":U "*.csv"
            TITLE "Fichier d'enregistrement"
            SAVE-AS
            UPDATE action .

        IF NOT action THEN RETURN.

        testfile() .
            
    END METHOD .

    METHOD PRIVATE CHARACTER homePath () :
        DEFINE VARIABLE fldpth AS CHARACTER   NO-UNDO.

        fldpth = OS-GETENV("HOMEPATH":U) + "\Desktop":U .

        RETURN fldpth .
    END METHOD.

    METHOD PRIVATE VOID testFile () :
        FILE-INFO:FILE-NAME = path.

        IF NOT FILE-INFO:FULL-PATHNAME EQ ? THEN DO:
            MESSAGE "Le fichier existe déjà." SKIP
                    "Souhaitez-vous l'écraser?"
            VIEW-AS ALERT-BOX INFO BUTTONS YES-NO UPDATE action.
        END.
        
    END METHOD.

END CLASS.
My Procedure:
Code:
USING src.classes.*  .

DEFINE VARIABLE maClass AS CLASS cxFileHelper NO-UNDO .
DEFINE VARIABLE toto AS CHARACTER   NO-UNDO.
maClass = NEW cxFileHelper() .

maClass:openFile() .


MESSAGE maClass:path
    VIEW-AS ALERT-BOX INFO BUTTONS OK.
And it works very well.

So know I want to know if i'm using the best practice?

Best regards,

- BobyIsProgress -
 

Bounty

New Member
I don't want to start a lengthy discussion here. Everybody has his own style of coding, but what I would do:
1) Make "action" a local variable in the OpenFile function;
2) Let OpenFile return a LOGICAL (in this case variable "action");
3) Change "path" to a PROPERTY with GET and PRIVATE SET.

Code:
maclass = NEW cxFileHelper().
IF maClass:OpenFile() THEN
  MESSAGE maClass:Path VIEW-AS ALERT-BOX INFO BUTTONS OK.
 
Top