jueves, 2 de mayo de 2013

ILE. Conceptos

Pero realmente ¿qué es?

Podéis buscar el acrónimo en cualquier libro de Ibm pero creo que eso no es lo interesante. Desde mi punto de vista, ILE es una estrategia de diseño de aplicaciones. Para que sea útil debe estar concebido en el momento del diseño.

La estrategia de diseño de aplicaciones con ILE no es nueva. Se basa en algo tan antiguo como "el divide y vencerás". Las cosas pequeñas son más fáciles de gestionar y mantener... ¡y reutilizar!
Antiguamente hacíamos programas larguísimos (monolíticos con miles de líneas de código) donde estaba todo el código de cualquier funcionalidad compleja. Así el desarrollo era muy complejo pero peor era el mantenimiento ya que añadirle cualquier nueva funcionalidad era muy pesado en un programa tan grande. 
Toda esta problemática la podemos solventar realizando pequeñas funcionalidades en diferentes objetos y después mezclar todos estos objetos en un ejecutable. Esto lo permite ILE con sus piezas pero lo realmente importante es definir la división en pequeñas funcionalidades. 
Desarrollar funciones pequeñas es mucho más sencillo que realizar megaprogramas y cualquier modificación posterior es infinitamente más sencilla.

En este primer artículo trataré los conceptos que dan forma a ILE y en sucesivos artículos indicaré la estrategia de diseño que he adoptado con el objetivo de facilitar el desarrollo de aplicaciones y mejorar el mantenimiento de aplicaciones.

¿De que esta compuesto?


Se basa en cuatro conceptos:
  • El primero no tiene un nombre definido ya que en sí no es un objeto del sistema operativo. Lo podemos conocer como componente, prototipo (o incluso método acercándolo a la denominación de otros lenguajes de programación) .
  • Módulo (*MODULE)
  • Programa de servicio (*SRVPGM)
  • Programa (*PGM)

Componente

Un componente serían unas líneas de código (en general relativamente pocas) que realizan una funcionalidad concreta. Por ejemplo, calcular una determina tasa asociada a un importe. 
Permite recibir un conjunto de parámetros de entrada y permite, opcionalmente, devolver un conjunto de parámetros de salida
Ejemplo de código de componente que recibe dos parámetros y devuelve como función un valor.
     PCalculaTasa      B
     DCalculaTasa      PI            15  4
     D Importe                       15  2 Const
     D Pais                              3 Const

     D W_Tasa          S             15  2
      /Free
         //Calcula los impuestos
         Select;                    
           When Pais = 'ESP'; // España
             W_Tasa = Importe / 12;
           Other;             // Para cualquier otro pais
             W_Tasa = Importe / 10;
         EndSl;    
         Return W_Tasa;
      /End-Free
     P                 E

Para completar la definición es necesario lo que se conoce como un prototipo que simplemente es la definición de la interfaz de llamada para que pueda ser conocida desde el fuente desde donde se utiliza.

Ejemplo de prototipo
     PCalculaTasa      B
     DCalculaTasa      PI            15  4
     D Importe                       15  2 Const
     D Pais                              3 Const



Desde el fuente donde se desea utilizar habría que añadir la llamada a la funcionalidad
Ejemplo de llamada. Llama a la función pasándole el valor del importe y el país y devolverá el calculo sobre las variables Tasa1 y Tasa2
         Tasa1 = CalculaTasa(WImporte : 'ESP');
         Tasa2 = CalculaTasa(WImporte : 'FRA');


Interno o Externo



Atendiendo a su ámbito, pueden ser internos a un fuente, es decir, su ámbito de ejecución es solo en el fuente en el que está definido o externos de forma que pueden ser llamados desde otros fuentes. Por aproximación, los  internos vendrían a sustituir o serían como las rutinas internas (exsr). En los internos el código del componente y el prototipo están en el mismo fuente que lo utiliza y en los externos, el fuente que lo utiliza SOLO tiene el prototipo. 
Para facilitar la modificación e inserción los prototipos se suelen poner en un fuente /Copy y se inserta en el fuente que lo necesita.

El ejemplo anterior sería interno ya que en la definición del componente no aparece la clave EXPORT. Así para poder convertirlo en externo habría que poner dicha clave a nivel de definición.
     PCalculaTasa      B                   Export


Función y procedimiento

El componente se puede definir de dos formas; como función cuya diferencia es que devolverá un determinado valor de un tipo o como procedimiento
Para definirlo como función es necesario declarar el tipo de valor a devolver sobre el nombre de la función y además deberá tener al menos una instrucción return que finalizará la ejecución del componente y devolverá el valor a quién le llamó.

Ejemplo de definición de función con parámetro de retorno numérico de 15,4
     PCalculaTasa      B
     DCalculaTasa      PI            15  4
     D Importe                       15  2 Const
     D Pais                              3 Const

     D W_Tasa          S             15  2
      /Free
. . . 
         Return W_Tasa;
      /End-Free
     P                 E


Ejemplos de uso de la función desde cualquier proceso

         Tasa1 = CalculaTasa(WImporte : 'ESP');
         If CalculaTasa(WImporte : 'FRA') > 1000;
. . .


Para definirlo como procedimiento, NO debe tener definición de parámetro a nivel de nombre de componente y no se puede utilizar la instrucción return. Por otra  parte se pueden definir n parámetros de salida.


Ejemplo del mismo código de componente como procedimiento
     PCalculaTasa      B
     DCalculaTasa      PI            
     D Importe                       15  2 Const
     D Pais                              3 Const
     D Tasa                          15  2
      /Free
         //Calcula los impuestos
         Select;                    
           When Pais = 'ESP'; // España
             Tasa = Importe / 12;
           Other;             // Para cualquier otro pais
             Tasa = Importe / 10;
         EndSl;    
      /End-Free
     P                 E



Ejemplos de uso del procedimiento desde cualquier proceso 

         CalculaTasa(WImporte : 'ESP' : Tasa1);
         CalculaTasa(WImporte : 'FRA' : Tasa2);
         If Tasa2 > 1000;
. . .


Parámetros

La ventaja de los componentes es la facilidad de gestionar los parámetros de entrada y de salida y la potencia que les aporta ya que incluso permite definir un parámetro opcional facilitando su llamada desde otros objetos (incluso cuando se modifica)
Los parámetros pueden ser de entrada y salida. Para ello se definen que se "pasen" por valor o por referencia. Si se pasan por valor (se definen como const) no se podrán modificar pero si se definen por referencia, se podrán modificar en el código interno del componente y así se devolverán al que le llamó.

También se pueden definir parámetros como opcionales, es decir, que desde donde se le llame al componente se informe ese parámetro o no. Una de las posibilidades es utilizando options(*nopass) como clave. Lo único es que el componente debe estar preparado en su código para recibir solo parte de los parámetros y para ello utilizaremos la BIF %Parms que nos indicará el número de parámetros que se reciben. Internamente SOLO podremos utilizar ese parámetro si se ha recibido. Si intentamos utilizarlo sin haberlo recibido, obtendremos un error. Por ello se utiliza %Parms para conocer si lo podremos utilizar.
Esto es útil cuando se van variando componente a lo largo de la vida pero no se tienen que "tocar" todas las llamadas que se estuvieran haciendo en otros procesos.

Siguiendo el ejemplo, supongamos que ahora hay una nueva versión del componente  que permite recibir un descuento para el calculo de la tasa pero hay mucho programas que lo utilizan que deberían seguir comportándose igual y sin cambiarse.


Ejemplo de la nueva versión del componente

     PCalculaTasa      B
     DCalculaTasa      PI            15  4
     D Importe                       15  2 Const
     D Pais                              3 Const
     D Descuento                     15  2 Const Options(*Nopass)

     D W_Tasa          S             15  2
     D W_Descuento     S             15  2
      /Free
         If %PARMS>=3;
           w_Descuento = Descuento;
         Else;
           w_Descuento = *Zeros;
         EndIf;
         //Calcula los impuestos
         Select;                    
           When Pais = 'ESP'; // España
             W_Tasa = (Importe - w_Descuento) / 12;
           Other;             // Para cualquier otro pais
             W_Tasa = (Importe - w_Descuento) / 10;
         EndSl;    
         Return W_Tasa;
      /End-Free
     P                 E


Las llamadas antiguas seguirán funcionando perfectamente sin tener que modificar el código.

         Tasa1 = CalculaTasa(WImporte : 'ESP');
         If CalculaTasa(WImporte : 'FRA') > 1000;
. . .



Y se  podrán codificar nuevas llamadas con los nuevos parametros

         TasaX = CalculaTasa(WImporte : 'ESP' : wDescuento);
. . .




Módulo

Es un objeto compilado en el sistema operativo (*MODULE). Resulta de la compilación de un fuente de un lenguaje determinado y preparado para ILE (Rpg, Cobol, Cl, etc.)
Un módulo en si mismo NO es ejecutable. Se utiliza para recopilar una o varias funcionalidades en un fuente. Un modulo puede "llamar" a otro modulo. Utilizo los módulos para:

Módulo de componentes. Incluir en él varios componentes "relacionados". Imaginemos un conjunto de rutinas reunidas en un módulo. Por ejemplo, que tuviera la rutinas del cálculo del Pvp, del cálculo del Iva, del cálculo del descuento x, etc. Es decir, tendría los fuentes de los n componentes.
Estos componentes serán externos (EXTPGM) para que puedan ser utilizados  desde otros fuentes.
Módulo con componentes

Módulo de pantalla. Hacer la funcionalidad de uso de una pantalla. Por ejemplo, tengo un módulo para presentar un subfichero de registros de la lista para un mantenimiento, tengo otro módulo para realizar el mantenimiento de un registro, etc.
Es decir, divido las funcionalidades visuales de una aplicación para poner una ventana en cada módulo.
Desde el punto de vista de desarrollo y mantenimiento es más sencillo (y reutilizable) hacer un fuente con cada pantalla y que se llamen entre ellos que hacer un solo fuente con n pantallas (monolítico). Lógicamente tener en un solo fuente TODOS los procesos y flujos relacionados con varias pantallas es muchísimo más complicado que tener un fuente en cada modulo por cada pantalla, mas acotado, simple y controlado y sin mezclarse datos ni flujos, ni variables.
Esto es posible por que llamadas entre módulos se resuelven en tiempo de compilación por lo que es como si fueran rutinas internas y por lo tanto NO degrada la ejecución.

Fuente monolítico vs. módulos





Programa de Servicio

Es un objeto en el sistema operativo (*SRVPGM). Resulta de "unión" (link) de uno o varios módulos y opcionalmente otros programas de servicio.
Los programas de servicio permite "encapsular" funcionamiento y rutinas que se utilizarán en varios programas. NO es ejecutable por si mismo.

Después desde un programa se utilizará el programa de servicio llamando a las rutinas o componentes comunes.

Programa de servicio


En una estrategia correcta en un programa de servicio se deberían incluir aquellos componentes que puedan ser utilizados en varios programas. Después se crearan programas ejecutables que utilicen los componentes de ese programa de servicio.

Las ventajas adicionales que tienen los programas de servicio es que, con cierto cuidado, se puede modificar el código e incluso incluir nuevos componentes ¡sin tener que compilar los programas donde ya se esta utilizando!  
Los programas de servicio tienen una especie de lvlchk denominado signature que identifica una determinadas características que tenía el programa de servicio cuando se creó. Además, un programa de servicio puede (a través de un lenguaje especial Binder) almacenar todas las signatures de las diferentes características por las que ha ido cambiando el programa de servicio. 
Cuando se ejecuta un programa que tiene asociado un programa de servicio, lo primero que se revisa es que la signature que tiene almacenada el programa con referencia al programa de servicio está entre las signature que tiene el programa se servicio. En caso contrario, dará error y no se ejecutará el programa. Lo que significa esto es que la revisión de los componentes incluidos en un programa se servicio que son utilizados por un programa se realiza en tiempo de ejecución. 

Cuando un programa utiliza un programa de servicio, en tiempo de ejecución, se carga el programa de servicio en memoria y se realizan las acciones necesarias para inicializarlo. Esto tiene un coste en tiempo de ejecución pero mucho menor que el coste de ejecución que ocurre cuando  un programa llama a otro programa.


Programa ILE

Es un objeto en el sistema operativo (*PGM). Resulta de "unión" (link) de uno o varios módulos y opcionalmente programas de servicio. Es el objeto ejecutable.


Programa
Un programa tiene un punto de acceso que la rutina principal por donde comienza la ejecución del programa. Cuando se ejecuta el programa, revisa que los programas de servicio que tuviera asociado son correctos y entonces comienza la ejecución del programa por la rutina de  entrada al programa. Desde esta rutina se pueden ejecutar otras rutinas o componentes internos de ese modulo u otros módulos que estén unidos al programa o ejecutar rutinas o componentes externos que estén en programas de servicio.


A tener en cuenta

Después de explicar lo que son cada una de las partes que componen ILE es necesario recordar las siguientes características:
  • Utilizar componentes para encapsular funcionalidades con un alcance determinado. Hay que gestionar correctamente los parámetros para facilitar el mantenimiento.
  • Los componentes reutilizables en varios programas deberían encapsularse en módulos dentro de programas de servicio.
  • Un módulo que deba estar en varios programas deberían incluirse en un programa de servicio.
  • Los programas de servicio son capaces de gestionar diferentes "versiones" a través de la signatures.
  • Las llamadas entre módulos se resuelve en tiempo de compilación por lo que cuando se ejecutan no necesitan tiempo adicional al que sería necesario si fueran antiguas rutinas.
  • Las llamadas a programas de servicio son resueltas en tiempo de ejecución por lo que tienen cierto coste en tiempo de ejecución pero no llegan al coste que sería necesario para llamar de un programa a otro programa.
En los próximos artículos trataremos una estrategia de diseño que utilizo para reducir tiempo de desarrollo y costes de mantenimiento.

¡ Espero que no haya sido demasiado "ladrillo" y que haya sido más o menos claro!

23 comentarios:

  1. Cuál es la diferencia entre RPG ILE y RPG Free?

    ResponderEliminar
    Respuestas
    1. Con Rpg Free me refiero al lenguaje de programación. En el as400 hay diferentes lenguajes de programación como Cobol, RPG y dentro del RPG hay diferentes versiones. Entre algunos esta el RPG III que estaba basado en Hojas y el código lo tenías que poner en determinadas posiciones dentro de cada tipo de hoja. RPG free es la última evolución del RPG donde puedes escribir donde quieras y es mucho más legible. Es más parecido a cualquier lenguaje moderno de programación.

      En cuanto a ILE es un concepto de arquitectura de aplicaciones. Donde construyes la aplicación donde los programas son módulos independientes que se unen para formar la aplicación. Además contiene conceptos de reutilización, división y generación de pequeños componentes para hacer más fácil el desarrollo de aplicaciones y lo que es más importante el mantenimiento de las mismas.
      En la arquitectura ILE los módulos los puedes desarrollar en diferentes lenguajes (Cobol, Rpg, etc.) y después unirlos.

      La deformación profesional me ha llevado a mi a llamar programación con RPG ILE por que utilizo el desarrollo de aplicaciones con arquitectura ILE y sólo utilizo lenguaje RPG (no he tenido la necesidad de crear modulos con otros lenguajes)

      Eliminar
  2. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  3. Excelente artículo: Muy claro y didáctico. Gracias por compartir tu conocimiento.

    ResponderEliminar
  4. realmente es un choque muy fuerte para quienes estamos acostumbrados a la vieja escuela. Y lo peor es que, en muchos sitios de trabajos tratan de no utilizar estos conceptos sino hacerlos a la vieja manera

    ResponderEliminar
    Respuestas
    1. Es complicado "romper" con determinados esquemas. Pero es necesario adaptarse y modernizarse... o terminará desapareciendo nuestro maravilloso RPGLE

      Eliminar
  5. Esta muy buena la explicación.
    Tengo la siguiente consulta, como sería la llamada con parámetros *Nopass, del procedimiento.

    ResponderEliminar
    Respuestas
    1. Si tienes parámetros *nopass indica que no es necesario pasarlos. Logicamente el procedimiento llamado tiene que estar preparado para no recibir algunos de esos datos. Un ejemplo de llamada es simple. Imagina un procedimiento con tres parametros y el último es *nopass, entonces lo puedes llamar de la siguiente forma: procedimiento(A : B : C) ó no pasar el último, procedimiento(A : B)

      Eliminar
  6. Buen día Fernando. Excelente explicación, pero tengo una duda: Llamaste a módulos externos (EXTPGM), Que diferencia hay entre el módulo de componentes externos y un programa de servicio?

    ResponderEliminar
    Respuestas
    1. Lo primero discúlpame por no haberte contestado antes por que, sinceramente, "se me paso". Espero que tengas ya la solución pero para que conste para otros, aquí lo pongo.
      Si un modulo lo "enlazas" en un programa, en el momento de compilación, el codigo "maquina" incluye en el PROGRAMA ejecutable TODOS los objetos. Si cambias el modulo, tiene que recompilar TODOS los programas donde esté enlazado. Si es un se incluye como programa de servicio, realmente el programa ejecutable SOLO tiene una "referencia" a ese programa de servicio y esa "referencia" se resuelve en tiempo de ejecución y si se cambia el programa de servicio NO es necesario (según el cambio realizado) volver a compilar todos los programas donde estuviera enlazado

      Eliminar
  7. Excelente articulo, gracias Fernando, soy de la vieja escuela RPG basado hojas, este articulo me resulta muy util para enfocarme en aprender ILE y no quedarme en el pasado.
    Saludos.
    Hector, desde Santiago, Chile.

    ResponderEliminar
    Respuestas
    1. Y falto la creación del directorio de enlace donde esraran los módulos podría explicar creo que hay que crearlo antes de compilar crtsrvpgm

      Eliminar
    2. Hola José. Para hacer el crtsrvpgm no es necesario crear un directorio de enlace. Para compilar, se puede hacer de dos formas: Una, poniendo en el crtsrvpgm explicitamente los modulos que se quieren enlazar (no necesita directorio de enlace) o poniendo un directorio de enlace y logicamente, en el directorio tienen que estar añadidos los nombres de los modulos. El directorio de enlace no es más que un indice con un conjunto de módulos que facilita la gestión de compilaciones pero en principio nada más. Se hace con CRTBNDDIR y después se añaden referencias con ADDBNDDIRE donde añade el nombre del modulo al directorio de enlace. En el crtsrvpgm puedes poner varios directorios de enlace por si quieres "separar" los indices de modulos simplemente por gestión. Imagina los modulos relacionados con clientes en un directorio de enlace y los modulos relacionado con proveedores en otro directorio. Pero es simplemente a efectos de organización.

      Eliminar
  8. Hola Fernando
    He provado a crear un Modulo LSTxxxx pero me graba en la estructura de datos hasta que encuentra en mi tabla el primer campo que contiene un valor NULL
    He provado a incorporar en el formateo de la SentenciaSQL con COALESCE, pero no le gusta al ejecutar el FETCH ....
    Estoy perdido.
    Un saludo y gracias

    ResponderEliminar
  9. HOLA FERNANDO.. Bendiciones. tengo una duda, yo tengo un service program ya creado y necesito modificar el fuente, la pregunta es, si compilo nuevamente el modulo basta para que se actulice el service program o tengo que crear nuevamente el service (CRTSRVPGM)

    ResponderEliminar
    Respuestas
    1. Hola
      Si modificas un modulo dentro del programa de servicio, dependiendo de la modificación, te podría valer simplemente con actualizar el programa. En cualquier caso, en general, yo siempre utilizo el CRTSRVPGM por que en general no tiene ningún efecto más allá de tener que poner todos los modulos. Lo realmente lo importante es la signatura y esta puede cambiar o no dependiendo del cambio que hayas hecho en el fuente. Si has cambiado parametros, si has añadido modulos y no has tenido en cuenta la gestión dentro del lenguaje Binder, te podrá cambiar la signatura y en ese caso TIENES que recompilar TODOS los programas que utilicen ese programa de servicio.
      Por lo tanto, te recomiendo que utilizando update o create, después verifiques la signature que te ha generado (en base a los cambios y en base al binder) para que veas si existe algún problema con los actuales programas que utilizan ese programa de servicio. Ya sabes, si cambia la signature (y no tiene las versiones anteriores), el programa que lo utilice con la signature anterior, va a fallar.
      Espero haberte ayudado
      Un saludo

      Eliminar
    2. Muchas gracias... si fue precisamente lo que me paso... hice el cambio pero no se veia reflejado... pero crei que no era necesario por que utilizaba un Binding Directory, pero una vez recompile el programa que hace el llamado del service program ya todo funciono.

      Eliminar
  10. hola edward tengo una duda soy nuevo en este entorno de la as400.
    la duda es yo tengo un objeto compilado sin source. pero el fuente se me perdio. el compilado lo tengo en una libreria. la pregunta es desde el compilado puedo recuperar el fuente teniendo IBM que trabajo con AS400.
    desarrollo en cobol

    gracias y un saludo desde Colombia.

    ResponderEliminar
    Respuestas
    1. Hola
      Creo que desde SO no existe ninguna funcionalidad para extraer el fuente a partir de objetivo compilado. Supongo que existirán aplicaciones comerciales que serán capaces de hacerlo pero las desconozco.
      Lo podrás hacer manualmente (copy+paste) desde el DEBUG pero siempre que hayas compilado con directivas que incluyan el fuente (intuyo que si existen herramientas comerciales, se basarán en lo mismo)

      Eliminar
  11. Hola Fernando, tengo la siguiente problemática, en un programa COBOL ILE muy complejo necesito hacer unas pruebas bajo formato FREE, pero ciertamente no es igual a RPGLE, entonces ¿cómo debo declarar las instrucciones?, gracias!

    ResponderEliminar
    Respuestas
    1. Disculpa pero realmente no he trabajado con Cobol así que en ese tema no te puedo ayudar. Lo siento

      Eliminar