개요 및 목표
SAP S/4HANA Cloud와 On-Premise 환경에서 표준으로 제공되는 Business Object(BO)를 확장할 때, 과거처럼 APPEND나 소스 수정으로 접근하면 다음 릴리스에서 필드 충돌·활성화 실패·업그레이드 롤백이라는 값비싼 대가를 치릅니다. RAP(RESTful ABAP Programming Model)이 등장하면서 SAP는 Extension Include라는 별도 확장 계층을 제공했고, 이 계층은 표준 BDEF(Behavior Definition)·CDS View·핸들러 클래스와 느슨하게 결합되어 업그레이드 시에도 안전하게 보존됩니다.
이 글을 다 읽고 나면 다음을 수행할 수 있습니다.
- Extension Include의 동작 원리와 표준 BO 확장 지점 3가지(필드·액션·결정) 구분
- 표준
PurchaseOrderBO에 커스텀 필드와 액션을 추가하는 실무 코드 작성 - Extend BDEF, Extend View Entity, Extend Behavior Implementation을 조합한 완전한 확장 스택 구성
- 업그레이드 안전성(upgrade safety) 검증을 위한 ATC 체크와 릴리스 컨트랙트 확인
사전에 알고 있어야 할 것
이 글은 advanced 난이도이며, 다음 개념에 익숙하다는 전제로 진행합니다. RAP Managed/Unmanaged 시나리오 차이, CDS View Entity와 define behavior 구문, ABAP Cloud Development Model(Steampunk 포함) 개발 규칙, Behavior Pool의 FOR MODIFY·FOR VALIDATE 핸들러 메서드 시그니처, 그리고 Extension Point와 Enhancement Framework의 개념적 차이. Fiori Elements 앱을 한 번 이상 배포해 본 경험이 있으면 UI 확장까지 무리 없이 따라올 수 있습니다.
환경, 버전, 준비물
실전 예제는 다음 환경 조합에서 검증한 내용을 기준으로 재구성했습니다.
- ABAP Platform: SAP S/4HANA 2023 On-Premise 또는 ABAP Environment 2402 릴리스 이상 (Extension Include는 2020 릴리스부터 지원되지만 BDEF 확장 문법은 2208 이후 성숙)
- 개발 도구: ADT(ABAP Development Tools) for Eclipse 2024-03 또는 그 이후
- 대상 BO: SAP 표준으로 릴리스된
I_PurchaseOrderTP(BO 이름은 프로젝트별로 다를 수 있으므로 릴리스된 오브젝트인지API State로 반드시 확인) - 필요 권한: 개발 사용자에
S_DEVELOP과 확장 대상 패키지에 대한 Software Component 쓰기 권한. Cloud 환경은 ABAP Cloud를 통한 Extend 명령 사용 - 추가 준비물: 확장 필드용 Domain/Data Element를 담을 커스텀 패키지, ATC 변형
ABAP_CLOUD_DEFAULT
표준 오브젝트가 Cloud Development(C1) contract로 릴리스되어 있는지 반드시 사전 확인해야 하며, 그렇지 않은 오브젝트는 Extension Include로 확장할 수 없습니다.
핵심 개념 이해
Extension Include를 이해하는 가장 좋은 비유는 레고 확장판입니다. 표준 BO는 완성된 레고 세트이고, SAP는 그 세트의 특정 위치에 "여기에 블록을 붙일 수 있음"이라고 표시된 스터드(stud)를 미리 심어 둡니다. 스터드는 CDS 뷰의 extend view entity, BDEF의 extend behavior definition, Behavior Pool의 local handler라는 세 종류로 나타납니다. 개발자는 스터드가 있는 곳에만 자신의 블록을 얹을 수 있고, SAP는 스터드가 아닌 부분은 자유롭게 리팩터링합니다. 다음 릴리스에서 내부 구조가 바뀌어도 스터드 위치와 계약(contract)은 유지되므로, 개발자의 확장은 그대로 살아남습니다.
과거 APPEND STRUCTURE 방식은 표준 DDIC 구조에 필드를 물리적으로 삽입하는 침습적(invasive) 확장이었습니다. 필드 하나를 추가하면 표준 뷰·게이트웨이 프로젝션·OData 메타데이터가 전부 재활성화되어야 했고, SAP가 동일 이름의 필드를 표준에 추가하는 순간 활성화가 깨졌습니다. Extension Include는 이 문제를 계층 분리로 해결합니다. 확장 필드는 별도 Extension Structure에 담기고, 표준 CDS 뷰는 이를 Extension Include 어노테이션으로만 참조합니다. 표준 코드는 확장을 알지 못한 채 컴파일되고, 확장은 표준 계약이 유지되는 한 자동으로 통합됩니다.
BDEF 관점에서는 세 가지 확장 지점이 열려 있습니다. 첫째, extend behavior for 구문으로 표준 BO에 새로운 액션(action)·결정(determination)·검증(validation)을 붙일 수 있습니다. 둘째, 필드 특성 확장으로 표준 필드에 readonly·mandatory 등을 덮어씌울 수 있습니다. 셋째, 사이드 이펙트(side effect)를 확장해서 표준 필드 변경이 확장 필드에 즉시 반영되도록 만들 수 있습니다. 이 세 지점은 SAP가 API contract로 보증하는 영역이며, ATC의 Cloud Readiness 체크가 위반 여부를 자동 감지합니다.
실전 코드 3단계
1단계 — 기본: 표준 PurchaseOrder에 배송 우선순위 필드 추가
구매팀이 표준 필드에 없는 DeliveryPriority를 관리해야 한다는 요구가 들어왔습니다. 먼저 Custom Field를 담을 Extension Include 구조를 정의합니다.
@EndUserText.label: 'PO Delivery Priority Extension'
@AbapCatalog.enhancement.category: #EXTENSIBLE_CHARACTER
define structure ZPO_EXT_PRIO {
delivery_priority : abap.char(2);
priority_reason : abap.char(60);
}
이어서 표준 I_PurchaseOrderTP View Entity를 확장합니다. 이때 extend view entity 구문을 사용하며, 표준 뷰의 별칭(PO)을 통해 확장 필드를 조인이 아니라 추가 컬럼으로 노출합니다.
extend view entity I_PurchaseOrderTP with ZPO_EXT_PRIO_V {
cast('' as abap.char(2)) as DeliveryPriority,
cast('' as abap.char(60)) as PriorityReason
}
초기값을 cast로 둔 이유는, 실제 데이터가 저장될 Extension Table을 이후 단계에서 붙이기 위함입니다. 1단계에서는 필드가 CDS 표면에 노출되고 Fiori Elements 앱에서 인식되는 것까지가 목표입니다.
2단계 — 실무 시나리오: BDEF 확장, 저장 처리, 검증 로직
확장 필드에 실제 값을 저장·검증하려면 BDEF와 Behavior Pool을 확장해야 합니다. 먼저 표준 BDEF를 확장하는 별도 BDEF 파일을 만듭니다.
extension
extend behavior for I_PurchaseOrderTP
{
extension
field ( mandatory : create ) DeliveryPriority;
field PriorityReason;
validation validatePriority on save
{ field DeliveryPriority; create; update; }
determination setDefaultPriority on modify
{ create; }
side effects
{
field DeliveryPriority affects field PriorityReason;
}
}
확장 로직을 담을 별도 Behavior Pool을 만들고, FOR BEHAVIOR OF 대신 EXTENSION FOR BEHAVIOR OF로 선언한다는 점이 핵심입니다.
CLASS zbp_i_purchaseordertp_ext DEFINITION
PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF I_PurchaseOrderTP.
ENDCLASS.
CLASS lhc_purchaseorder_ext IMPLEMENTATION.
METHOD validatePriority.
READ ENTITIES OF i_purchaseordertp IN LOCAL MODE
ENTITY PurchaseOrder
FIELDS ( DeliveryPriority )
WITH CORRESPONDING #( keys )
RESULT DATA(orders).
LOOP AT orders INTO DATA(order).
IF order-DeliveryPriority NOT IN ( 'A1', 'A2', 'B1', 'B2', 'C1' ).
APPEND VALUE #(
%tky = order-%tky
%msg = new_message(
id = 'ZPO_EXT'
number = '001'
severity = if_abap_behv_message=>severity-error
v1 = order-DeliveryPriority )
%element-DeliveryPriority = if_abap_behv=>mk-on
) TO reported-purchaseorder.
APPEND VALUE #( %tky = order-%tky ) TO failed-purchaseorder.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setDefaultPriority.
" 신규 생성 시 우선순위가 비어있으면 기본값 B2 부여
MODIFY ENTITIES OF i_purchaseordertp IN LOCAL MODE
ENTITY PurchaseOrder
UPDATE FIELDS ( DeliveryPriority )
WITH VALUE #( FOR k IN keys
( %tky = k-%tky
DeliveryPriority = 'B2' ) )
REPORTED DATA(update_reported).
ENDMETHOD.
ENDCLASS.
실무에서는 검증 실패 시 reported·failed를 정확히 채우는 것이 매우 중요합니다. 이 두 테이블이 비어 있으면 Fiori UI에서 오류 배지가 뜨지 않아 사용자에게 무엇이 잘못됐는지 전달되지 않습니다.
3단계 — 프로덕션: 성능·테스트·업그레이드 안전성
운영 환경 배포 전에 세 가지를 반드시 점검합니다. 첫째, Extension Table을 별도로 두어 표준 트랜잭션의 잠금 범위와 격리합니다.
@EndUserText.label: 'PO Priority Persistence'
define table zpo_prio_ext {
key mandt : mandt not null;
key purchase_order : ebeln not null;
delivery_priority : abap.char(2);
priority_reason : abap.char(60);
last_changed_at : timestampl;
last_changed_by : abp_lastchange_user;
}
둘째, ABAP Unit으로 확장 로직만 격리 테스트합니다. RAP Test Double Framework를 활용하면 표준 BO를 실행하지 않고도 확장 핸들러를 단독 검증할 수 있습니다.
CLASS ltc_priority_validation DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
CLASS-DATA environment TYPE REF TO if_cds_test_environment.
CLASS-METHODS class_setup.
METHODS invalid_priority_is_rejected FOR TESTING.
ENDCLASS.
CLASS ltc_priority_validation IMPLEMENTATION.
METHOD class_setup.
environment = cl_cds_test_environment=>create(
i_for_entity = 'I_PurchaseOrderTP' ).
ENDMETHOD.
METHOD invalid_priority_is_rejected.
environment->insert_test_data( VALUE #(
( PurchaseOrder = '4500000123'
DeliveryPriority = 'ZZ' ) ) ).
MODIFY ENTITIES OF i_purchaseordertp
ENTITY PurchaseOrder EXECUTE validatePriority
FROM VALUE #( ( %tky-PurchaseOrder = '4500000123' ) )
FAILED DATA(failed)
REPORTED DATA(reported).
cl_abap_unit_assert=>assert_not_initial( failed ).
ENDMETHOD.
ENDCLASS.
셋째, ATC 변형 ABAP_CLOUD_DEFAULT를 확장 패키지 전체에 돌려서 사용 가능한 API 검사·릴리스 컨트랙트 위반·Cloudification 경고가 없는지 확인합니다. Extension Include로 확장했더라도 표준 필드에 직접 SELECT하거나 릴리스되지 않은 클래스를 참조하면 다음 릴리스에서 활성화 실패가 발생할 수 있습니다.
자주 만나는 실수와 문제 해결
실수 1: Extension Include를 릴리스되지 않은 표준 오브젝트에 시도. 대상 CDS나 BDEF가 API State: Released가 아니면 확장 자체가 컴파일되지 않거나, 컴파일되어도 다음 SP에서 깨집니다. 반드시 ADT의 오브젝트 속성 화면에서 릴리스 상태와 릴리스 컨트랙트(C0/C1/C2)를 먼저 확인하세요.
실수 2: 확장 필드에 표준 도메인을 재사용하지 않고 임의 도메인 사용. 표준 필드와 조인·비교가 필요한 확장 필드는 반드시 표준 데이터 요소를 재사용해야 값 도움말(Value Help)과 통화 참조가 자동 연결됩니다.
실수 3: 확장 핸들러에서 표준 MODIFY ENTITIES를 직접 호출. 이는 무한 루프나 트랜잭션 이상 종료의 원인이 됩니다. 확장 핸들러 안에서 상태를 바꿔야 할 때는 반드시 IN LOCAL MODE를 붙이고, 가능하면 determination으로 표준 흐름 안에서 처리되도록 위임합니다.
FAQ 1 — Extension Include와 Custom Field(In-App Extensibility)는 무엇이 다른가? Custom Field는 Key User가 UI로 필드를 추가하는 사용자 확장이고, Extension Include는 개발자가 ABAP 오브젝트로 만드는 개발자 확장입니다. 로직이 복잡하거나 여러 BO에 걸친 확장이 필요하면 Extension Include를 권장합니다.
FAQ 2 — 확장 필드를 표준 OData 서비스에서 노출하려면? Service Definition을 extend해서 확장 필드를 expose에 추가해야 합니다. Service Binding은 재활성화만 하면 됩니다.
FAQ 3 — 업그레이드 후 확장이 비활성화되면? 대부분 원인은 표준이 릴리스 컨트랙트를 변경했거나(드묾), 확장이 사용해선 안 되는 내부 오브젝트를 참조했기 때문입니다. ATC 리포트를 비교해 신규 위반 항목을 우선 확인하세요.
이어서 탐색할 주제
Extension Include에 익숙해졌다면 다음 주제로 확장 스킬을 넓혀 갈 수 있습니다. 첫째, Behavior Extensions with Draft Handling: 표준 BO가 드래프트를 지원할 때 확장 필드의 드래프트 저장 라우팅을 구성하는 방법. 둘째, Extend Metadata Extensions: Fiori Elements UI에 확장 필드를 페이스팅하고 SelectionField/LineItem에 위치를 지정하는 방식. 셋째, Side-by-Side Extensibility: BTP에서 CAP 서비스로 확장 로직을 분리해 S/4의 코어와 완전히 독립시키는 아키텍처. 넷째, Released Object 조회 API를 사용해 확장 가능한 오브젝트를 자동으로 발견하는 방법도 함께 익히면 실무에서 유용합니다.
더 읽어볼 만한 자료
- SAP Help — Enhancing Behavior Definitions (ABAP Platform)
- SAP Help — Extending a RAP Business Object (ABAP Cloud)
- SAP Help — Extension Includes in CDS View Entities
- SAP Community Blog — RAP Extensibility Deep Dive
- SAP Developers — Extending a Released RAP BO Walkthrough
- SAP Help — Behavior Extension Reference (BDEF Extend Syntax)
- SAP Blogs — RAP Extensibility 태그 모음
댓글 0
아직 댓글이 없습니다.