Me dedico al desarrollo de software desde hace dos décadas y he tenido 
oportunidad de leer muchas opiniones sobre los criterios que deben regir la 
construcción de un programa de servicio (DLL en Windows, o biblioteca de 
funciones en Unix/Linux). Yo llego a la conclusión de que cualquier criterio es 
bueno y, dependiendo de la situación, optas por una solución u otra.

Por ejemplo, en mi caso, tengo cuatro o cinco programas de servicio 
“generalistas” que utilizan casi todos los programas ILE. Esto no significa que 
utilicen toda su funcionalidad. Tengo la sensación que es más cómodo unirlos 
todos en un solo programa de servicio, que me será más cómodo su mantenimiento 
y se cargarán más rápido en memoria ¿?. En cambio tengo otros específicos de 
una parcela de la aplicación que permanecerán “aislados”. Posiblemente me 
equivoque, pero probaré.

Desde mi punto de vista, el mantenimiento de un programa de servicio no me 
genera mucho más trabajo que la de un programa. Por ejemplo, dispongo de un 
programa de servicio de manejo de fechas (como tú), compuesto por tres módulos: 
manejo de fechas, manejo de periodos de tiempo y un cronómetro. La interfaz 
está definida con el lenguaje de enlace (BND) y una “signatura”.

Si tengo que añadir una nueva función hago lo siguiente:


1.    Decido cual es el módulo que contendrá la función. No importa la posición 
en el fuente. La puedes codificar en cualquier sitio: al final, principio, por 
el medio.

2.    Añado el prototipo en el miembro fuente que incluyo en mis programas 
(/COPY). Normalmente hay uno por programa de servicio.

3.    Añado la función al final de la lista del lenguaje de enlace (BND). 
¡Ojo!, siempre al final. No cambio la “signatura”.

4.    Recompilo el módulo (CRTRPGMOD).

5.    Actualizo el programa de servicio (UPDSRVPGM).

Sólo recompilo el programa de servicio si añado un módulo más o cambio por 
completo su interfaz.

Para mí, el directorio de enlace es una mera herramienta que me facilita la 
compilación de los programas.

Saludos,

Javier

De: [email protected] 
[mailto:[email protected]] En nombre de alberto
Enviado el: miércoles, 19 de agosto de 2015 7:45
Para: forum.help400
Asunto: RE: Procedimientos en programas de servicio

Muchas gracias Javier, son consejos para tener en cuenta.
Respecto a la última cuestión que planteas, creo que juntarlos todos en uno 
sólo, o quizá hacer varios por temas, sólo beneficia por el tema de tenerlos 
ordenados, pero eso es una cosa muy pero que muy subjetiva.
Lo que sí está claro es que el mantenimiento y creación de programas de 
servicio es farragoso de narices, y cuanto más agrupados estén, mejor.
 Pero igualmente nos podemos encontrar con una situación: tener creado un 
programa de servicio desde hace años, de por ejemplo..fechas, y te sale la 
necesidad de crear una función nueva que te devuelva por ejemplo el dia de la 
semana que corresponde a una fecha...qué harías tú?  lo creas todo de nuevo? o 
creas un programa de servicio nuevo y lo metes en el mismo directorio de enlace 
y ya está?
Salu2




De:        Javier Mora <[email protected]>
Para:        "'forum.help400'" <[email protected]>
Fecha:        18/08/2015 13:08
Asunto:        RE: Procedimientos en programas de servicio
Enviado por:        [email protected]
________________________________



Algunos consejos:

1.    Utiliza siempre las “especificaciones de exportación” (tipo de fuente 
BND) para definir claramente la interfaz (o lista de procedimientos) del 
programa de servicio y dale una “signatura” (o identificador de nivel).
2.    Añade siempre los nuevos procedimientos al final de la especificación de 
exportación (igual que lo harías cuando añades un campo nuevo en un fichero). 
No es necesario cambiar la “signatura”.
3.    Todos los procedimientos de la interfaz del programa de servicio e 
incluidos en la “especificación de exportación” deben definirse con la palabra 
clave EXPORT (como lo haces ahora).
4.    Si cambiaras el orden de los procedimientos en las “especificaciones de 
exportación” sin cambiar la “signatura” los programas que utilicen el programa 
de servicio no generarán un mensaje de escape, pero empezarán a tener un 
comportamiento extraño.
5.    El orden de los procedimientos en el código fuente no es importante, 
siempre y cuando se mantenga el orden original en las “especificaciones de 
exportación”.
6.    La palabra EXPORT se puede utilizar en procedimientos que no aparezcan en 
la interfaz del programa de servicio. ¿Qué interés tiene esta técnica? No tiene 
ningún sentido en un programa de servicio con un único módulo pero cuando esté 
compuesto por más de un módulo, los procedimientos EXPORT son visibles entre 
módulos.
7.    No construyas programas de servicio ni muy grandes (gigantescos ni muy 
pequeños). Piensa que el programa que los use tendrá que cargarlos en memoria 
la primera vez que se necesiten y quedará residente hasta que finalice el 
trabajo. ¿Qué es grande o pequeño? Es bastante subjetivo y te lo señala tu 
propia experiencia.
8.    Intenta agrupar en un programa de servicio procedimientos con una 
funcionalidad similar: por ejemplo, funciones de fecha, manejo de cadenas de 
caracteres, gestión de excepción/errores, listas enlazadas, etc.

Con el tiempo, me he dado cuenta que hay una serie de funciones que 
prácticamente se usan en casi todos los programas: fechas, cadenas de 
caracteres o manejo de excepciones (entre otras). En estos casos me planteo 
juntarlas todas en un solo programa de servicio, pero no tengo muy claro si 
hago bien o mal. Ni en qué me beneficia o perjudica.

Un saludo,

Javier

De: [email protected] 
[mailto:[email protected]] En nombre de alberto
Enviado el: martes, 18 de agosto de 2015 12:05
Para: forum.help400
Asunto: RE: Procedimientos en programas de servicio

Buenas.
Pues sí que has aclarado. era yo que lo estaba haciendo mal.
En las funciones, se define el parámetro a nivel de componente y se pone el 
EXPORT:
P Fun021i         B                   EXPORT
D Fun021i         PI             8  0
Pues yo me había empeñado en no poner tampoco el EXPORT cuando no había que 
definir el parámetro, (como cuando retorna más de un valor).
P Fun022i         B
D Fun022i         PI

Salu2 y gracias



De:        Javier Mora <[email protected]>
Para:        "'forum.help400'" <[email protected]>
Fecha:        18/08/2015 11:06
Asunto:        RE: Procedimientos en programas de servicio
Enviado por:        [email protected]
________________________________




No he entendido muy bien tu problema. A modo de resumen, RPG no entiende o 
distingue entre funciones o procedimientos, todo son subprocedimientos. 
Nosotros podemos diferenciarlos como: funciones o procedimientos. Realmente, lo 
único que los diferencia es que las primeras pueden formar parte de expresiones.

Por ejemplo, una función típico que yo uso frencuentemente es:

   /**
    *  IsLeapYear()
    *
    *  Comprobar si el año es bisiesto.
    *
    *  Parámetro      Uso  Descripción
    *
    *  date            E   Una fecha cualquiera.
    *
    *  Valor retorno: *ON si el año es bisiesto.
    *                 *OFF en caso contrario.
    */

    P IsLeapYear      B                   Export
    D IsLeapYear      PI              N
    D   date                          D   Const

    D year            S             10I 0
     /FREE

      year = %Subdt( date: *YEARS );

     // Los múltiplos de 100 deben ser divisibles entre 400
      If %Rem( year: 100 ) = 0;
         Return  ( %Rem( year: 400 ) = 0 );
      Else;
         Return  ( %Rem( year: 4 ) = 0 );
      Endif;
      Return  *OFF;

     /END-FREE
    P IsLeapYear      E

Que me devuelve *ON si el año de la fecha pasada es bisiesto u *OFF en caso 
contrario.

Un procedimiento típico en mi instalación podría ser este:

   /**
    *  ConvertCase()
    *
    *  Convertir a mayúsculas o minúsculas una cadena de caracteres.
    *
    *  Parámetro      Uso  Descripción
    *
    *  inStr           E   Expresión de tipo cadena para convertir a
    *                      mayúsculas/minúsculas.
    *  inStrSize       E   Tamaño en bytes de la cadena de entrada.
    *  outStr          S   Cadena que recibirá la cadana convertida.
    *  outStrSize      E   Tamaño en bytes de la variable que recibirá
    *                      la cadena convertida.
    *  o_option        E   Tipo de conversión:
    *                      0 = a mayúsculas (valor por defecto)
    *                      1 = a minúsculas
    *  o_ccsid         E   Identificador del juego de caracteres con
    *                      el que está codificada la cadena 'inStr'.
    *
    *  Valor retorno: Ninguno.
    */

    P ConvertCase     B                   Export
    D ConvertCase     PI
    D   inStr                             Const Like( TypeBuffer2 )
    D                                           Options( *VARSIZE )
    D   inStrSize                         Const Like( INT4_T )
    D   outStr                                  Like( TypeBuffer2 )
    D                                           Options( *VARSIZE )
    D   outStrSize                        Const Like( INT4_T )
    D   o_option                          Const Like( INT4_T )
    D                                           Options( *NOPASS )
    D   o_ccsid                           Const Like( INT4_T )
    D                                           Options( *NOPASS )

    D PARM_OPTION     C                   5
    D PARM_CCSID      C                   6

    D rcb             DS                  LikeDs( NLS_reqCtlBlk_ccsid_T )
    D error           DS                  LikeDs( ERRC0100_T )

    D minLen          S                   Like( INT4_T )
     /FREE

     // Si no se indica el tamaño de la cadena de entrada ni
     // la de destino no es necesario realizar la conversión
     // ni ninguna otra cosa.
      If  inStrSize <= 0 Or outStrSize <= 0;
         //Si interesa, ¡aquí podría lanzarse una excepción!
         Return;
      Endif;

     // Si la cadena de entrada sólo contiene blancos, no hay
     // conversión, se devuelven los mismos blancos.
      If  %Subst( inStr: 1: inStrSize ) = *BLANKS;
         %Subst( outStr: 1: outStrSize ) = *BLANKS;
         Return;
      Endif;

     // Configurar el bloque de control para la conversión.
      rcb = *ALLx'00';
      rcb.reqType = 1;            // Conversión por CCSID
      If  %Parms() >= PARM_CCSID;
         rcb.ccsid   = o_ccsid;
      Else;
         rcb.ccsid   = 0;         // Usar el CCSID del trabajo
      Endif;
      If  %Parms() >= PARM_OPTION;
         rcb.caseReq = o_option;
      Else;
         rcb.caseReq = STR_TO_UPPER;
      Endif;

     // El tamaño más corto de los parámetros determina cuantos
     // caracteres se van a convertir
      minLen = Min( inStrSize: outStrSize );

     // Convertir los datos
      Clear  error;
      QlgConvertCase( rcb
                    : %Subst( inStr: 1: minLen )
                    : outStr
                    : minLen
                    : error
                    );
      If  outStrSize > minLen;
         %Subst( outStr: minLen+1: outStrSize-minLen ) = *BLANKS;
      Endif;
      Return;

     /END-FREE
    P ConvertCase     E

Como puedes ver tiene 6 parámetros y uno es de salida (outStr). En otros 
procedimientos podrían ser más.

En ambos casos (función y procedimiento) se define el subprocedimiento como 
EXPORT y también se añaden a la lista de procedimientos exportados (tipo de 
funente BND).

Espero haber aclarado un poco tus dudas.

Saludos,

Javier

De: [email protected] 
[mailto:[email protected]] En nombre de alberto
Enviado el: martes, 18 de agosto de 2015 9:18
Para: forum.help400
Asunto: Procedimientos en programas de servicio

Buenas. Estoy reorganizando el tema de subprogramas, rutinas o como le queramos 
decir, y estoy haciendo funciones con ellos y creando programas de servicio.
Para las funciones con un valor EXPORT, no hay problema, pero claro, tengo 
muchos subprogramas de estos que me devuelven varios parámetros, vamos, que son 
procedimientos normales, no funciones. Estos no sé cómo meterlos (ni si se 
puede) en programa de servicio, ya que al no tener un campo EXPORT no los puedo 
meter en el fuente *BND.
No he encontrado ningún ejemplo que lo haga, ni tampoco he encontrado nada que 
me diga que no se puede hacer.
Me podéis decir si se puede hacer, y en caso afirmativo, cómo?
Simplemente, crear un programa de servicio con un procedimiento que devuelva 
varios parámetros.
Gracias____________________________________________________
Únete a Recursos AS400, nuestra Comunidad ( http://bit.ly/db68dd )
Forum.Help400 © Publicaciones Help400, S.L. 
____________________________________________________
Únete a Recursos AS400, nuestra Comunidad ( http://bit.ly/db68dd )
Forum.Help400 © Publicaciones Help400, S.L.
____________________________________________________
Únete a Recursos AS400, nuestra Comunidad ( http://bit.ly/db68dd )
Forum.Help400 © Publicaciones Help400, S.L.

Responder a