Modularization Part 7: Global Classes vs Local Classes
Decide where a class belongs: local classes inside one program vs global classes in the class library (SE24/ADT) — reuse, visibility, testing, transport, naming, and how to promote a local class to a global one.
Explanation
📌 KEY POINTS
✅ Local classes live inside one program (report, function group, class include) — only that program can use them.
✅ Global classes (ZCL_…) live in the class library — reusable by any program, transported as their own objects.
✅ Start local for program-specific logic; make it global when a second consumer appears.
💡 Local test classes (FOR TESTING) belong in the test include of the global class or program.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 6 wrote a local class. This part answers where classes should live.
━━━━━━━━━━━━━━━━━━━━
▶ 1. LOCAL CLASSES
- Defined in the program (or its includes).
- Perfect for structuring a report: lcl_report, lcl_alv_handler, lcl_data_access.
- No naming pollution in the system; changes affect only that program.
- Can't be reused by other programs.
━━━━━━━━━━━━━━━━━━━━
▶ 2. GLOBAL CLASSES
- Created in SE24 (form-based or source-code editor) or ADT; name ZCL_… / YCL_….
- Visible system-wide, have their own transport object, documentation and where-used list.
- Suitable for services used by many programs: ZCL_FLIGHT_SERVICE, ZCL_BOOKING_VALIDATOR.
- Global classes can also contain local helper classes (local types include) and local test classes (test classes include).
━━━━━━━━━━━━━━━━━━━━
▶ 3. WHEN TO GO GLOBAL
- A second program needs the same logic.
- The logic is a stable service (validation, calculation, data access for a business object).
- It is called from function modules, BAdIs, RFC wrappers or other classes.
Don't make everything global "just in case" — global means a maintained interface.
━━━━━━━━━━━━━━━━━━━━
▶ 4. NAMING AND ORGANIZATION
- Global: ZCL_<AREA>_<PURPOSE>, interfaces ZIF_…, exceptions ZCX_….
- Local: lcl_, lif_, lcx_, test classes ltc_.
- Package per functional area.
━━━━━━━━━━━━━━━━━━━━
▶ 5. PROMOTING A LOCAL CLASS
In ADT: refactoring or copy the local class definition/implementation into a new global class; replace references; keep the program's local class as thin adapter if needed; move its unit tests to the global class's test include.
━━━━━━━━━━━━━━━━━━━━
▶ 6. FRIENDS AND TEST ACCESS
A class can declare FRIENDS to allow another class (e.g. a test class) access to private members. Use sparingly — prefer testing via public methods.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Keep lcl_report local in your report.
- Move the flight service logic into global ZCL_FLIGHT_SERVICE (code example).
- Use it from two different programs.
✅ CHECKPOINT: you place classes deliberately — local for program structure, global for reuse.
Code example
* ===== Global class ZCL_FLIGHT_SERVICE (SE24) =====CLASS zcl_flight_service DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. TYPES ty_flights TYPE STANDARD TABLE OF sflight WITH DEFAULT KEY. METHODS constructor IMPORTING iv_carrid TYPE s_carr_id. METHODS get_flights RETURNING VALUE(rt_flights) TYPE ty_flights. CLASS-METHODS free_seats IMPORTING is_flight TYPE sflight RETURNING VALUE(rv_free) TYPE i. PRIVATE SECTION. DATA mv_carrid TYPE s_carr_id.ENDCLASS. CLASS zcl_flight_service IMPLEMENTATION. METHOD constructor. mv_carrid = iv_carrid. ENDMETHOD. METHOD get_flights. SELECT * FROM sflight INTO TABLE rt_flights WHERE carrid = mv_carrid. ENDMETHOD. METHOD free_seats. rv_free = is_flight-seatsmax - is_flight-seatsocc. ENDMETHOD.ENDCLASS. * ===== Test class (local test classes include of ZCL_FLIGHT_SERVICE) =====* CLASS ltc_free_seats DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.* PRIVATE SECTION. METHODS full_flight FOR TESTING.* ENDCLASS.* CLASS ltc_free_seats IMPLEMENTATION.* METHOD full_flight.* DATA: ls_flight TYPE sflight, lv_free TYPE i.* ls_flight-seatsmax = 100. ls_flight-seatsocc = 100.* lv_free = zcl_flight_service=>free_seats( ls_flight ).* cl_abap_unit_assert=>assert_equals( act = lv_free exp = 0 ).* ENDMETHOD.* ENDCLASS. * ===== Consumer 1: report (local class only for report structure) =====REPORT zmod_part7.PARAMETERS p_carr TYPE s_carr_id DEFAULT 'LH'. CLASS lcl_report DEFINITION. PUBLIC SECTION. CLASS-METHODS run IMPORTING iv_carr TYPE s_carr_id.ENDCLASS. CLASS lcl_report IMPLEMENTATION. METHOD run. DATA: lo_service TYPE REF TO zcl_flight_service, lt_flights TYPE zcl_flight_service=>ty_flights, ls_f TYPE sflight, lv_free TYPE i. CREATE OBJECT lo_service EXPORTING iv_carrid = iv_carr. " global service lt_flights = lo_service->get_flights( ). LOOP AT lt_flights INTO ls_f. lv_free = zcl_flight_service=>free_seats( ls_f ). WRITE: / ls_f-connid, ls_f-fldate, lv_free. ENDLOOP. ENDMETHOD.ENDCLASS. START-OF-SELECTION. lcl_report=>run( p_carr ). * ===== Consumer 2: e.g. an RFC function module or a BAdI uses the same class =====* 💡 Modern syntax (7.40+): DATA(lo_service) = NEW zcl_flight_service( iv_carr ).Real project scenario
Three reports each had a local class with nearly identical "booking validation" logic. A new validation rule was added to two of them; the third kept accepting invalid bookings, which surfaced only in an audit.
The team promoted the logic to a global class ZCL_BOOKING_VALIDATOR with unit tests and replaced the three local copies with calls to it. The reports kept their own local classes for UI and flow — a clean split between program structure and reusable services.
Common mistakes
- Copying local classes between programs instead of creating a global one.
- Making every helper global without a real second consumer.
- No unit tests in global classes.
- Inconsistent naming (ZCL vs local lcl).
- Overusing FRIENDS to access private data.
Best practices
- Local classes for program structure; global classes for reusable services.
- Promote to global when a second consumer appears.
- Keep global interfaces small and stable; document them.
- Put unit tests in the global class's test include.
- Follow naming conventions (ZCL_, ZIF_, ZCX_, lcl_, ltc_).
Interview angle
Questions: "Local vs global class?", "When do you make a class global?", "Where do unit tests of a global class live?"
Strong answer: local classes exist only in their program and structure it; global classes in the class library are reusable system-wide with their own transport and documentation; go global when logic is reused or is a stable service, not by default; unit tests live in the test classes include; follow naming conventions.
Practice this lesson
Quick check
1. Where is a local class visible?
2. A local class in report A must now be used by reports B and C. What is the right approach?
3. PRIVATE visibility means:
Interview questions
1. A customer validation rule was written as a local class in one report. Now two other programs need it. What do you do?
Answer it in your own words first, then compare.
2. How do you evolve a legacy function group into a service class without breaking callers?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- Modularization Part 1: Why and How to Split ABAP Programs
- Modularization Part 10: Modularization for Unit Testing and Regression Safety
- Modularization Part 2: FORM Routines — Legacy but Still Important
- Modularization Part 3: FORM vs Method vs Function Module
- Modularization Part 4: Function Modules and Function Groups
- Modularization Part 5: Update Function Modules and IN UPDATE TASK
- Modularization Part 6: Methods and Local Classes
- Modularization Part 8: Parameter Passing — IMPORTING, EXPORTING, CHANGING and RETURNING