ABAP

SAP 확장 Tier 1 vs 2 vs 3 어떻게 다를까 #shorts #SAP #ABAP

▶ YouTube에서 보기

SAP 확장 모델이 3계층으로 나뉜 이유

SAP S/4HANA Cloud가 등장하면서 ERP를 "건드리지 않고 어떻게 확장할 것인가"가 핵심 과제로 떠올랐습니다. 과거 ECC 시절에는 SE38에서 표준 프로그램을 그대로 수정하거나, User Exit/BAdI로 핵심 로직에 깊숙이 개입하는 방식이 일반적이었습니다. 그러나 이런 침습적 확장은 분기마다 들어오는 SAP 업그레이드를 사실상 불가능하게 만드는 주범이었습니다.

SAP는 이를 해결하기 위해 Clean Core 원칙을 선언하고, 확장 가능 지점을 명확히 분리한 3계층 모델을 정의했습니다. Tier 1은 비즈니스 사용자가 UI에서 직접 수행하는 Key User 확장, Tier 2는 ABAP Cloud 개발 모델을 따르는 On-Stack 확장, Tier 3는 BTP 상에서 동작하는 Side-by-Side 확장입니다. 이 글은 세 계층이 어떻게 다르고, 실무 시나리오에서 어떤 기준으로 선택해야 하는지 구매 주문(PurchaseOrder) 확장 사례로 살펴봅니다.

다음 항목을 끝까지 확인해 보세요.

  • 3-Tier 확장 모델의 등장 배경과 Clean Core의 의미
  • 각 Tier의 구현 방식, 책임자, 사용 도구
  • 같은 요구사항을 Tier 1/2/3로 풀어내는 코드 차이
  • 업그레이드 안전성과 라이프사이클 관점의 비교
  • 프로젝트 초기 단계에서 Tier를 결정하는 체크리스트

환경 및 전제 조건

ABAP 객체지향 기초(클래스, 인터페이스), RAP(RESTful ABAP Programming Model)의 BO 구조, ADT(ABAP Development Tools in Eclipse) 사용 경험이 있으면 Tier 2 부분이 수월합니다. Tier 3는 SAP BTP의 멀티테넌트 개념, OAuth2/Destination Service, Node.js 또는 CAP(Cloud Application Programming Model)에 대한 기본 이해가 필요합니다. Tier 1은 비개발자도 따라올 수 있도록 구성했습니다.

이 글의 코드와 화면 설명은 다음 환경을 기준으로 작성되었습니다.

  • SAP S/4HANA Cloud Public Edition 2402 이상 (Private Edition도 ABAP Cloud Development Model 적용 시 동일)
  • ABAP Platform 2023 / ABAP for Cloud Development
  • ADT(ABAP Development Tools) for Eclipse 2024-03 이상
  • SAP BTP, Cloud Foundry 환경 + Node.js 20.x 또는 CAP 8.x
  • SAP Fiori Launchpad의 Key User 역할(SAP_BR_BPC_EXPERT 유사 역할) 권한
  • BTP destination "S4HC_API"에 PurchaseOrder OData v4 서비스(API_PURCHASEORDER_PROCESS_SRV) 등록

핵심 개념: 3-Tier 모델을 한눈에

3-Tier 모델은 "확장이 시스템 어디에서, 누구에 의해, 어떤 라이프사이클로 동작하는가"를 기준으로 분리합니다. 빌딩에 비유하자면, Tier 1은 사무실 내부에 가구를 재배치하는 일, Tier 2는 빌딩 내부에 새 사무실을 짓는 일, Tier 3는 옆 건물을 새로 지어 다리(API)로 연결하는 일에 해당합니다.

  • Tier 1 — Key User Extensibility: UI 기반 도구(Custom Fields, Custom Business Objects, Custom Logic 앱)로 표준 BO에 필드를 추가하거나 BAdI 스타일 훅에 JavaScript 유사 문법을 작성합니다. 개발자가 아닌 비즈니스 컨설턴트가 담당합니다.
  • Tier 2 — Developer Extensibility (On-Stack): ABAP Cloud 언어 버전을 사용해 ADT에서 클래스, RAP BO, CDS 뷰를 작성합니다. 직접 테이블 접근은 금지되고, Released API와 화이트리스트된 명령만 사용 가능합니다.
  • Tier 3 — Side-by-Side Extensibility: BTP에 별도 앱을 배포하고, OData/SOAP/Events로 S/4HANA와 통신합니다. 가장 자유롭지만, 통신 지연·인증·데이터 동기화를 직접 책임져야 합니다.

핵심은 업그레이드 안전성표현력의 트레이드오프입니다. Tier가 낮을수록 변경 후 SAP 업그레이드 시 깨질 위험이 적지만, 표현할 수 있는 로직의 복잡도가 제한됩니다. Tier가 높을수록 거의 모든 것을 자유롭게 만들 수 있지만, 그만큼 운영 책임도 커집니다.

Clean Core는 단순히 "표준 코드 건드리지 말기"가 아닙니다. 표준 객체와 확장 객체 사이의 상호작용 지점을 SAP가 명시적으로 공개한 API/Extension Point로만 제한하자는 약속에 가깝습니다.

Tier 1: Key User 확장 — 코드 없이 필드 추가하기

구매 주문에 "내부 승인 등급(Internal Approval Grade)"이라는 사용자 정의 필드를 추가한다고 가정합니다. Tier 1에서는 Fiori Launchpad의 Custom Fields 앱에서 진행합니다.

  1. Custom Fields 앱 실행 → Business Context로 "Purchase Order Item"(컨텍스트 ID: SAP_PUR_PO_ITEM) 선택
  2. Label "Internal Approval Grade", Identifier YY1_InternalApprovalGrade, Type "Code List"로 신규 생성
  3. "Enable Usage"에서 UI, OData API, Reports 체크 → Publish
  4. Adapt UI 모드에서 Manage Purchase Orders 앱에 필드 노출
  5. Custom Logic 앱에서 BAdI Purchase Order: Check on Save에 다음 ABAP-restricted 스니펫 작성
" Custom Logic editor (Tier 1) — 매우 제한된 ABAP 서브셋
IF purchaseorderitem-yy1_internalapprovalgrade IS INITIAL
   AND purchaseorderitem-netpriceamount > 10000.
  RAISE EXCEPTION TYPE cx_bs_check
    MESSAGE ID 'ZPO' TYPE 'E' NUMBER '001'
    WITH purchaseorderitem-purchaseorderitem.
ENDIF.

이 방식은 클래스 정의, 패키지 관리, 운송 요청(TR) 생성을 사용자가 의식할 필요가 없습니다. 모든 변경 사항은 SAP가 관리하는 확장 저장소에 보관되며, 업그레이드 시 자동으로 재검증됩니다.

Tier 2: ABAP Cloud로 PurchaseOrder 검증 클래스 만들기

Tier 1으로 풀기에는 로직이 복잡하다고 가정합시다. "공급업체 신용등급 테이블과 조인해서 등급이 C 이하면 자동으로 결재선에 CFO를 추가"하는 요구사항입니다. 이때는 ABAP Cloud 개발 모델, 즉 Tier 2로 진입합니다.

ABAP Cloud는 다음 제약을 둡니다.

  • 패키지는 Software Component: ZLOCAL 또는 고객 네임스페이스, Language Version은 "ABAP for Cloud Development"
  • 모든 사용 객체는 Released API여야 함 (C1: Use System-Internally 불가)
  • SELECT는 Released CDS 뷰만 가능, 직접 DB 테이블 접근 금지
  • 클래스는 가능한 한 FINAL, 인터페이스는 RESTRICTED로 공개 범위 명시
"! 

PO 자동 결재 검증

"! 공급업체 신용등급에 따라 추가 승인자를 결정한다. CLASS zcl_po_validator DEFINITION PUBLIC FINAL CREATE PRIVATE. PUBLIC SECTION. INTERFACES if_oo_adt_classrun. CLASS-METHODS get_instance RETURNING VALUE(ro_instance) TYPE REF TO zcl_po_validator. METHODS evaluate_credit_risk IMPORTING iv_supplier_id TYPE c LENGTH 10 iv_total_amount TYPE p LENGTH 15 DECIMALS 2 RETURNING VALUE(rs_result) TYPE zif_po_types=>ty_risk_result RAISING cx_zpo_validation. PRIVATE SECTION. CLASS-DATA so_singleton TYPE REF TO zcl_po_validator. METHODS fetch_credit_grade IMPORTING iv_supplier_id TYPE c LENGTH 10 RETURNING VALUE(rv_grade) TYPE c LENGTH 1. ENDCLASS. CLASS zcl_po_validator IMPLEMENTATION. METHOD get_instance. IF so_singleton IS INITIAL. so_singleton = NEW #( ). ENDIF. ro_instance = so_singleton. ENDMETHOD. METHOD evaluate_credit_risk. DATA(lv_grade) = fetch_credit_grade( iv_supplier_id ). rs_result-supplier_id = iv_supplier_id. rs_result-credit_grade = lv_grade. IF lv_grade CA 'CD' AND iv_total_amount > 50000. rs_result-extra_approver = 'CFO'. rs_result-requires_review = abap_true. ELSE. rs_result-requires_review = abap_false. ENDIF. ENDMETHOD. METHOD fetch_credit_grade. " Released CDS 뷰만 사용 (직접 테이블 SELECT 금지) SELECT SINGLE creditgrade FROM I_SupplierCreditRiskView WHERE Supplier = @iv_supplier_id INTO @rv_grade. ENDMETHOD. METHOD if_oo_adt_classrun~main. TRY. DATA(ls_risk) = evaluate_credit_risk( iv_supplier_id = '0010003456' iv_total_amount = '78000.00' ). out->write( ls_risk ). CATCH cx_zpo_validation INTO DATA(lx_err). out->write( lx_err->get_text( ) ). ENDTRY. ENDMETHOD. ENDCLASS.

이 클래스를 RAP BO의 Behavior Implementation에서 호출하면, 표준 PurchaseOrder의 동작을 침해하지 않으면서 확장 BDEF(extend behavior)로 검증 액션을 추가할 수 있습니다. ABAP Unit 테스트도 일반 클래스와 동일하게 작성 가능합니다.

Tier 3: BTP Side-by-Side로 독립 앱 만들기

"구매 부서가 자체 모바일 앱으로 외부 협력사 데이터를 받아오고, S/4HANA의 PO와 매칭해 리포트를 만든다"는 시나리오를 가정합니다. 이 정도가 되면 S/4 내부에 두기엔 책임 경계가 모호하므로 Tier 3가 적합합니다.

아래는 CAP(Cloud Application Programming Model) 기반 서비스 정의 실전 예제입니다.

// db/schema.cds
namespace zpo.report;

entity SupplierScore {
  key supplierId   : String(10);
      partnerName  : String(80);
      externalRank : Integer;
      lastSyncAt   : Timestamp;
}
// srv/po-report-service.cds
using { API_PURCHASEORDER_PROCESS_SRV as S4 } from './external/S4';
using zpo.report from '../db/schema';

service PoReportService @(path:'/po-report') {
  entity Suppliers as projection on report.SupplierScore;

  @readonly
  entity PurchaseOrders as projection on S4.A_PurchaseOrder {
    PurchaseOrder, Supplier, PurchaseOrderType, CreationDate
  };

  action enrichScore(supplierId: String) returns SupplierScore;
}
// srv/po-report-service.js
const cds = require('@sap/cds');

module.exports = cds.service.impl(async function () {
  const { SupplierScore } = this.entities;
  const s4 = await cds.connect.to('API_PURCHASEORDER_PROCESS_SRV');

  this.on('enrichScore', async (req) => {
    const { supplierId } = req.data;

    // 1) S/4HANA에서 해당 공급업체의 최근 PO 건수 조회
    const orders = await s4.run(
      SELECT.from('A_PurchaseOrder')
        .where({ Supplier: supplierId })
        .limit(50)
    );

    // 2) 외부 신용평가사 API 호출
    const ext = await fetch(`https://credit.example.com/score/${supplierId}`, {
      headers: { Authorization: `Bearer ${process.env.CREDIT_TOKEN}` }
    }).then(r => r.json());

    // 3) BTP HANA Cloud에 캐싱
    const score = {
      supplierId,
      partnerName: ext.name,
      externalRank: ext.rank,
      lastSyncAt: new Date().toISOString()
    };

    await UPSERT.into(SupplierScore).entries(score);
    req.info(`Synchronized ${orders.length} POs for supplier ${supplierId}`);
    return score;
  });

  this.on('error', (err, req) => {
    cds.log('po-report').error(err);
    req.reject(500, 'Enrichment failed. Check destination/credentials.');
  });
});

이 앱은 BTP Cloud Foundry에 cf push로 배포되며, S/4HANA와는 Destination Service를 통한 Principal Propagation으로 인증합니다. S/4의 어떤 코드도 수정하지 않으므로 Clean Core가 가장 잘 지켜집니다. 반면 네트워크 지연, 토큰 갱신, 모니터링은 전적으로 BTP 운영 팀의 몫입니다.

Tier 1 vs Tier 2 vs Tier 3 — 같은 요구를 다른 결로

관점Tier 1 Key UserTier 2 ABAP CloudTier 3 Side-by-Side
주 담당자비즈니스 컨설턴트ABAP 개발자풀스택/클라우드 개발자
도구Fiori 앱 (Custom Fields, Custom Logic)ADT in EclipseVS Code, BTP Cockpit, CAP/Node.js
실행 위치S/4HANA 내부S/4HANA 내부BTP 별도 런타임
표현력제한적 (서브셋)중간 (Released API 한정)거의 무제한
업그레이드 영향매우 낮음낮음 (API 폐기 시 알림)없음 (느슨한 결합)
운영 부담거의 없음표준 ABAP과 동일BTP 별도 운영 필요
일반적 활용필드 추가, 단순 검증RAP 확장, 복잡한 도메인 로직독립 앱, 외부 시스템 연동

Clean Core와 업그레이드 안전성

Clean Core 점수는 SAP의 Cloud ALM과 Custom Code Migration 도구로 측정 가능합니다. 권장 원칙은 다음과 같습니다.

  • 표준 객체를 절대로 직접 수정하지 않는다 (Modification 금지)
  • 모든 외부 의존성은 Released API 또는 Public OData를 통한다
  • 확장 객체는 별도 네임스페이스/소프트웨어 컴포넌트에 격리한다
  • Tier 1으로 충분하면 Tier 2로 올리지 않는다 ("가장 낮은 Tier 원칙")
  • Tier 3로 가는 결정은 도메인 경계 + 데이터 마스터링 위치를 함께 고려한다

흔한 실수와 해결 방법

Q1. Tier 2에서 "Use of object X is not permitted" 오류가 납니다.
사용하려는 함수 모듈/클래스/CDS가 Released API가 아닐 가능성이 큽니다. ADT에서 해당 객체를 열어 Properties → API State를 확인하고, "Released for Cloud Development(C1)"가 아니면 대체 API를 찾거나 SAP에 Release를 요청해야 합니다.

Q2. Custom Logic 앱(Tier 1)에서 복잡한 LOOP가 안 됩니다.
Tier 1의 ABAP 서브셋은 의도적으로 제한됩니다. 동적 SQL, 외부 호출, 비제한 LOOP는 막혀 있습니다. 로직이 길어진다면 Tier 2로 올려 RAP Determination/Validation으로 옮기는 것을 권장합니다.

Q3. Tier 3 CAP 앱이 S/4HANA에서 401을 받습니다.
대부분 Destination의 Authentication 유형 불일치입니다. Business User 흐름이라면 OAuth2SAMLBearerAssertion, 시스템 간 통신이라면 OAuth2ClientCredentials로 설정해야 합니다. Communication Arrangement(SAP_COM_0102 등)와 Scope 매핑도 함께 확인하세요.

Q4. 같은 기능을 Tier 1과 Tier 2 어디에 둘지 모르겠습니다.
"이 로직을 비즈니스 사용자가 6개월 뒤 직접 바꿀 가능성이 있는가?"를 질문하세요. Yes면 Tier 1, No이거나 단위 테스트가 필수인 도메인 규칙이면 Tier 2가 일반적으로 더 적합합니다.

프로젝트 초반 Tier 선택 체크리스트

다음 질문에 답하면서 Tier를 결정하세요. 항목에 체크할수록 해당 Tier가 더 적합합니다.

Tier 1 체크리스트

  • □ 비즈니스 사용자가 직접 설정·변경을 요청했다
  • □ 표준 BO의 필드 추가·UI 변경이 전부다
  • □ 로직이 BAdI 스텁 안에서 30줄 이내로 끝난다
  • □ 외부 시스템 호출, 복잡한 집계가 없다
  • □ 단위 테스트보다 빠른 반영이 더 중요하다

Tier 2 체크리스트

  • □ ABAP 개발자가 구현하고 코드 리뷰/테스트가 필요하다
  • □ RAP BO 동작(Validation, Determination, Action)에 개입해야 한다
  • □ Released CDS 뷰로 조회 가능한 데이터만 필요하다
  • □ 커스텀 리포트·ALV가 필요하다
  • □ 확장이 S/4HANA 트랜잭션 내에서 동기 실행되어야 한다

Tier 3 체크리스트

  • □ 외부 SaaS·레거시 시스템과 통합이 핵심이다
  • □ S/4HANA에 없는 UI/UX(모바일 앱, 포털)가 필요하다
  • □ 독립적인 릴리즈·배포 사이클이 필요하다
  • □ 다중 테넌트, 멀티-클라우드 시나리오다
  • □ 대용량 배치 처리나 ML 파이프라인이 포함된다

하나의 프로젝트에서 세 Tier가 모두 공존하는 것은 드문 일이 아닙니다. 중요한 것은 각 확장이 어느 Tier에 속하는지를 처음부터 명확히 정의해 두는 것입니다. 경계가 흐려지면 업그레이드 비용이 급격히 늘어납니다.

댓글 0

아직 댓글이 없습니다.