Ir al contenido
Programación ABAP

Modularización

Cómo dividir un programa en piezas reutilizables: macros, includes, subrutinas, módulos de función y llamadas a otros programas.

Manual ABAP
10 de 14

Antes y ahora

Este capítulo se escribió para SAP R/3 y ABAP clásico. Aquí tienes qué ha cambiado; en cada apartado verás la comparación con código y, plegado, el texto original.

ConceptoEn el manualHoyEstado
Reutilizar unas líneasMacros (DEFINE)Métodos o expresionesSustituido
Dividir un programaSubrutinas (FORM / PERFORM)Clases locales y métodosSustituido
Datos compartidosTABLES, COMMON PARTAtributos de una claseSustituido
ErroresExcepciones clásicas y sy-subrcExcepciones de clase con TRY … CATCHSe escribe distinto
Código reutilizable entre programasMódulos de función e includesClases globales; módulos de función para RFC, BAPI y actualizaciónSe escribe distinto
Llamar a una transacciónCALL TRANSACTIONCALL TRANSACTION … WITH AUTHORITY-CHECKSe escribe distinto

Sigue igual: los módulos de función (SE37), imprescindibles para RFC, SUBMIT … AND RETURN, los includes para ordenar programas grandes.

10.1 Macros

Sustituido

Así se hace hoy

Las macros no se pueden depurar paso a paso y el ATC las marca. Casi siempre se sustituyen por una expresión o por un método:

Antes
DEFINE anadir_linea.
  ls_linea-campo = &1.
  ls_linea-valor = &2.
  APPEND ls_linea TO lt_lineas.
END-OF-DEFINITION.

anadir_linea 'MATNR' lv_matnr.
anadir_linea 'WERKS' lv_werks.
Ahora
lt_lineas = VALUE #( BASE lt_lineas
  ( campo = 'MATNR' valor = lv_matnr )
  ( campo = 'WERKS' valor = lv_werks ) ).
Texto original del manual: sintaxis clásica
  • Sintaxis de definición de una macro. Pueden usarse hasta 9 parámetros: &1, &2, ..., &9:

    ABAP
    DEFINE nombre_macro. bloque.
    
    END-OF-DEFINITION.
  • Sintaxis de uso de la macro definida. Se indica su nombre, seguido de los parámetros actuales:
    nombre_macro [ p1 ] [ p2 ] ... [ p9 ] .
    Ejemplo:

    ABAP
    DATA solucion TYPE i.
    
    DEFINE salida.                "macro llamada salida
      WRITE: / 'El resultado de la operación &1 &2 &3 es', &4.
    END-OF-DEFINITION.
    
    DEFINE operacion.             "macro llamada operacion; usa la macro salida
      solucion = &1 &2 &3.
      salida &1 &2 &3 solucion.
    END-OF-DEFINITION.
    
    operacion 4 + 3.              "muestra: El resultado de la operación 4 + 3 es 7

Se han definido las macros ‘operación’ y ‘salida’, y además la primera hace uso de la segunda en su definición. Con esto se crea una nueva “instrucción” ABAP llamada ‘operación’, con 3 parámetros formales. Al ejecutarla con parámetros actuales ‘4’ ‘+’ ‘3’, lo que se ve en pantalla es: “El resultado de la operación 4 + 3 es 7”. Los operandos &1 y &3 son números, así como el resultado &4, y el operando &2 es el operador binario. En la variable ‘solución’ se calcula el resultado, y se llama a la macro ‘salida’ para mostrar éste en pantalla.

MacrosDEFINEEvitarIncludesINCLUDEOrganizar códigoSubrutinasFORM / PERFORMObsoletasMódulos de funciónCALL FUNCTIONPara RFC y BAPIClases y métodosCLASS / METHODRecomendadoLas clases ofrecen encapsulación, interfaces, herencia, excepciones de clase y pruebas unitarias con ABAP Unit.Las subrutinas siguen funcionando, pero SAP las declara obsoletas y no existen en ABAP Cloud.Los módulos de función siguen siendo necesarios para llamadas remotas (RFC), BAPI y tareas de actualización.
Evolución de las unidades de modularización. Para código nuevo, clases y métodos; los módulos de función, para RFC, BAPI y actualización.

10.2. Inclusión de código

Sigue igual

Así se hace hoy

Los includes siguen sirviendo para ordenar un programa grande (por ejemplo, uno para las definiciones y otro para las clases locales). No los reutilices entre programas: para eso están las clases globales.

  • Existe una sentencia que permite incluir o insertar (en tiempo de generación / compilación, no en tiempo de ejecución) el código fuente del programa especificado, dentro del llamante. Esta sentencia sólo puede estar codificada en una línea. Dicho programa debe ser de tipo I (es un INCLUDE). Estos no llevan sentencia PROGRAM ni REPORT, y no son ejecutables directamente, sino que deben ser llamados siempre desde otro programa, con la sentencia INCLUDE. Por lo demás, es código ABAP normal. Los includes se usan para agrupar subrutinas que van a ser reutilizadas en muchos programas (por ejemplo, programas ‘batch-input’).

    Sintaxis:

    ABAP
    INCLUDE nombre_include.

10.3. Zonas de datos comunes

Sustituido

Así se hace hoy

Las zonas de datos comunes hacen que un cambio en un programa rompa otro sin avisar. Hoy los datos que se comparten se encapsulan en una clase, como atributos con métodos para leerlos y cambiarlos.

Texto original del manual: sintaxis clásica

Las zonas COMMON PART están obsoletas. Para compartir datos entre programas usa parámetros, clases o, si no hay más remedio, la memoria ABAP (EXPORT/IMPORT).

  • Se usan para declarar datos comunes a varios programas. En todos ellos debe estar declarada la misma COMMON PART, con el mismo nombre y estructura (se puede por ejemplo declarar la COMMON PART en un INCLUDE aparte, y llamarlo desde donde sea necesario). Un programa puede tener varias COMMON PART, que se identifican por su distinto nombre (el nombre es opcional si sólo hay una).
    Sintaxis:
  • DATA: BEGIN OF COMMON PART [ nombre ].
  • Sentencias declarativas de datos.
  • DATA: END OF COMMON PART.

10.4. Subrutinas

Sustituido

Así se hace hoy

Las subrutinas siguen compilando, pero SAP las declara obsoletas. El código nuevo se organiza en clases: locales dentro del programa o globales (SE24 o ADT) para reutilizarlas.

Antes
PERFORM calcular_iva USING    lv_base
                    CHANGING lv_iva.

FORM calcular_iva USING    pv_base TYPE netwr
                  CHANGING pv_iva  TYPE netwr.
  pv_iva = pv_base * '0.21'.
ENDFORM.
Ahora
CLASS lcl_impuestos DEFINITION FINAL.
  PUBLIC SECTION.
    CLASS-METHODS iva
      IMPORTING iv_base       TYPE netwr
      RETURNING VALUE(rv_iva) TYPE netwr.
ENDCLASS.

CLASS lcl_impuestos IMPLEMENTATION.
  METHOD iva.
    rv_iva = iv_base * '0.21'.
  ENDMETHOD.
ENDCLASS.

" Se usa directamente en una expresión
lv_total = lv_base + lcl_impuestos=>iva( lv_base ).
Texto original del manual: sintaxis clásica

Existen 2 tipos de subrutinas: internas (el código de la subrutina está dentro del programa que la llama) y externas (la subrutina está en un programa distinto al llamante). Las subrutinas se codifican al final del programa principal, tras todos los eventos. No se pueden anidar. Se puede salir de una subrutina con un EXIT (salida incondicional) o un CHECK (salida condicional), si estas sentencias no están dentro de un bucle. Sólo dentro de una subrutina se puede usarse la sentencia LOCAL campo, para declarar variables locales a la subrutina (sólo visibles dentro de ella). Deja oculto el valor de ese campo que tuviera antes de entrar a la subrutina, y lo restaura al salir de ésta.

  • Sintaxis de declaración: (igual para subrutinas internas y externas)

    ABAP
    FORM nombre [ parámetros ].
    
      bloque.
    
    ENDFORM.
  • Sintaxis de la llamada

    • Llamada a una subrutina interna: PERFORM nombre [ parámetros ].
    • Llamada a una subrutina externa: PERFORM name (programa) [ paráms ] [ IF FOUND ].
      En este caso se debe indicar el programa en el cual se encuentra la subrutina llamada. Con IF FOUND, si la subrutina no existe, la sentencia PERFORM es ignorada y no se genera error.
    • Llamada dinámica: PERFORM (var) [ IN PROGRAM (var2) ] [ parám ] [ IF FOUND ].
      Se llama a la subrutina cuyo nombre está contenido en el campo o variable ‘var’. Se puede indicar opcionalmente el nombre del programa donde está (así vale para subrutinas internas y externas), en el campo o variable ‘var2’. IF FOUND es igual que antes.
    • Llamada a partir de una lista: PERFORM índice OF subrutina1 subrutina2 ... subrutinaN.
      El sistema ejecuta la subrutina que ocupe la posición especificada en ‘índice’ (literal o variable), de la lista dada de subrutinas. Con esto sólo se puede llamar a subrutinas internas.
  • Parámetros formales:

    FORM nombre [ TABLES lista_tablas ] [ USING lista_var ] [ CHANGING lista_var ][ TYPE ... | LIKE ... ].

    Las distintas opciones deben escribirse en este mismo orden. Los parámetros formales de una subrutina interna pueden ser cualesquiera variables declaradas en el llamante (no las variables locales internas a la subrutina), pues son visibles. Por esa misma razón ni siquiera es necesario declarar esos parámetros formales. En cambio en las subrutinas externas sí es necesario pues esas variables no serán visibles directamente. Usando parámetros ya no es necesario declarar un COMMON PART en el llamante y llamado para pasar valores a una subrutina externa.

    Las variables de USING y CHANGING pueden ser de cualquier tipo, mientras que las de TABLES deben ser tablas internas (con o sin área de trabajo). Por tanto, con CHANGING y USING pueden pasarse también tablas, pero hay que pasar explícitamente la estructura de la misma (por ejemplo con un LIKE) para poder referenciar luego a sus campos.
    Ejemplo:

    ABAP
    PERFORM nombre CHANGING itabla.
    
    
    FORM nombre CHANGING ztabla LIKE itabla.
      ...
    ENDFORM.
  • Parámetros actuales:

    PERFORM nombre [(prog)] [ TABLES lista_tablas ] [ USING lista_var ][ CHANGING lista_var ].
  • Paso de parámetros:Hay 3 formas de pasar datos (parámetros) a una subrutina:

    • Paso por valor: El parámetro formal y el actual ocupan posiciones de memoria distintas, es una copia, con lo que su valor no puede ser modificado por la subrutina. Sólo se puede usar en USING con la opción VALUE.
    • Paso por referencia: El parámetro formal y el actual ocupan la misma posición de memoria, con lo que su valor puede ser modificado por la subrutina. Se pasa la dirección del parámetro, no una copia. Se puede usar en TABLES, USING y CHANGING.
      Ejemplos:

      ABAP
      PERFORM fecha_fin_mes USING fedat.
      
      PERFORM load TABLES itab USING zcampo zfile.
  • Paso por valor y resultado: El parámetro formal y el actual ocupan posiciones de memoria distintas (se pasa una copia), pero su valor puede ser modificado por la subrutina (el valor se copia al parámetro actual solo cuando la subrutina termina con normalidad; si termina por un mensaje de error o una excepción, el parámetro no se modifica). Sólo se puede usar en CHANGING con VALUE.

10.5. Módulos de función

Se escribe distinto

Así se hace hoy

Los módulos de función siguen siendo necesarios para llamadas remotas (RFC), BAPI, tareas de actualización y para usar las funciones estándar de SAP. En código nuevo, los errores se tratan con excepciones de clase:

Antes
CALL FUNCTION 'Z_LEER_CLIENTE'
  EXPORTING
    iv_kunnr  = lv_kunnr
  EXCEPTIONS
    not_found = 1
    OTHERS    = 2.
IF sy-subrc <> 0.
  MESSAGE 'Cliente no encontrado' TYPE 'E'.
ENDIF.
Ahora
TRY.
    DATA(ls_cliente) = lo_repo->leer( lv_kunnr ).
  CATCH zcx_no_encontrado INTO DATA(lx_error).
    MESSAGE lx_error TYPE 'E'.
ENDTRY.
UnidadÚsala para
Clase localLa lógica de un programa: se prueba con ABAP Unit
Clase globalCódigo reutilizable entre programas
Módulo de funciónLlamadas remotas (RFC), BAPI, tareas de actualización y diálogos de SAP GUI
IncludeSolo para organizar programas grandes
Subrutina y macroSolo para mantener programas antiguos
Texto original del manual: sintaxis clásica

Una función es una subrutina externa especial que se almacena en una “biblioteca central” de SAP. Hay muchas predefinidas, de librería, así como subrutinas, que pueden ser llamados desde cualquier programa ABAP. Se pueden crear otras nuevas (indicando el grupo de funciones al que van a pertenecer). Las funciones se crean por menú en Workbench ABAP – Biblioteca de Funciones. También se pueden ver y testar (probar su funcionamiento introduciendo valores en los parámetros de entrada de forma manual, al pulsar en el botón Test).

  • Grupo de funciones: Sirve para reutilizar funciones (son programas que calculan algo, que devuelven algo como parámetro(s) de salida). Es análogo a un pool de subrutinas (agrupación de subprogramas). El grupo de funciones crea un programa de tipo grupo de funciones (function pool, que se compone sólo de sentencias INCLUDE) de nombre SAPLXXXX, con XXXX el nombre del grupo de funciones.
  • Sintaxis de la llamada a una función: Con esta sentencia se llama a un módulo de función desde programa. Conviene escribir la sintaxis de esta sentencia usando el botón de Traer Modelo del Editor ABAP, para que aparezcan automáticamente los parámetros de concretos de la función.

    CALL FUNCTION nombre [ EXPORTING f1 = a1 ... fn = an ][ IMPORTING f1 = a1 ... fn = an ] [ CHANGING f1 = a1 ... fn = an ][ TABLES f1 = a1 ... fn = an ] [ EXCEPTIONS f1 = a1 ... fn = an ].
  • EXPORTING: Parámetros que van hacia el módulo, son los de entrada (la función por tanto no los modifica). Se dan valores actuales a1 ... an a los parámetros formales f1 ... fn de la función (que estarán declarados como IMPORT en la función).
  • IMPORTING: Parámetros de salida (en la función estarán declarados como EXPORT). CHANGING: Parámetros de entrada / salida (son modificables). TABLES: Se usa para pasar tablas internas como parámetros.
  • EXCEPTIONS: Se usa para gestionar excepciones y errores. Cuando se activa la excepción fi, en el campo de retorno SY-SUBRC se tendrá el valor ai. Así se puede saber qué ocurrió al ejecutar la función. Con OTHERS = a se da tratamiento a errores no contemplados.
  • ERROR-MESSAGE = re. Se usa para tratar errores generando un mensaje. Se tendrá el valor re en SY-SUBRC. Se podrá mandar el mensaje desde el programa llamante, accediendo a los campos del sistema: SY-MSGID (nombre del mensaje), SY-MSGNR (número del mensaje), SY-MSGTY (tipo del mensaje), SY-MSGV1 ... SY-MSGV4 (4 textos para los 4 posibles parámetros & del mensaje).
    Ejemplo:

    ABAP
    DATA: text(20),
          front(20),
          end(20).
    
    text = 'testing: string-split'.
    
    CALL FUNCTION 'STRING_SPLIT'               " módulo de función predefinido
      EXPORTING delimiter = ':' string = text  " parámetros de entrada
      IMPORTING head = front tail = end        " parámetros de salida
      EXCEPTIONS not_found = 1 OTHERS = 2.     " excepciones
    
    CASE sy-subrc. ... ENDCASE.                  " tratamiento de los errores
  • Objetos parciales de una función:

    • Atributos y parámetros: Una función tiene los siguientes parámetros: EXPORTING (de entrada a la función), IMPORTING (de salida. Resultado de la función), CHANGING (de entrada / salida), TABLES (tablas internas de entrada / salida), EXCEPTIONS (excepciones producidas por la función. Se usa para el manejo de errores).
    • Texto fuente: Código ABAP de la función.
    • Documentación: Asociada a la función, dependiente del idioma.
    • Datos globales: Código ABAP con las sentencias declarativas del grupo de función.
    • Programa principal: el programa SAPLxxxx del grupo de funciones. Cada módulo de función tiene su propio include dentro de él.
  • Sintaxis de la definición de la función:

    FUNCTION nombre [ EXPORT f1 ... fn ] [ IMPORT f1 ... fn ] [ TABLES f1 ... fn ][ EXCEPTION f1 ... fn ]. bloque. ENDFUNCTION.

Se usa esta sentencia para crear el código fuente de un módulo de funciones. El nombre del módulo puede tener hasta 30 caracteres (el del grupo de funciones tenía 4 en R/3 antiguo; hoy, hasta 26). No debe escribirse REPORT ni PROGRAM. El resto es similar a una subrutina, pero no se declaran con DATA variables para los parámetros EXPORT ni IMPORT (ya lo hace SAP automáticamente). Puede usarse en toda función de grupo de funciones XXXX un include llamado LXXXXTOP. El resto de includes que use la función se llamarán: LxxxxUyy, con xxxx el nombre del grupo de funciones e yy el número del módulo. Tras el ENDFUNCTION pueden codificarse las subrutinas que use dicha función, si tiene.

  • Gestión de excepciones dentro de un módulo de función. Hay 2 maneras:

    RAISE excepción.

    MESSAGE ... RAISING excepción.

    Dentro de un módulo de función los errores se comunican elevando excepciones; un MESSAGE sin RAISING interrumpe al programa que llama. Desde hace años también se pueden usar excepciones de clase (RAISING cx_…), que es lo recomendado. La segunda sentencia activa un mensaje, pero no lo muestra. Para poder visualizarlo hay que acceder a los campos del sistema de la tabla SYST, donde se almacena el texto del mensaje, número, ... pero desde el programa principal).
    Ejemplo:

    ABAP
    * En el programa que llama
    CALL FUNCTION 'Z_DIVISION'
      EXPORTING  n1 = lv_a  n2 = lv_b
      IMPORTING  result = lv_resultado
      EXCEPTIONS div_zero = 5.
    IF sy-subrc = 5.
      MESSAGE e001(zz).
    ENDIF.
    
    * En el módulo de función (la interfaz IMPORTING n1 n2,
    * EXPORTING result y EXCEPTIONS div_zero se define en la SE37)
    FUNCTION z_division.
    
      IF n2 = 0.
        RAISE div_zero.                          "elevar excepción
      ELSE.
        result = n1 / n2.
      ENDIF.
    
    ENDFUNCTION.

10.6. Llamada a un report

Sigue igual

Así se hace hoy

SUBMIT … WITH … AND RETURN funciona igual. Si el report llamado muestra un ALV y quieres sus datos en lugar del listado, la clase CL_SALV_BS_RUNTIME_INFO permite capturarlos.

  • SUBMIT nombre_report | (variable) [ AND RETURN ] [ LINE-SIZE columnas ][ LINE-COUNT líneas ] [ VIA SELECTION-SCREEN ] [ WITH criterio_selección ][ USING SELECTION-SET variante ] [ WITH FREE SELECTIONS libre_selección ][ WITH SELECTION-TABLE tabla ].
  • Puede darse el nombre del report a llamar de forma estática (indicando su nombre directamente) o dinámica (mediante una variable).
    Parámetros:

    • AND RETURN: El sistema devuelve el control al finalizar al programa llamado (pulsando en éste el botón BACK: F3); si no se usa esta opción, no se vuelve al llamante (aunque se pulse F3); el programa que llama termina.
    • LINE-SIZE y LINE-COUNT: Formatean el tamaño de salida del report llamado.
    • VIA SELECTION-SCREEN: Con esta opción el sistema muestra la pantalla de selección del llamado (por defecto no aparecerá, porque se supone que el llamante pasará al llamado como parámetros los datos que necesite para su ejecución).
    • WITH: Se especifica el valor concreto para un criterio de selección (SELECT-OPTIONS) del llamado. Habrá un WITH para cada PARAMETER o SELECT-OPTIONS del llamado al que deba pasársele valor. Con esto se le pasan al llamado sus parámetros de ejecución.
    • USING SELECTION-SET: Se ejecuta el llamado con la variante especificada. Así, es posible saltarse la pantalla de selección del report llamado, y rellenar los valores de los parámetros de ésta mediante la variante especificada, en lugar de dar un WITH para cada uno.
    • WITH FREE SELECTIONS: Se crea una ventana de diálogo para selecciones dinámicas.
    • WITH SELECTION-TABLE: Permite pasar dinámicamente valores a los criterios de selección del llamado que se desee. La estructura de la tabla especificada debe ser la misma que la de RSPARAMS, que tiene 6 campos: SELNAME (8 caracteres: nombre del criterio de selección o parámetro), KIND (1 carácter: ‘S’ para SELECT-OPTIONS y ‘P’ para PARAMETERS), SIGN, OPTION, LOW, HIGH (éstos como un criterio de selección).

10.7. Llamada a una transacción

Se escribe distinto

Así se hace hoy

Antes
SET PARAMETER ID 'AUN' FIELD lv_vbeln.
CALL TRANSACTION 'VA03' AND SKIP FIRST SCREEN.
Ahora
SET PARAMETER ID 'AUN' FIELD lv_vbeln.
CALL TRANSACTION 'VA03' WITH AUTHORITY-CHECK
                        AND SKIP FIRST SCREEN.

Sin WITH AUTHORITY-CHECK, el usuario podría entrar en una transacción que no tiene autorizada (S_TCODE). El ATC lo marca como error de seguridad.

  • LEAVE TO TRANSACTION código_transacción [ AND SKIP FIRST SCREEN ].
    Llama a la transacción especificada, sin devolver el control al programa llamante cuando ésta acabe. Con AND SKIP FIRST SCREEN se salta la primera pantalla de la transacción.
  • CALL TRANSACTION código_transac [ AND SKIP FIRST SCREEN ] [ USING tabla].
    Devuelve cuando acabe el control al programa llamante. Con USING se le pasa una tabla con la estructura de la BDCDATA para que se realicen automáticamente las acciones especificadas.

Para seguir