Programar en ABAP no es solo hacer que algo funcione… también es hacer que sea entendible, fácil de mantener y sin dolores de cabeza para el próximo que lo toque (o tú mismo dentro de dos meses). Aquí te dejo buenas prácticas esenciales que todo ABAPer debería aplicar.
Tabla de contenidos
🧠 Nombres claros > nombres cortos
Usar nombres significativos para variables, clases y métodos es fundamental para que cualquier persona (o tú mismo en el futuro) entienda el código sin esfuerzo.
| Objeto | Incorrecto | Correcto |
|---|---|---|
| Programa | ZR1 | ZSD_LISTADO_PEDIDOS |
| Clase | ZCL1 | ZCL_GESTION_FACTURAS |
| Variable | LV1 | LV_TOTAL_IMPORTE |
Claves:
✔ Usa nombres descriptivos.
✔ Siempre con prefijo Z / Y si es objeto Z.
✔ El idioma da igual, pero sé consistente (todo en español o todo en inglés).
Convenciones recomendadas:
- Variables locales:
lv_* - Variables globales:
gv_* - Constantes:
lc_* - Estructuras:
ls_* - Tablas internas:
lt_* - Clases:
lcl_*(locales),zcl_*(globales) - Métodos:
get_*,process_*,validate_*
🏗️ Usa el Diccionario ABAP (SE11) siempre que sea posible
Definir tipos de datos, estructuras y tablas en el Diccionario ABAP en lugar de hacerlo directamente en el programa promueve la reutilización y consistencia.
❌ Evita:
DATA: BEGIN OF ls_customer,
id TYPE i,
name TYPE string,
END OF ls_customer.
✅ Mejor:
Crea una estructura ZSTR_CUSTOMER en SE11 y úsala:
DATA ls_customer TYPE zstr_customer.
🚫 No uses números mágicos
Los «números mágicos» son valores literales sin explicación. Usa constantes para darles significado.
❌ Evita:
IF lv_status = 'A'. " ... ENDIF.
✅ Mejor:
CONSTANTS: lc_status_active TYPE c VALUE 'A'. IF lv_status = lc_status_active. " ... ENDIF.
📏 Modulariza tu código
Divide programas grandes en módulos de función, clases o métodos. Esto hace el código más testeable y mantenible. Evita programas de 1000 líneas con todo en un solo bloque.
⚡ Optimiza el acceso a bases de datos
Las operaciones de base de datos son costosas. Sigue estas reglas:
- Usa
SELECTconWHEREen lugar de leer toda la tabla (a ser posible por los campos claves). - Nunca hacer
INSERT,MODIFYoUPDATEpor cada registro en unLOOPsalvo que sea estrictamente necesario. Mejor añadir a una tabla interna y hacerINSERT ztab FROM TABLE it_tab.oMODIFY ztab FROM TABLE it_tab. - Evita
SELECTdentro de bucles. - Evita
LOOPdentro de otroLOOP. Sustituir porREAD TABLE ... WITH KEYsobre tablas hashed/sorted o usar índices en tablas internas. - Usa
FOR ALL ENTRIEScon precaución (verifica que la tabla no esté vacía), o si tu versión de SAP lo permiteINNER JOIN - Prefiere
JOINsobre múltiplesSELECTsimples. - No uses SELECT * salvo que necesites todas las columnas.
❌ Evita:
LOOP AT lt_orders INTO ls_order.
SELECT SINGLE * FROM vbap INTO ls_vbap
WHERE vbeln = ls_order-vbeln.
ENDLOOP.
✅ Mejor:
IF lt_orders IS NOT INITIAL.
SELECT * FROM vbap INTO TABLE lt_vbap
FOR ALL ENTRIES IN lt_orders
WHERE vbeln = lt_orders-vbeln.
ENDIF.
⚡ FOR ALL ENTRIES vs INNER JOIN (¿cuál es mejor y cuándo?)
| Opción | ¿Cuándo usarla? | Ventajas | Problemas |
|---|---|---|---|
| INNER JOIN | Siempre que las tablas tengan relación directa y estés en SAP 7.4+ | Más rápido, menos memoria, se ejecuta en la base de datos | No puedes hacer lógica compleja entre tablas |
| FOR ALL ENTRIES | Cuando no puedes usar joins (tablas sin relación en diccionario) | Flexible | ⚠️ Si la tabla está vacía → devuelve TODOS los registros. Más lenta. |
| LEFT OUTER JOIN | Mostrar datos de tabla principal aunque no haya correspondencia (ej: pedidos sin posiciones) | Lo más usado en SAP | Mejor que FOR ALL ENTRIES en la mayoría de escenarios |
🛑 Verifica siempre sy-subrc después de READ TABLE
Cuando trabajas con tablas internas, nunca asumas que el registro que buscas va a existir. Siempre verifica el código de retorno sy-subrc para evitar errores en tiempo de ejecución.
❌ No hagas esto:
READ TABLE lt_customers INTO ls_customer WITH KEY id = lv_customer_id.
lv_name = ls_customer-name. " ¡Posible dump!
✅ Mejor haz esto:
READ TABLE lt_customers INTO ls_customer WITH KEY id = lv_customer_id.
IF sy-subrc <> 0.
" Registro NO encontrado - maneja el error
MESSAGE e001(z_custom) WITH lv_customer_id.
RETURN.
ENDIF.
" Registro encontrado - procede con seguridad
lv_name = ls_customer-name.
🧹 Limpia tu código: elimina código comentado y muerto
El código comentado o que nunca se ejecuta solo genera confusión. Intenta eliminarlo para dejar el código lo más limpio posible.
✔ Elimina código comentado que ya no se utiliza
✔ Indenta correctamente
✔ No dejes BREAK-POINT ni WRITE en productivo
✔ Usa SLIN o ATC para detectar errores y mejoras
💬 Mensajes y textos (no hardcodear)
- Usa Message Classes (SE91) y Text Elements. Esto facilita traducción, cambios y consistencia.
- Para textos en programas:
TEXT-001oTEXT-010(Text Symbols) según convenga.
Ejemplo:
MESSAGE e001(zmm_mensajes) WITH lv_pedido.
🛡️ Manejo de errores
Usa bloques de manejo de excepciones y comprueba los resultados de las operaciones críticas.
❌ Evita:
CALL FUNCTION 'Z_FUNCION_IMPORTANTE'.
✅ Mejor:
CALL FUNCTION 'Z_FUNCION_IMPORTANTE'
EXCEPTIONS
error_occurred = 1
OTHERS = 2.
IF sy-subrc <> 0.
" Manejar el error
ENDIF.
Para clases, usa el manejo de excepciones orientado a objetos:
TRY.
lo_object->process_data( ).
CATCH zcx_my_exception INTO lo_ex.
" Manejar excepción
ENDTRY.
📋 Documenta, pero no exageres
La documentación debe explicar el «porqué», no el «qué». El código ya dice lo que hace. Usa comentarios para:
- Explicar decisiones técnicas complejas
- Documentar parámetros en métodos y funciones
- Indicar por qué se hace algo de cierta manera
⚙️Estructura recomendada para reportes
En programas con SE38:
| Include | Para… |
|---|---|
ZPROG_TOP | Data, types, constantes |
ZPROG_SEL | Pantalla de selección (PARAMETERS, SELECT-OPTIONS) |
ZPROG_F01 | Subrutinas o formularios |
Esto mantiene el programa limpio y escalable.
Estas prácticas no son teoría, son cosas que evitan dumps, descuadres en productivo y llamadas de madrugada. Si las aplicas, tu código será:
✔ Más rápido
✔ Más fácil de mantener
✔ Más profesional

