ABAP

Tier 1 vs 2 vs 3 — 확장 레벨 선택법 #shorts #SAP #ABAP

같은 요건, 세 갈래의 길

SAP S/4HANA와 ABAP Platform 환경에서 표준 기능을 확장할 때, 어떤 방식을 고를지 망설인 경험이 한 번쯤 있을 겁니다. 같은 "판매 오더에 프로모션 코드 필드 하나 추가"라는 요건이라도 Tier 1(Key User), Tier 2(Developer Extensibility), Tier 3(Classic) 중 어느 길을 택하느냐에 따라 업그레이드 안정성, 권한 모델, 개발 공수가 완전히 달라집니다. 이 글에서는 세 가지 확장 레벨의 동작 원리를 비교하고, 동일한 시나리오(SalesOrder 커스텀 필드 추가)를 세 방식으로 구현하면서 선택 기준을 정리합니다.

  • Tier 1/2/3의 기술적 경계와 책임 분리 이해
  • 각 Tier별 적용 가능한 SAP 에디션 식별
  • 동일 요건을 세 방식으로 구현한 코드 비교
  • 업그레이드 안정성 관점에서 의사결정 기준 수립

먼저 알아두면 좋은 배경

ABAP Dictionary(DDIC) 기본 구조, CDS View 문법, BAdI(Business Add-In) 개념, 그리고 ABAP RESTful Application Programming Model(RAP)의 큰 그림을 어느 정도 알고 있어야 코드 예제가 자연스럽게 읽힙니다. Fiori Launchpad에서 Custom Field & Logic, Custom CDS View 같은 Key User App을 한 번이라도 열어본 경험이 있다면 더 좋습니다. 표준 Z 네임스페이스와 ZZ1_ 접두어의 차이를 알고 있다면 절반은 따라온 셈입니다.

실습 환경과 준비물

예제는 다음 환경을 기준으로 합니다. 에디션별로 사용할 수 있는 Tier가 달라지므로 본인 시스템과 비교해 확인이 필요합니다.

  • SAP S/4HANA Cloud Public Edition 2402 이상 — Tier 1 전용
  • SAP S/4HANA Cloud Private Edition / SAP S/4HANA 2023 on-premise — Tier 1 + Tier 2 + (제한적) Tier 3
  • SAP BTP, ABAP Environment(Steampunk) — Tier 2 Developer Extensibility 전용
  • ADT(ABAP Development Tools) for Eclipse 2023-09 이상
  • Fiori Launchpad 접근 권한 + SAP_BR_EXTENSIBILITY_SPEC 비즈니스 역할
  • Key User App: "Custom Fields", "Custom Logic", "Custom Business Objects"
Cloud Public 에디션에서는 Tier 3(클래식 수정)이 원천적으로 차단됩니다. 반대로 순수 on-premise 환경에서도 Tier 1을 활용할 수 있지만, 권장 범위와 활성화 절차는 시스템 설정에 따라 달라집니다.

3-Tier 확장 모델의 동작 원리

SAP는 Clean Core 전략을 통해 "표준은 건드리지 말고, 확장은 명시적인 인터페이스로만"이라는 원칙을 강하게 밀고 있습니다. 이 원칙을 세 단계 구조로 표현한 것이 Tier 1/2/3 모델입니다.

  • Tier 1 — Key User Extensibility (In-App): 업무 사용자가 Fiori 앱 안에서 마우스 클릭으로 필드 추가, 로직 삽입, UI 변경을 수행합니다. 메타데이터로 저장되며 업그레이드 시 시스템이 자동으로 호환성을 책임지는 방향으로 설계되어 있습니다.
  • Tier 2 — Developer Extensibility (On-Stack): ABAP 개발자가 ADT에서 released ABAP API와 RAP을 활용해 별도 패키지에 확장을 작성합니다. 표준 코드는 손대지 않고, 화이트리스트된 객체만 사용합니다.
  • Tier 3 — Classic Extensibility: 전통적인 BAdI, User-Exit, Enhancement Point, Modification Assistant 등을 통해 표준 코드를 확장하거나 수정합니다. 가장 자유롭지만 업그레이드 시 충돌 가능성이 가장 높습니다.

비유하자면 Tier 1은 아파트 인테리어의 가구 재배치, Tier 2는 베란다 확장 공사(허가된 범위), Tier 3은 내력벽 일부를 건드리는 리모델링에 가깝습니다. 자유도와 위험도가 반비례합니다.

구분Tier 1Tier 2Tier 3
주 사용자Key UserABAP DeveloperABAP Developer
도구Fiori Key User AppsADT + RAPSE80, SE19, SE38
업그레이드 안정성매우 높음높음 (Released API 한정)중간~낮음
적합 케이스필드/룰 추가, UI 조정업무 객체 신규, 복잡 로직레거시 통합, Core 수정
Cloud Public 지원OXX

1단계 — Tier 1: Key User로 SalesOrder에 커스텀 필드 추가

판매 오더에 "프로모션 코드(ZZ1_PromoCode)" 필드를 추가해 보겠습니다. Fiori Launchpad에서 Custom Fields 앱을 열고 Business Context로 "Sales: Sales Order"를 선택합니다. UI 화면에서 입력만 하면 되지만, 내부적으로 생성되는 메타데이터는 결국 CDS Extension View와 동일한 형태가 됩니다.

// 시스템이 Key User 입력을 기반으로 자동 생성하는 Extension View (개념적 표현)
extend view I_SalesOrder with ZZ1_SalesOrderPromoExt
  association [0..1] to I_PromoCode as _Promo
    on $projection.ZZ1_PromoCode = _Promo.PromoCode
{
  @Consumption.valueHelpDefinition: [{ entity: { name: 'I_PromoCode', element: 'PromoCode' } }]
  @EndUserText.label: 'Promotion Code'
  ZZ1_PromoCode,
  _Promo
}

필드를 추가한 뒤 같은 앱의 "UI and Reports" 탭에서 OData 서비스, 분석 쿼리, Form Template 중 어느 영역까지 노출할지 체크합니다. Custom Logic 앱에서는 BAdI 후보 위치(예: "Sales Order — Validation")에 다음과 같은 짧은 ABAP 스니펫을 입력할 수 있습니다.

" Custom Logic — BAdI: Validate Sales Order at Save
IF salesorder-zz1_promocode IS NOT INITIAL AND
   salesorder-totalnetamount < 10000.
  APPEND VALUE #(
    messagetype = 'E'
    messagetext = |Promo { salesorder-zz1_promocode } requires net amount >= 10,000| )
    TO messages.
ENDIF.

Key User는 SE80을 열 필요도, Transport Request를 직접 생성할 필요도 없습니다. 변경 사항은 Software Collection으로 묶여 자동으로 운반되며, 다음 업그레이드 때도 메타데이터 호환성이 시스템 측에서 관리되도록 설계되어 있습니다.

2단계 — Tier 2: Developer Extensibility로 외부 호출 + 보강 로직

Tier 1만으로는 외부 시스템 호출이나 복잡한 트랜잭션 로직을 표현하기 어렵습니다. 이런 경우 ADT에서 ABAP Cloud 개발 모드로 별도 패키지(ZPROMO_EXT)를 만들고, released BAdI를 구현합니다. 아래 예제는 가상의 외부 프로모션 엔진에 HTTP 호출을 보내 할인율을 가져오는 로직입니다.

CLASS zcl_promo_so_enhancer DEFINITION
  PUBLIC FINAL CREATE PUBLIC
  FOR BEHAVIOR OF ZI_SalesOrder.

  PUBLIC SECTION.
    METHODS enrich_promo FOR MODIFY
      IMPORTING keys FOR ACTION SalesOrder~enrichPromo.
ENDCLASS.

CLASS zcl_promo_so_enhancer IMPLEMENTATION.
  METHOD enrich_promo.
    DATA(log) = cl_bali_log_factory=>create_log(
                  VALUE #( object = 'ZPROMO' subobject = 'ENRICH' ) ).

    TRY.
        DATA(dest)   = cl_http_destination_provider=>create_by_comm_arrangement(
                          comm_scenario = 'ZPROMO_ENGINE_SCN'
                          service_id    = 'ZPROMO_REST' ).
        DATA(client) = cl_web_http_client_manager=>create_by_http_destination( dest ).

        LOOP AT keys INTO DATA(key).
          DATA(req)  = client->get_http_request( ).
          req->set_uri_path( |/promo/{ key-zz1_promocode }| ).
          DATA(resp) = client->execute( if_web_http_client=>get ).

          IF resp->get_status( )-code = 200.
            DATA(payload) = /ui2/cl_json=>generate( json = resp->get_text( ) ).
            MODIFY ENTITIES OF zi_salesorder IN LOCAL MODE
              ENTITY SalesOrder
                UPDATE FIELDS ( zz1_discountpct )
                WITH VALUE #( ( salesorderid    = key-salesorderid
                                zz1_discountpct = payload->*-discount ) )
              REPORTED DATA(rep).
          ENDIF.
        ENDLOOP.

      CATCH cx_web_http_client_error cx_http_dest_provider_error INTO DATA(ex).
        log->add_exception( ex ).
        APPEND VALUE #( %msg = new_message_with_text(
                          severity = if_abap_behv=>ms-error
                          text     = ex->get_text( ) ) ) TO reported-salesorder.
    ENDTRY.

    cl_bali_log_saver=>save_log( log ).
  ENDMETHOD.
ENDCLASS.

핵심은 cl_web_http_client_manager, cl_bali_log_factory처럼 명시적으로 released 처리된 API만 사용한다는 점입니다. ADT는 ABAP Cloud 모드에서 비공개 API 사용을 컴파일 단계에서 차단해 줍니다. 패키지 속성을 "ABAP for Cloud Development"로 지정하면 강제 적용됩니다. 외부 연결은 SM59가 아닌 Communication Arrangement(SCC4와 별개)를 통해 관리되므로, 운영자가 키 로테이션·인증서 갱신을 한 곳에서 통제할 수 있는 장점이 있습니다.

3단계 — Tier 3: Classic BAdI로 동일 요건 구현 (on-premise 한정)

기존 ECC에서 마이그레이션한 시스템이라면 Tier 3 방식이 익숙할 겁니다. 같은 요건을 클래식 BAdI 구현으로 풀어보면 다음과 같습니다. SE19에서 Enhancement Implementation을 생성하고 메서드를 채웁니다.

METHOD if_ex_badi_sd_sales_item~check_promo.
  DATA: lt_log TYPE bal_t_msg,
        ls_msg TYPE bal_s_msg,
        lv_disc TYPE p DECIMALS 2.

  CHECK is_vbap-zzpromocode IS NOT INITIAL.

  CALL FUNCTION 'Z_PROMO_ENGINE_LOOKUP'
    EXPORTING
      iv_code   = is_vbap-zzpromocode
    IMPORTING
      ev_disc   = lv_disc
    EXCEPTIONS
      not_found = 1
      OTHERS    = 2.

  IF sy-subrc <> 0.
    ls_msg-msgty = 'E'.
    ls_msg-msgid = 'ZPROMO'.
    ls_msg-msgno = '001'.
    ls_msg-msgv1 = is_vbap-zzpromocode.
    APPEND ls_msg TO ct_messages.
    RETURN.
  ENDIF.

  cs_vbap-zzdiscountpct = lv_disc.

  PERFORM write_appl_log USING 'ZPROMO' 'ITEM' ls_msg.
ENDMETHOD.

코드 자체는 단순하지만 ZZPROMOCODE, ZZDISCOUNTPCT 컬럼을 VBAP에 append structure로 직접 추가해야 하고, 표준 화면(VA01)도 Screen Exit 또는 GuiXT를 통해 노출해야 합니다. 다음 S/4HANA 업그레이드 시 표준 코드가 BAdI 시그니처를 변경하면 활성화가 깨질 수 있으니 SPAU/SPDD 단계에서 일일이 검토해야 합니다. 또한 SAP가 동일 영역에 새로운 Released API를 제공하기 시작하면, 동일 기능이 Tier 2 코드와 중복돼 유지보수 비용이 두 배로 늘기 쉽습니다.

자주 부딪히는 실수와 트러블슈팅

Q1. Custom Field가 OData 서비스에 노출되지 않습니다. Custom Fields 앱의 "UI and Reports" 탭에서 해당 Business Context의 서비스 항목을 체크했는지 확인하세요. Publish 단계를 건너뛰면 메타데이터만 생성되고 런타임 노출은 일어나지 않습니다. 또한 캐시 갱신을 위해 /IWFND/CACHE_CLEANUP 실행이 필요할 수 있습니다.

Q2. ABAP Cloud 모드에서 기존 함수 모듈 호출이 "use of object is not permitted"로 막힙니다. 해당 객체가 released 상태인지 ADT의 API State 뷰에서 확인하세요. released되지 않았다면 Custom Communication Scenario를 사용하거나, on-stack 환경에서는 Wrapper Class를 만들고 표준 객체에 대한 사용 승인(Use System-Internal) 절차를 거칩니다.

Q3. Tier 1으로 만든 필드를 Tier 2에서 참조하고 싶습니다. 가능합니다. Custom Field는 내부적으로 표준 CDS Extension으로 구현되므로 ZZ1_ 접두어가 붙은 요소를 Tier 2의 Behavior나 Projection View에서 참조할 수 있습니다. 다만 Key User가 필드를 삭제하면 Tier 2 코드가 깨지므로 의존 관계를 문서화해두는 편이 안전합니다.

Q4. Tier 3 BAdI를 새로 도입해도 되나요? 신규 프로젝트라면 가능한 한 Tier 1/2로 우회하는 것이 권장됩니다. 그래도 Tier 3을 선택해야 한다면 해당 Enhancement Spot이 SAP에 의해 명시적으로 제공된 위치인지, modification이 아닌 enhancement인지 먼저 확인하세요. 또한 SPAU/SPDD 시 충돌 검토 책임자가 누구인지 운영 가이드에 명시해 두는 것이 좋습니다.

Q5. 동일 시점에 Tier 1과 Tier 2 로직이 모두 실행되면 순서는? 일반적으로 Tier 2(Released BAdI)가 먼저 실행되고 Tier 1(Custom Logic)이 뒤이어 호출되는 패턴이 자주 관측되지만, 정확한 호출 순서는 BAdI 정의(Multiple Use, Filter)와 시스템 버전에 따라 달라지므로 ABAP 디버거로 검증하는 것이 권장됩니다.

여기서 더 파보면 좋은 것들

이 글에서 다룬 세 Tier의 경계가 이해됐다면, 다음 주제들이 자연스러운 후속 학습 경로입니다.

  • Custom Business Object와 Custom Analytical Query로 완전히 새로운 업무 객체 만들기
  • BTP Side-by-Side Extensibility — SAP Build Apps, Event Mesh와 결합한 비ABAP 확장
  • ABAP Cloud Development Model의 3-Layer Software Stack(Foundation / Public Cloud / Private Cloud) 이해
  • Clean Core Dashboard와 Custom Code Migration App을 활용한 기존 Z코드 평가
  • RAP의 Managed/Unmanaged Behavior 차이와 Draft 처리

더 읽어볼 만한 자료

댓글 0

아직 댓글이 없습니다.