Tuscan Consulting Logo

ABAP Development: Tips and Tricks for ABAP 7.4

March 30, 2025
7 min read
Raghu Krishnappa
ABAP Development

ABAP 7.4 introduced a wealth of new features and capabilities that significantly enhance developer productivity and code quality. In this article, we'll explore essential tips and best practices for leveraging ABAP 7.4 to its fullest potential.

1. Embrace Inline Declarations

One of the most significant improvements in ABAP 7.4 is the ability to declare variables inline. This feature not only makes your code more concise but also improves readability by placing variable declarations closer to their usage.

* Old style
DATA: lv_name TYPE string,
      lv_date TYPE datum.

lv_name = 'John Doe'.
lv_date = sy-datum.

* New inline style
DATA(lv_name) = 'John Doe'.
DATA(lv_date) = sy-datum.

Inline declarations are particularly useful when working with method results or function module returns:

* Directly use the result
DATA(lt_flights) = get_flights( iv_carrier = 'LH' ).

* Works with complex expressions too
DATA(lv_days_between) = cl_abap_datfm=>get_days_between_dates( 
  iv_date_1 = '20250101' 
  iv_date_2 = sy-datum 
).

Pro Tip: While inline declarations improve readability, use them judiciously. Sometimes explicit typing with DATA statements provides better clarity, especially for complex types.

2. Leverage Table Expressions

ABAP 7.4 introduced powerful table expressions that simplify working with internal tables. These expressions make your code more concise and readable.

* Old style
DATA: lt_flights TYPE TABLE OF spfli,
      ls_flight  TYPE spfli.

READ TABLE lt_flights INTO ls_flight WITH KEY carrid = 'LH' connid = '0400'.
IF sy-subrc = 0.
  * Process ls_flight
ENDIF.

* New style with table expressions
DATA(lt_flights) = get_flights( ).
TRY.
    DATA(ls_flight) = lt_flights[ carrid = 'LH' connid = '0400' ].
    * Process ls_flight
  CATCH cx_sy_itab_line_not_found.
    * Handle exception
ENDTRY.

You can also use table expressions for field symbols and to directly access specific fields:

* Field symbol with table expression
ASSIGN lt_flights[ carrid = 'LH' connid = '0400' ] TO FIELD-SYMBOL(<fs_flight>).

* Direct field access
DATA(lv_cityto) = lt_flights[ carrid = 'LH' connid = '0400' ]-cityto.

3. Use String Templates

String templates in ABAP 7.4 allow you to embed expressions directly within strings, making string concatenation much cleaner and more readable.

* Old style string concatenation
DATA: lv_first_name TYPE string VALUE 'John',
      lv_last_name  TYPE string VALUE 'Doe',
      lv_message    TYPE string.

CONCATENATE 'Hello, ' lv_first_name ' ' lv_last_name '!' INTO lv_message.

* New style with string templates
DATA(lv_first_name) = 'John'.
DATA(lv_last_name) = 'Doe'.
DATA(lv_message) = |Hello, { lv_first_name } { lv_last_name }!|.

* Format numbers and dates
DATA(lv_amount) = 1234.56.
DATA(lv_formatted) = |Amount: { lv_amount DECIMALS = 2 }|. "Amount: 1,234.56

DATA(lv_today) = sy-datum.
DATA(lv_date_formatted) = |Today is { lv_today DATE = USER }|.

4. Adopt Functional Programming with ABAP

ABAP 7.4 introduced functional programming constructs that can make your code more concise and expressive. The REDUCE, FILTER, and TRANSFORM operators are particularly useful.

* REDUCE to calculate a sum
DATA(lt_items) = get_order_items( ).
DATA(lv_total_amount) = REDUCE decfloat34( 
  INIT sum = 0 
  FOR item IN lt_items 
  NEXT sum = sum + item-amount 
).

* FILTER to get a subset of a table
DATA(lt_flights) = get_flights( ).
DATA(lt_lh_flights) = FILTER #( 
  lt_flights USING KEY carrier WHERE carrid = 'LH' 
).

* TRANSFORM to convert data
DATA(lt_customers) = get_customers( ).
DATA(lt_customer_names) = TRANSFORM string_table( 
  FOR customer IN lt_customers 
  LET full_name = |{ customer-firstname } { customer-lastname }| IN
  ( full_name ) 
).

5. Optimize Database Access with CDS Views

Core Data Services (CDS) views, introduced with ABAP 7.4, provide a powerful way to define and consume semantically rich data models. They push data processing to the database layer, improving performance.

@AbapCatalog.sqlViewName: 'ZFLIGHTINFO'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Flight Information'
define view ZI_FlightInfo as select from spfli
  association [0..1] to scarr as _Airline on $projection.carrid = _Airline.carrid {
  key carrid as Carrid,
  key connid as Connid,
      cityfrom as Cityfrom,
      cityto as Cityto,
      _Airline.carrname as Carrname
}

* Consuming the CDS view in ABAP
SELECT * FROM zi_flightinfo 
  WHERE carrid = 'LH' 
  INTO TABLE @DATA(lt_flights).

Performance Tip: CDS views can significantly improve performance by pushing filtering, joining, and aggregation to the database layer. Always consider using CDS views for complex data retrieval operations.

6. Implement Exception-Based Error Handling

ABAP 7.4 fully supports class-based exceptions, which provide a more structured approach to error handling compared to traditional ABAP error handling with sy-subrc.

* Define a custom exception class
CLASS zcx_flight_not_found DEFINITION
  PUBLIC
  INHERITING FROM cx_static_check
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS constructor
      IMPORTING
        textid   LIKE textid OPTIONAL
        previous LIKE previous OPTIONAL
        carrid   TYPE s_carr_id
        connid   TYPE s_conn_id.

    DATA: carrid TYPE s_carr_id READ-ONLY,
          connid TYPE s_conn_id READ-ONLY.
ENDCLASS.

* Use exceptions in your methods
METHODS get_flight
  IMPORTING
    iv_carrid      TYPE s_carr_id
    iv_connid      TYPE s_conn_id
  RETURNING
    VALUE(rs_flight) TYPE spfli
  RAISING
    zcx_flight_not_found.

METHOD get_flight.
  SELECT SINGLE * FROM spfli
    WHERE carrid = @iv_carrid
    AND connid = @iv_connid
    INTO @rs_flight.
  
  IF sy-subrc <> 0.
    RAISE EXCEPTION TYPE zcx_flight_not_found
      EXPORTING
        carrid = iv_carrid
        connid = iv_connid.
  ENDIF.
ENDMETHOD.

* Call the method with exception handling
TRY.
    DATA(ls_flight) = get_flight( 
      iv_carrid = 'LH'
      iv_connid = '0400' 
    ).
    * Process flight data
  CATCH zcx_flight_not_found INTO DATA(lx_not_found).
    * Handle exception
    DATA(lv_error_msg) = |Flight { lx_not_found->carrid } { lx_not_found->connid } not found|.
ENDTRY.

7. Use Constructor Expressions

Constructor expressions allow you to create and populate complex data structures in a single statement, making your code more concise and readable.

* Old style
DATA: ls_flight TYPE spfli.

ls_flight-carrid = 'LH'.
ls_flight-connid = '0400'.
ls_flight-cityfrom = 'FRANKFURT'.
ls_flight-cityto = 'NEW YORK'.

* New style with constructor expression
DATA(ls_flight) = VALUE spfli( 
  carrid = 'LH'
  connid = '0400'
  cityfrom = 'FRANKFURT'
  cityto = 'NEW YORK'
).

* Create and fill internal table
DATA(lt_flights) = VALUE tt_flights( 
  ( carrid = 'LH' connid = '0400' cityfrom = 'FRANKFURT' cityto = 'NEW YORK' )
  ( carrid = 'LH' connid = '0401' cityfrom = 'FRANKFURT' cityto = 'BOSTON' )
).

* BASE addition to preserve existing content
DATA(lt_more_flights) = VALUE tt_flights( 
  BASE lt_flights
  ( carrid = 'AA' connid = '0017' cityfrom = 'NEW YORK' cityto = 'CHICAGO' )
).

8. Implement Unit Tests with ABAP Unit

ABAP 7.4 includes robust support for unit testing through ABAP Unit. Implementing unit tests improves code quality and makes refactoring safer.

CLASS ltcl_flight_service_test DEFINITION FINAL FOR TESTING
  DURATION SHORT
  RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    DATA:
      mo_flight_service TYPE REF TO zcl_flight_service,
      mo_mock_database  TYPE REF TO lcl_mock_database.

    METHODS:
      setup,
      test_get_flight FOR TESTING,
      test_flight_not_found FOR TESTING.
ENDCLASS.

CLASS ltcl_flight_service_test IMPLEMENTATION.
  METHOD setup.
    mo_mock_database = NEW #( ).
    mo_flight_service = NEW #( io_database = mo_mock_database ).
  ENDMETHOD.

  METHOD test_get_flight.
    * Prepare test data
    mo_mock_database->add_flight( 
      VALUE #( carrid = 'LH' connid = '0400' cityfrom = 'FRANKFURT' cityto = 'NEW YORK' )
    ).

    * Execute method under test
    DATA(ls_flight) = mo_flight_service->get_flight( 
      iv_carrid = 'LH'
      iv_connid = '0400'
    ).

    * Verify result
    cl_abap_unit_assert=>assert_equals(
      act = ls_flight-cityfrom
      exp = 'FRANKFURT'
      msg = 'Incorrect departure city'
    ).
    cl_abap_unit_assert=>assert_equals(
      act = ls_flight-cityto
      exp = 'NEW YORK'
      msg = 'Incorrect destination city'
    ).
  ENDMETHOD.

  METHOD test_flight_not_found.
    * Execute method under test and expect exception
    TRY.
        mo_flight_service->get_flight( 
          iv_carrid = 'XX'
          iv_connid = '9999'
        ).
        
        cl_abap_unit_assert=>fail( 'Exception was expected but not raised' ).
      CATCH zcx_flight_not_found.
        * Exception was expected, test passes
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

Conclusion

ABAP 7.4 introduced a wealth of features that can significantly improve your development productivity and code quality. By adopting these modern ABAP programming techniques, you can write more concise, readable, and maintainable code.

Remember that while these new features are powerful, they should be used judiciously. Always consider readability and maintainability when deciding which features to use in your projects. And as with any programming language, consistent coding standards across your team are essential for long-term success.

Raghu Krishnappa

Raghu Krishnappa

Founder & SAP Consultant at Tuscan Consulting with over 20 years of experience in SAP implementations and ABAP development.