<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oktay Ates</title>
    <description>The latest articles on DEV Community by Oktay Ates (@oktay_a56a5e9cc26cc1df8fe).</description>
    <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3815408%2F9552fca3-5256-48c7-b621-f02ed2bee5cd.png</url>
      <title>DEV Community: Oktay Ates</title>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oktay_a56a5e9cc26cc1df8fe"/>
    <language>en</language>
    <item>
      <title>ABAP RESTful Application Programming Model (RAP) PART 3: A Senior Architect's Guide to Building Modern Fiori Apps</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Sun, 05 Apr 2026 19:24:25 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/abap-restful-application-programming-model-rap-part-3-a-senior-architects-guide-to-building-g69</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/abap-restful-application-programming-model-rap-part-3-a-senior-architects-guide-to-building-g69</guid>
      <description>&lt;p&gt;If you’ve been building SAP applications for more than a few years, you’ve seen the landscape shift dramatically. We went from classic Dynpro screens to Web Dynpro, then to SAPUI5 with OData services wired up manually, and now we’re in the era of the &lt;strong&gt;ABAP RESTful Application Programming Model (RAP)&lt;/strong&gt;. And I’ll be honest with you — RAP is the most significant architectural leap I’ve seen in the ABAP world in over a decade.&lt;/p&gt;

&lt;p&gt;But here’s the thing: most teams I’ve consulted with are still building new Fiori apps the old way. They’re creating function modules, manually exposing OData services, and wondering why maintenance is killing them six months later. If you’re one of those teams, this guide is for you. We’re going to break down &lt;strong&gt;ABAP RAP&lt;/strong&gt; from a senior architect’s perspective — what it actually is, how the layered architecture works, and how to build a real, working application without wasting weeks on boilerplate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is ABAP RAP and Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;ABAP RESTful Application Programming Model&lt;/strong&gt; is SAP’s official, recommended framework for building transactional and read-only Fiori applications on SAP S/4HANA (on-premise 1909+) and SAP BTP ABAP Environment. It combines CDS Views, behavior definitions, service definitions, and service bindings into a coherent, layered architecture.&lt;/p&gt;

&lt;p&gt;Think of RAP as the answer to the question: &lt;em&gt;“How do we build enterprise-grade OData services without writing the same boilerplate code over and over again?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The key pillars of RAP are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CDS Views as the data model foundation&lt;/strong&gt; — not just for reporting anymore&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Behavior Definitions (BDEF)&lt;/strong&gt; — declaring what operations your business object supports&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Behavior Implementations (BAPI replacement)&lt;/strong&gt; — the actual ABAP logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Service Definitions and Bindings&lt;/strong&gt; — exposing your model as OData V2 or V4&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’ve been following our CDS Views series on this site, you already understand the data modeling layer. RAP takes that foundation and adds transactional capability on top of it. That’s the key insight.&lt;/p&gt;

&lt;p&gt;Also worth noting: if you’ve been working through the concepts in our &lt;a href="https://aixsap.com/abap-oop-design-patterns-part-2-factory-observer-and-decorator-patterns-in-real-sap-systems/" rel="noopener noreferrer"&gt;ABAP OOP Design Patterns series&lt;/a&gt;, you’ll find that RAP’s architecture strongly encourages the same design discipline — clean separation of concerns, single responsibility, and testable units.&lt;/p&gt;

&lt;h2&gt;
  
  
  The RAP Architecture: Three Layers You Need to Understand
&lt;/h2&gt;

&lt;p&gt;Before we write a single line of code, let me walk you through the architecture. Understanding this upfront will save you hours of confusion later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: The Data Model (CDS Interface Views)
&lt;/h3&gt;

&lt;p&gt;At the base, you define your business entity using CDS views. In RAP, we distinguish between &lt;strong&gt;Interface Views&lt;/strong&gt; (the raw data contract) and &lt;strong&gt;Projection Views&lt;/strong&gt; (the consumption-specific projection). This separation is critical — your interface view is stable and reusable; your projection view is tailored for a specific Fiori app or UI5 component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;AbapCatalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqlViewName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;ZI_SALESORDER&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;AbapCatalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compiler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compareFilter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;AbapCatalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preserveKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;AccessControl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorizationCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="k"&gt;CHECK&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EndUserText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;Interface&lt;/span&gt; &lt;span class="k"&gt;View&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="k"&gt;view&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrder&lt;/span&gt;
  &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;
  &lt;span class="k"&gt;association&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrderItem&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;_Item&lt;/span&gt;
    &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;projection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SalesOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SalesOrder&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="n"&gt;vbeln&lt;/span&gt;          &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;erdat&lt;/span&gt;          &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ernam&lt;/span&gt;          &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;CreatedByUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;netwr&lt;/span&gt;          &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;NetValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;waerk&lt;/span&gt;          &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;Currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="k"&gt;Association&lt;/span&gt;
      &lt;span class="n"&gt;_Item&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the define root view entity keyword — this marks it as the root of a Business Object (BO) hierarchy, which RAP needs to understand the structure of your entity graph.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: The Behavior Definition (BDEF)
&lt;/h3&gt;

&lt;p&gt;This is where RAP gets interesting. The Behavior Definition is a declarative artifact where you tell the framework what your business object can &lt;em&gt;do&lt;/em&gt;. Can it be created? Updated? Deleted? Does it support draft? Does it have custom actions?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="n"&gt;managed&lt;/span&gt; &lt;span class="k"&gt;implementation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ZBP_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;unique&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;strict&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="n"&gt;behavior&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;
&lt;span class="n"&gt;persistent&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;
&lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;zdraft_salesorder&lt;/span&gt;
&lt;span class="n"&gt;etag&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt; &lt;span class="n"&gt;LastChangedAt&lt;/span&gt;
&lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;
&lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;field&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;numbering&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;managed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;field&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;readonly&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;CreationDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CreatedByUser&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;update&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="k"&gt;Edit&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;Activate&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="k"&gt;Resume&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="n"&gt;determine&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="n"&gt;Prepare&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;features&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ApproveSalesOrder&lt;/span&gt; &lt;span class="k"&gt;result&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;mapping&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SalesOrder&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vbeln&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;CreationDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;erdat&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;CreatedByUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ernam&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;NetValue&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;netwr&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;Currency&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;waerk&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;association&lt;/span&gt; &lt;span class="n"&gt;_Item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me highlight what’s happening here. The managed keyword means SAP’s framework handles the standard CRUD persistence — you don’t write the INSERT/UPDATE/DELETE logic yourself. That alone eliminates hundreds of lines of boilerplate. The with draft declaration gives you draft capability (save-as-draft before final commit) essentially for free.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: The Behavior Implementation Class
&lt;/h3&gt;

&lt;p&gt;For anything that goes beyond standard CRUD — validations, determinations, and custom actions — you implement a &lt;strong&gt;Behavior Implementation (BIL) class&lt;/strong&gt;. This is a local class hierarchy generated and managed by the framework.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;lhc_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;INHERITING&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;cl_abap_behavior_handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;validate_net_value&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;VALIDATE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;SAVE&lt;/span&gt;
        &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="k"&gt;keys&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ValidateNetValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;approve_sales_order&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;ACTION&lt;/span&gt;
        &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="k"&gt;keys&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ApproveSalesOrder&lt;/span&gt; &lt;span class="k"&gt;RESULT&lt;/span&gt; &lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;lhc_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;validate_net_value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;instances&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;need&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;
    &lt;span class="k"&gt;READ&lt;/span&gt; &lt;span class="n"&gt;ENTITIES&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="k"&gt;MODE&lt;/span&gt;
      &lt;span class="n"&gt;ENTITY&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;
      &lt;span class="k"&gt;FIELDS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;NetValue&lt;/span&gt; &lt;span class="k"&gt;Currency&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;CORRESPONDING&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;keys&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;RESULT&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_salesorders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;FAILED&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_failed&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;lt_salesorders&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;NetValue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;APPEND&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;salesorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

        &lt;span class="k"&gt;APPEND&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;
          &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;state_area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;VALIDATE_NET_VALUE&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
          &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;id&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;ZSO_MESSAGES&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;number&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;severity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;if_abap_behv_message&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;
            &lt;span class="n"&gt;v1&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;SalesOrder&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;NetValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;if_abap_behv&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;reported&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;salesorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;approve_sales_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Read&lt;/span&gt; &lt;span class="k"&gt;current&lt;/span&gt; &lt;span class="k"&gt;state&lt;/span&gt;
    &lt;span class="k"&gt;READ&lt;/span&gt; &lt;span class="n"&gt;ENTITIES&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="k"&gt;MODE&lt;/span&gt;
      &lt;span class="n"&gt;ENTITY&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;
      &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;FIELDS&lt;/span&gt;
      &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;CORRESPONDING&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;keys&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;RESULT&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_orders&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Modify&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt; &lt;span class="n"&gt;scenario&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;field&lt;/span&gt;
    &lt;span class="k"&gt;MODIFY&lt;/span&gt; &lt;span class="n"&gt;ENTITIES&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="k"&gt;MODE&lt;/span&gt;
      &lt;span class="n"&gt;ENTITY&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;
      &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;FIELDS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;NetValue&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;lt_orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;
        &lt;span class="n"&gt;NetValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;NetValue&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;REPORTED&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_reported&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;FAILED&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;MAPPED&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_mapped&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Return&lt;/span&gt; &lt;span class="k"&gt;result&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;caller&lt;/span&gt;
    &lt;span class="k"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="n"&gt;lt_orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-%&lt;/span&gt;&lt;span class="n"&gt;tky&lt;/span&gt;
      &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay close attention to the READ ENTITIES and MODIFY ENTITIES statements — these are RAP-specific EML (Entity Manipulation Language) statements. They work through the business object’s buffer, not directly against the database, which is what gives RAP its transactional consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Definition and Binding: Exposing Your BO as OData
&lt;/h2&gt;

&lt;p&gt;Once your data model and behavior are in place, exposing it as an OData service is straightforward. The &lt;strong&gt;Service Definition&lt;/strong&gt; selects which entities to expose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;EndUserText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="k"&gt;Definition&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;ZSD_SalesOrder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;expose&lt;/span&gt; &lt;span class="n"&gt;ZC_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;expose&lt;/span&gt; &lt;span class="n"&gt;ZC_SalesOrderItem&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;SalesOrderItem&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we’re exposing the &lt;strong&gt;Projection Views&lt;/strong&gt; (ZC_*), not the interface views directly. This is intentional — it keeps your internal data contract separate from what you publish to consumers.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Service Binding&lt;/strong&gt; then ties this to a protocol (OData V2 for classic Fiori apps, OData V4 for newer ones) and enables you to publish and test the service directly from ADT (Eclipse). This is where you also preview the Fiori app generated from your annotations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managed vs. Unmanaged: Choosing the Right RAP Flavor
&lt;/h2&gt;

&lt;p&gt;One of the most common questions I get is: &lt;em&gt;“Should I use managed or unmanaged RAP?”&lt;/em&gt; Here’s my honest take after working with both on production systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Managed RAP when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You’re building on a &lt;em&gt;new&lt;/em&gt; or &lt;em&gt;greenfield&lt;/em&gt; custom table&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want draft handling without building it yourself&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your persistence model matches your BO model closely&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speed of development is a priority&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Unmanaged RAP when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You’re wrapping existing BAPIs or function modules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your persistence logic is complex and involves multiple tables in non-standard ways&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You’re migrating a legacy application and need full control&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my experience, managed RAP with additional save (where you hook in custom save logic) gives you the best of both worlds for about 80% of use cases. Don’t reach for unmanaged unless you genuinely need it — the boilerplate cost is real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Testing RAP Behavior: Don’t Skip This
&lt;/h2&gt;

&lt;p&gt;RAP has excellent testability built in. You can unit test your behavior implementations using CL_ABAP_BEHV_TEST_ENVIRONMENT, which gives you an in-memory mock of the RAP runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;
  &lt;span class="k"&gt;DURATION&lt;/span&gt; &lt;span class="k"&gt;SHORT&lt;/span&gt; &lt;span class="k"&gt;RISK&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="k"&gt;HARMLESS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;environment&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;if_abap_behv_test_environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;class_setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;class_teardown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;validate_negative_net_value&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_SalesOrder&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;class_setup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cl_abap_behv_test_environment&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;entity_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;ZI_SALESORDER&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;class_teardown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;validate_negative_net_value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Arrange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Insert&lt;/span&gt; &lt;span class="k"&gt;test&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;
    &lt;span class="k"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;insert_test_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;salesorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;0000000001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;netvalue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;currency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;EUR&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Act&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Trigger&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;
    &lt;span class="k"&gt;MODIFY&lt;/span&gt; &lt;span class="n"&gt;ENTITIES&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ZI_SalesOrder&lt;/span&gt;
      &lt;span class="n"&gt;ENTITY&lt;/span&gt; &lt;span class="n"&gt;SalesOrder&lt;/span&gt;
      &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="n"&gt;ValidateNetValue&lt;/span&gt;
      &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;salesorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;0000000001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;FAILED&lt;/span&gt;   &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_failed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;REPORTED&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_reported&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Expect&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="k"&gt;message&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_not_initial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lt_failed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;salesorder&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Validation&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="k"&gt;fail&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;negative&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to go deeper on testing strategies, our article on &lt;a href="https://aixsap.com/abap-unit-testing-in-sap-s-4hana-a-senior-architects-guide-to-writing-tests-that-actually-matter/" rel="noopener noreferrer"&gt;ABAP Unit Testing in SAP S/4HANA&lt;/a&gt; covers the broader testing philosophy that pairs perfectly with RAP development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common RAP Mistakes I’ve Seen in the Field
&lt;/h2&gt;

&lt;p&gt;Let me save you from the pain I’ve witnessed on real projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 1: Using Database Access in Behavior Implementations
&lt;/h3&gt;

&lt;p&gt;Do &lt;em&gt;not&lt;/em&gt; use SELECT statements directly inside your BIL methods. Always use READ ENTITIES. Why? Because RAP maintains a transactional buffer. If you bypass it with direct DB reads, you’ll read stale data and create consistency bugs that are incredibly hard to debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 2: Not Understanding the RAP Transaction Model
&lt;/h3&gt;

&lt;p&gt;RAP enforces a strict phase model: &lt;strong&gt;interaction phase → save sequence → cleanup&lt;/strong&gt;. Understanding that validations and determinations run in a specific order — and that the framework calls them, not you — is fundamental. Read SAP’s documentation on the RAP BO runtime phases before writing your first BIL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 3: Skipping the Projection View Layer
&lt;/h3&gt;

&lt;p&gt;I’ve seen developers expose interface views directly. This creates tight coupling between your internal data model and your service consumers. When you need to change the interface view for another use case, you break your Fiori app. Always use projection views. They’re not overhead — they’re insurance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake 4: Ignoring Feature Controls
&lt;/h3&gt;

&lt;p&gt;RAP has a powerful mechanism for controlling which operations are available at runtime — called &lt;strong&gt;feature controls&lt;/strong&gt;. Use them to conditionally enable/disable actions, fields, or CRUD operations based on business state. Too many developers leave everything enabled and put conditional logic inside the action itself, which leads to confusing UX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Considerations in RAP
&lt;/h2&gt;

&lt;p&gt;Performance in RAP deserves its own article, but a few principles matter immediately. First, your CDS interface views are the performance foundation — a slow CDS view means a slow OData service. Apply everything you know about CDS performance optimization here.&lt;/p&gt;

&lt;p&gt;Second, be careful with &lt;strong&gt;determinations triggered on field change&lt;/strong&gt;. If you attach a determination to every field modification, you’ll fire expensive logic on every keystroke in a Fiori form. Scope your determinations tightly.&lt;/p&gt;

&lt;p&gt;Third, for large entity sets, implement &lt;strong&gt;server-side pagination&lt;/strong&gt; through your OData binding configuration. Don’t let your Fiori app load 10,000 records on initial load because no one thought about $top and $skip.&lt;/p&gt;

&lt;p&gt;For a deeper dive into SAP performance patterns, our &lt;a href="https://aixsap.com/sap-abap-performance-optimization-identifying-and-fixing-bottlenecks-in-real-world-systems/" rel="noopener noreferrer"&gt;ABAP Performance Optimization guide&lt;/a&gt; is a solid complement to what we’ve covered here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RAP is not just another framework — it’s a paradigm shift that enforces good architecture by default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The layered model (interface view → projection view → behavior → service) is not optional ceremony; it’s what makes your apps maintainable at scale.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Managed RAP with draft is your default starting point for new transactional apps. Deviate when you have a concrete reason.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EML (READ ENTITIES / MODIFY ENTITIES) is the only correct way to interact with your BO inside behavior implementations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test your behavior implementations using the RAP test environment — it’s built for this, and it works well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Projection views are not overhead — they’re your consumer contract boundary.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re starting a new Fiori application today and you’re &lt;em&gt;not&lt;/em&gt; using RAP, you owe it to yourself and your team to understand why. The productivity gains are real, the code is more maintainable, and SAP is clearly investing in this model for the long term.&lt;/p&gt;

&lt;p&gt;Start with a simple managed BO. Build the layers. Test them. And resist the urge to add complexity until you need it. That’s been the lesson from every successful RAP project I’ve been involved with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you started working with ABAP RAP in your projects?&lt;/strong&gt; What’s the biggest challenge you’ve run into — is it the new mental model, the tooling in ADT, or something else entirely? Drop your experience in the comments below. If you found this guide useful, share it with your team — there’s a good chance someone is still building OData services the old way and doesn’t know there’s a better path.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>ABAP OOP Design Patterns — Part 2: Factory, Observer, and Decorator Patterns in Real SAP Systems</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Wed, 01 Apr 2026 21:38:36 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/abap-oop-design-patterns-part-2-factory-observer-and-decorator-patterns-in-real-sap-systems-1b18</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/abap-oop-design-patterns-part-2-factory-observer-and-decorator-patterns-in-real-sap-systems-1b18</guid>
      <description>&lt;p&gt;ABAP OOP Design Patterns — Part 2: Factory, Observer, and Decorator Patterns in Real SAP Systems&lt;br&gt;
If you’ve been writing ABAP long enough, you’ve probably inherited a codebase where every business rule is buried inside a 3,000-line function module, and adding a new requirement means copy-pasting logic you’re not even sure is correct. That’s not a skills problem — it’s an architecture problem. In &lt;a href="https://aixsap.com/abap-oop-ile-tasarim-desenleri-abap-oop-ve-strategy-pattern-gercek-dunya-uygulamalari/" rel="noopener noreferrer"&gt;Part 1 of this series&lt;/a&gt;, we explored how the Strategy Pattern helps you swap business logic cleanly without touching the calling code. Now it’s time to go further. In this second installment, we’re tackling three more battle-tested &lt;strong&gt;ABAP OOP design patterns&lt;/strong&gt;: Factory, Observer, and Decorator. Each one solves a very specific pain point I’ve encountered repeatedly across large SAP S/4HANA implementations — and I’ll show you exactly how to apply them.&lt;/p&gt;

&lt;p&gt;Before we dive in, a quick note: these patterns aren’t academic exercises. Every example below is inspired by real implementation challenges on production SAP systems. If you’re also working on improving code quality across the board, it’s worth reading alongside our guides on &lt;a href="https://aixsap.com/abap-clean-code-okunabilir-ve-surdurulebilir-sap-kodu-yazmanin-10-altin-kurali/" rel="noopener noreferrer"&gt;Clean ABAP best practices&lt;/a&gt; and &lt;a href="https://aixsap.com/sap-abapta-exception-handling-temiz-guvenilir-ve-surdurulebilir-hata-yonetimi/" rel="noopener noreferrer"&gt;robust exception handling in ABAP&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why These Three Patterns Matter in SAP Environments
&lt;/h2&gt;

&lt;p&gt;SAP systems are notorious for their complexity — multiple integration touchpoints, constantly changing business rules, and the eternal challenge of extending standard functionality without breaking things. Design patterns give you a shared vocabulary and proven blueprints for solving these recurring structural problems.&lt;/p&gt;

&lt;p&gt;Here’s a quick orientation before we get into code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Factory Pattern&lt;/strong&gt;: Controls how objects are created, keeping instantiation logic away from business logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observer Pattern&lt;/strong&gt;: Decouples event producers from event consumers — critical in event-driven SAP architectures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decorator Pattern&lt;/strong&gt;: Adds behavior to objects dynamically without changing the original class — your best friend when extending standard SAP logic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get into each one.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pattern 1: The Factory Pattern — Stop Hardcoding Object Creation
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Problem It Solves
&lt;/h3&gt;

&lt;p&gt;Imagine you have a pricing engine that needs to instantiate different pricing strategies based on customer type: standard, VIP, or wholesale. Without a factory, you’ll see code like this scattered everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;anti&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;instantiation&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;bleeding&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;
&lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;lv_customer_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_pricing&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_vip_pricing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ELSEIF&lt;/span&gt; &lt;span class="n"&gt;lv_customer_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;WHOLESALE&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_pricing&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_wholesale_pricing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_pricing&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_standard_pricing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now imagine this block duplicated across 12 different programs. The day you add a new customer type, you’re hunting through the entire codebase. That’s exactly the problem the Factory Pattern eliminates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing a Simple Factory in ABAP
&lt;/h3&gt;

&lt;p&gt;First, define your interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;INTERFACE&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;calculate_price&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;iv_base_price&lt;/span&gt;   &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="kt"&gt;p&lt;/span&gt; &lt;span class="k"&gt;DECIMALS&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
                &lt;span class="n"&gt;iv_quantity&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;i&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv_final_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="kt"&gt;p&lt;/span&gt; &lt;span class="k"&gt;DECIMALS&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDINTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then implement your concrete classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Standard&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;no&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_standard_pricing&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_standard_pricing&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;calculate_price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rv_final_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_base_price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;iv_quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;VIP&lt;/span&gt; &lt;span class="n"&gt;pricing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;discount&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_vip_pricing&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_vip_pricing&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;calculate_price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rv_final_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_base_price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;iv_quantity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the factory class itself — this is where the magic lives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_pricing_factory&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PRIVATE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;get_instance&lt;/span&gt;
        &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ro_factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_pricing_factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;create_strategy&lt;/span&gt;
        &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;iv_customer_type&lt;/span&gt;        &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;char10&lt;/span&gt;
        &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ro_strategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;
        &lt;span class="k"&gt;RAISING&lt;/span&gt;   &lt;span class="n"&gt;zcx_unknown_customer_type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;go_instance&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_pricing_factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_pricing_factory&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;only&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="k"&gt;instance&lt;/span&gt; &lt;span class="n"&gt;needed&lt;/span&gt;
    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;go_instance&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;BOUND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;go_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ro_factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;go_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;create_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="n"&gt;iv_customer_type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;STANDARD&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;ro_strategy&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_standard_pricing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;VIP&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;ro_strategy&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_vip_pricing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;WHOLESALE&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;ro_strategy&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_wholesale_pricing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;OTHERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Always&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;typed&lt;/span&gt; &lt;span class="k"&gt;exception&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;see&lt;/span&gt; &lt;span class="n"&gt;our&lt;/span&gt; &lt;span class="k"&gt;exception&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt; &lt;span class="n"&gt;guide&lt;/span&gt;
        &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_unknown_customer_type&lt;/span&gt;
          &lt;span class="k"&gt;EXPORTING&lt;/span&gt; &lt;span class="n"&gt;iv_customer_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_customer_type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDCASE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your business code becomes clean and future-proof:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lo_factory&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_pricing_factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lo_strategy&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_pricing_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;lo_factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zcl_pricing_factory&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;lo_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo_factory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create_strategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;iv_customer_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_cust_type&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo_strategy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;calculate_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;iv_base_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;iv_quantity&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_unknown_customer_type&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_exc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Log&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;handle&lt;/span&gt; &lt;span class="n"&gt;gracefully&lt;/span&gt;
&lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a new customer type now means adding one class and one WHEN clause in the factory. Nothing else changes. That’s the power of encapsulated object creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 2: The Observer Pattern — Event-Driven Logic Without Tight Coupling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem It Solves
&lt;/h3&gt;

&lt;p&gt;Consider a sales order creation process. When an order is created, you might need to: send a notification email, update a reporting table, and trigger a downstream MES workflow. Without the Observer pattern, your order creation class ends up calling all of these directly — a violation of the Single Responsibility Principle and a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;The Observer pattern lets you define a &lt;em&gt;subject&lt;/em&gt; (the order) and &lt;em&gt;observers&lt;/em&gt; (notification, reporting, MES integration) that register themselves and react independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  ABAP Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Observer&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt; &lt;span class="n"&gt;must&lt;/span&gt; &lt;span class="n"&gt;implement&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;
&lt;span class="k"&gt;INTERFACE&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;on_order_created&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zs_sales_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDINTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Subject&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;observable&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;
&lt;span class="k"&gt;INTERFACE&lt;/span&gt; &lt;span class="n"&gt;zif_order_subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;attach&lt;/span&gt; &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;io_observer&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;detach&lt;/span&gt; &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;io_observer&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zs_sales_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDINTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Concrete&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sales&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_sales_order_processor&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_order_subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;create_order&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zs_sales_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gt_observers&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_sales_order_processor&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_order_subject&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;APPEND&lt;/span&gt; &lt;span class="n"&gt;io_observer&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;gt_observers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_order_subject&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;detach&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="n"&gt;gt_observers&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;table_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io_observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_order_subject&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;gt_observers&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo_observer&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="n"&gt;lo_observer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;on_order_created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="n"&gt;creation&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;database&lt;/span&gt; &lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;number&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Notify&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt; &lt;span class="n"&gt;registered&lt;/span&gt; &lt;span class="n"&gt;observers&lt;/span&gt;
    &lt;span class="n"&gt;zif_order_subject&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Concrete&lt;/span&gt; &lt;span class="n"&gt;Observer&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_email_notifier&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_email_notifier&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;on_order_created&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Send&lt;/span&gt; &lt;span class="n"&gt;confirmation&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;cl_bcs&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;custom&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;
    &lt;span class="k"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Concrete&lt;/span&gt; &lt;span class="n"&gt;Observer&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MES&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_mes_trigger&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_mes_trigger&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;on_order_created&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Trigger&lt;/span&gt; &lt;span class="n"&gt;MES&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="k"&gt;via&lt;/span&gt; &lt;span class="n"&gt;REST&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;IDoc&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;See&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;SAP&lt;/span&gt; &lt;span class="n"&gt;MES&lt;/span&gt; &lt;span class="n"&gt;Integration&lt;/span&gt; &lt;span class="n"&gt;architecture&lt;/span&gt; &lt;span class="n"&gt;article&lt;/span&gt;
    &lt;span class="k"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;MES&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="n"&gt;triggered&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wiring it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lo_processor&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_sales_order_processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lo_email&lt;/span&gt;      &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_order_email_notifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lo_mes&lt;/span&gt;        &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_order_mes_trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_mes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Register&lt;/span&gt; &lt;span class="n"&gt;observers&lt;/span&gt;
&lt;span class="n"&gt;lo_processor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lo_email&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="n"&gt;lo_processor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lo_mes&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Create&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;observers&lt;/span&gt; &lt;span class="n"&gt;fire&lt;/span&gt; &lt;span class="n"&gt;automatically&lt;/span&gt;
&lt;span class="n"&gt;lo_processor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want to add a reporting observer next month? Create the class, register it. The processor never changes. This is exactly the kind of extensibility you need in a living SAP system — and it pairs beautifully with the event-driven approach we discussed in the context of &lt;a href="https://aixsap.com/sap-btp-event-mesh-event-driven-architecture-building-resilient-integrations-that-actually-scale/" rel="noopener noreferrer"&gt;SAP BTP Event Mesh architectures&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 3: The Decorator Pattern — Extending Behavior Without Inheritance Hell
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem It Solves
&lt;/h3&gt;

&lt;p&gt;Here’s a scenario I see regularly: you have a report output class that formats data. Now stakeholders want optional features — logging, caching, and access control — applied in different combinations. Using inheritance, you’d need a class for every combination: LoggingCachingOutputFormatter, CachingOutputFormatter, etc. That explodes fast.&lt;/p&gt;

&lt;p&gt;The Decorator pattern wraps objects to add behavior dynamically, without subclassing. It’s composable, testable, and elegant.&lt;/p&gt;

&lt;h3&gt;
  
  
  ABAP Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;
&lt;span class="k"&gt;INTERFACE&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;format_data&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt;          &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;ztt_report_data&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDINTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Base&lt;/span&gt; &lt;span class="n"&gt;concrete&lt;/span&gt; &lt;span class="k"&gt;implementation&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_base_formatter&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_base_formatter&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Core&lt;/span&gt; &lt;span class="n"&gt;formatting&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;converts&lt;/span&gt; &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt; &lt;span class="k"&gt;output&lt;/span&gt;
    &lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_row&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="k"&gt;CONCATENATE&lt;/span&gt; &lt;span class="n"&gt;rv_output&lt;/span&gt; &lt;span class="n"&gt;ls_row&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;field1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;ls_row&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;field2&lt;/span&gt; &lt;span class="n"&gt;CL_ABAP_CHAR_UTILITIES&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;NEWLINE&lt;/span&gt;
        &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;rv_output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Abstract&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;holds&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;reference&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt; &lt;span class="k"&gt;component&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_formatter_decorator&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;ABSTRACT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;io_wrapped&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PROTECTED&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mo_wrapped&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_formatter_decorator&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mo_wrapped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io_wrapped&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt; &lt;span class="k"&gt;component&lt;/span&gt;
    &lt;span class="n"&gt;rv_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_wrapped&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Logging&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt; &lt;span class="k"&gt;any&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;adds&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_logging_formatter&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;INHERITING&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;zcl_formatter_decorator&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt; &lt;span class="k"&gt;REDEFINITION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_logging_formatter&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cl_abap_systime&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_current_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Delegate&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt;
    &lt;span class="n"&gt;rv_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_wrapped&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cl_abap_systime&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_current_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Log&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt; &lt;span class="k"&gt;time&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;application&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;
    &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;Formatter&lt;/span&gt; &lt;span class="n"&gt;executed&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;lv_end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lv_start&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;I&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Caching&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="n"&gt;hasn&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="kt"&gt;t&lt;/span&gt; &lt;span class="n"&gt;changed&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_caching_formatter&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;INHERITING&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;zcl_formatter_decorator&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt; &lt;span class="k"&gt;REDEFINITION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mv_cache&lt;/span&gt;      &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;mv_cache_key&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_caching_formatter&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Simple&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;based&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;first&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="k"&gt;field&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;|{&lt;/span&gt; &lt;span class="nb"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}|.&lt;/span&gt;

    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;lv_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mv_cache_key&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;mv_cache&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;INITIAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;rv_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mv_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="k"&gt;result&lt;/span&gt;
      &lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;rv_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_wrapped&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="n"&gt;mv_cache&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rv_output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mv_cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now compose them however you need, at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Build&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Base&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;Log&lt;/span&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lo_base&lt;/span&gt;    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lo_cached&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lo_logged&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_data_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_base&lt;/span&gt;   &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_base_formatter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_cached&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_caching_formatter&lt;/span&gt; &lt;span class="k"&gt;EXPORTING&lt;/span&gt; &lt;span class="n"&gt;io_wrapped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo_base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OBJECT&lt;/span&gt; &lt;span class="n"&gt;lo_logged&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcl_logging_formatter&lt;/span&gt; &lt;span class="k"&gt;EXPORTING&lt;/span&gt; &lt;span class="n"&gt;io_wrapped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo_cached&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;caller&lt;/span&gt; &lt;span class="n"&gt;uses&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;unaware&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="kt"&gt;s&lt;/span&gt; &lt;span class="n"&gt;underneath&lt;/span&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo_logged&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;format_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;it_raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lt_data&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap decorators in and out based on configuration. Add an access-control decorator for certain users. None of the underlying classes change. This is composition over inheritance in action — one of the most important principles in the &lt;a href="https://aixsap.com/abap-clean-code-okunabilir-ve-surdurulebilir-sap-kodu-yazmanin-10-altin-kurali/" rel="noopener noreferrer"&gt;Clean ABAP guidelines&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Which Pattern — A Decision Guide
&lt;/h2&gt;

&lt;p&gt;Pattern&lt;br&gt;
Use When&lt;br&gt;
Avoid When&lt;/p&gt;

&lt;p&gt;Factory&lt;br&gt;
Object creation logic is complex or type-dependent&lt;br&gt;
You only ever create one type of object&lt;/p&gt;

&lt;p&gt;Observer&lt;br&gt;
One event triggers multiple independent reactions&lt;br&gt;
Observers are tightly ordered and dependent on each other&lt;/p&gt;

&lt;p&gt;Decorator&lt;br&gt;
You need to combine behaviors at runtime without subclassing&lt;br&gt;
Behavior combinations are fixed and few&lt;/p&gt;
&lt;h2&gt;
  
  
  Making Patterns Testable with ABAP Unit
&lt;/h2&gt;

&lt;p&gt;One underrated benefit of these patterns is testability. Because each component depends on interfaces, not concrete classes, you can inject test doubles easily. If you’re not yet writing unit tests for your ABAP classes, now is the time — our dedicated guide on &lt;a href="https://aixsap.com/abap-unit-testing-in-sap-s-4hana-a-senior-architects-guide-to-writing-tests-that-actually-matter/" rel="noopener noreferrer"&gt;ABAP unit testing in SAP S/4HANA&lt;/a&gt; walks through exactly how to structure tests for OOP-based code.&lt;/p&gt;

&lt;p&gt;For example, testing the Observer pattern is trivial with a mock observer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_mock_observer&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mv_was_called&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;abap_bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;ms_received&lt;/span&gt;   &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zs_sales_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_mock_observer&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_order_observer&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;on_order_created&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mv_was_called&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ms_received&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;is_order_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inject the mock, trigger the action, assert mv_was_called = abap_true. Clean, isolated, fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Factory Pattern&lt;/strong&gt; centralizes object creation and makes your codebase extensible without scattering CREATE OBJECT logic everywhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Observer Pattern&lt;/strong&gt; decouples event producers from consumers, making it easy to add new reactions to system events without modifying existing code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Decorator Pattern&lt;/strong&gt; lets you compose behaviors dynamically — far more flexible than deep inheritance hierarchies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;All three patterns make your code significantly easier to unit test, a non-negotiable requirement in modern SAP development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;These aren’t theoretical niceties — they solve concrete problems you face in every mid-to-large SAP project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re just getting started with OOP in ABAP and found this article dense, I’d recommend revisiting the Strategy Pattern from &lt;a href="https://aixsap.com/abap-oop-ile-tasarim-desenleri-abap-oop-ve-strategy-pattern-gercek-dunya-uygulamalari/" rel="noopener noreferrer"&gt;Part 1 of this series&lt;/a&gt; first — it lays the foundation that makes these patterns click.&lt;/p&gt;

&lt;p&gt;In Part 3, we’ll explore the &lt;strong&gt;Command&lt;/strong&gt; and &lt;strong&gt;Template Method&lt;/strong&gt; patterns — both essential for building undo/redo mechanisms, batch processing pipelines, and workflow engines in SAP. Stay tuned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s your experience with design patterns in ABAP?&lt;/strong&gt; Have you applied any of these on a real project? I’d love to hear what worked, what didn’t, and what challenges you ran into. Drop a comment below or connect with me — let’s keep the conversation going.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>ABAP Unit Testing in SAP S/4HANA: A Senior Architect's Guide to Writing Tests That Actually Matter</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Mon, 30 Mar 2026 21:35:37 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/abap-unit-testing-in-sap-s4hana-a-senior-architects-guide-to-writing-tests-that-actually-matter-2816</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/abap-unit-testing-in-sap-s4hana-a-senior-architects-guide-to-writing-tests-that-actually-matter-2816</guid>
      <description>&lt;p&gt;Let me be honest with you: for most of my early career, ABAP unit testing felt like a box-ticking exercise. Write a test, make it green, move on. It wasn’t until I inherited a legacy codebase that kept breaking in production—in ways nobody could predict—that I truly understood what good unit tests are worth. If you’re serious about building &lt;strong&gt;ABAP unit testing&lt;/strong&gt; practices that create real safety nets, this guide is for you.&lt;br&gt;
We’re going to go well beyond the basics. We’ll look at test doubles, dependency injection in ABAP OOP, how to structure test classes for maintainability, and how to integrate testing into your development workflow in a way that actually sticks—without slowing your team to a crawl.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why ABAP Unit Testing Is More Critical Than Ever in S/4HANA
&lt;/h2&gt;

&lt;p&gt;S/4HANA migration projects are exposing years of technical debt. I’ve seen it repeatedly: a business-critical program that “works fine” on ECC gets migrated, and suddenly edge cases that were hidden for a decade start surfacing. Without a solid test suite, every change becomes a leap of faith.&lt;/p&gt;

&lt;p&gt;Beyond migrations, the modern ABAP landscape has shifted dramatically. Clean ABAP principles (which we explored in &lt;a href="https://aixsap.com/abap-clean-code-okunabilir-ve-surdurulebilir-sap-kodu-yazmanin-10-altin-kurali/" rel="noopener noreferrer"&gt;ABAP Clean Code: 10 Golden Rules for Readable and Maintainable SAP Code&lt;/a&gt;) demand testability as a first-class concern. You can’t write clean code without writing testable code—they’re the same discipline.&lt;/p&gt;

&lt;p&gt;Here’s the business case in plain terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced regression risk&lt;/strong&gt;: Catch breaking changes before they reach production&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster onboarding&lt;/strong&gt;: Tests document intent better than comments ever will&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refactoring confidence&lt;/strong&gt;: Modify code without fear when your test suite has your back&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Technical debt visibility&lt;/strong&gt;: Hard-to-test code is a direct indicator of poor design&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Anatomy of a Good ABAP Unit Test
&lt;/h2&gt;

&lt;p&gt;Before we write a single line, let’s align on what makes a unit test valuable. I use the &lt;strong&gt;FIRST principles&lt;/strong&gt; as my mental checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;F&lt;/strong&gt;ast — Runs in milliseconds, no database round-trips&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;I&lt;/strong&gt;ndependent — Each test stands alone, no shared state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;R&lt;/strong&gt;epeatable — Same result every time, regardless of environment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;S&lt;/strong&gt;elf-validating — Pass or fail, no manual inspection needed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;T&lt;/strong&gt;imely — Written close to (or before) the production code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most ABAP unit tests I’ve audited fail on “Fast” and “Independent” because they hit the database or depend on system configuration. We’ll fix that.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up Your Test Class: The Local Test Class Pattern
&lt;/h2&gt;

&lt;p&gt;ABAP unit tests live in local test classes defined in the test include of a global class, or directly in a program’s test include. Here’s the standard scaffold I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;testing&lt;/span&gt; &lt;span class="n"&gt;ZCL_ORDER_VALIDATOR&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_order_validator&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;
  &lt;span class="k"&gt;RISK&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="k"&gt;HARMLESS&lt;/span&gt;
  &lt;span class="k"&gt;DURATION&lt;/span&gt; &lt;span class="k"&gt;SHORT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_order_validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;CUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;Class&lt;/span&gt; &lt;span class="k"&gt;Under&lt;/span&gt; &lt;span class="k"&gt;Test&lt;/span&gt;

    &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Runs&lt;/span&gt; &lt;span class="k"&gt;before&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;test&lt;/span&gt; &lt;span class="k"&gt;method&lt;/span&gt;
      &lt;span class="n"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Runs&lt;/span&gt; &lt;span class="k"&gt;after&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;test&lt;/span&gt; &lt;span class="k"&gt;method&lt;/span&gt;
      &lt;span class="n"&gt;should_reject_empty_order&lt;/span&gt;         &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;should_accept_valid_order&lt;/span&gt;         &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;should_reject_order_over_limit&lt;/span&gt;    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_order_validator&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mo_cut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt; &lt;span class="n"&gt;zcl_order_validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CLEAR&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;should_reject_empty_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Arrange&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;zs_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Act&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_result&lt;/span&gt;
      &lt;span class="n"&gt;exp&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_false&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Empty&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;rejected&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;should_accept_valid_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Arrange&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;zs_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;order_id&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;4500001234&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;material&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;MAT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;quantity&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
      &lt;span class="k"&gt;unit&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;PC&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Act&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_result&lt;/span&gt;
      &lt;span class="n"&gt;exp&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Valid&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;accepted&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;should_reject_order_over_limit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Arrange&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;zs_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;order_id&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;4500001235&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;material&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;MAT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;quantity&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;99999&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Exceeds&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;
      &lt;span class="k"&gt;unit&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;PC&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Act&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_result&lt;/span&gt;
      &lt;span class="n"&gt;exp&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_false&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;exceeding&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;rejected&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the naming convention: should_[expected_behavior]_[when_condition]. This reads like a specification. When a test fails at 2am, you want the name to tell you exactly what broke—not force you to dig through code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Injection: The Key to Testable ABAP OOP Code
&lt;/h2&gt;

&lt;p&gt;Here’s where most ABAP developers hit a wall. Your class calls a database-reading helper, an RFC, or a BAdI. How do you test the logic without actually hitting those external dependencies?&lt;/p&gt;

&lt;p&gt;The answer is &lt;strong&gt;dependency injection&lt;/strong&gt;—and it pairs perfectly with the OOP design patterns covered in &lt;a href="https://aixsap.com/abap-oop-ile-tasarim-desenleri-abap-oop-ve-strategy-pattern-gercek-dunya-uygulamalari/" rel="noopener noreferrer"&gt;ABAP OOP and Strategy Pattern: Real-World Applications&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the pattern in practice. First, define an interface for your dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;INTERFACE&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;get_by_id&lt;/span&gt;
    &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;iv_material_id&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt;
    &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs_material&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;
    &lt;span class="k"&gt;RAISING&lt;/span&gt;   &lt;span class="n"&gt;zcx_material_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDINTERFACE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then implement the real version that hits the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_material_repository&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_material_repository&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SINGLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;
      &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;iv_material_id&lt;/span&gt;
      &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;rs_material&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_material_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now inject the dependency through the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_processor&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt;
  &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;io_material_repo&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;process_order&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;is_order&lt;/span&gt;        &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zs_order&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv_success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;abap_bool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;mo_material_repo&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_processor&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mo_material_repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io_material_repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;process_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_material&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_material_repo&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;is_order&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;material&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
      &lt;span class="n"&gt;rv_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_material_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;rv_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_false&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Test Doubles: Mocks, Stubs, and Fakes in ABAP
&lt;/h2&gt;

&lt;p&gt;With dependency injection in place, you can now inject a fake implementation during testing. Let’s create a test double for our material repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Define&lt;/span&gt; &lt;span class="n"&gt;inside&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;test&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="k"&gt;include&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_material_repo_stub&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;INTERFACES&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;ms_return_material&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;mv_should_raise&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;abap_bool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_material_repo_stub&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;zif_material_repository&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;mv_should_raise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_material_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rs_material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ms_return_material&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;testing&lt;/span&gt; &lt;span class="n"&gt;ZCL_ORDER_PROCESSOR&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_order_processor&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;
  &lt;span class="k"&gt;RISK&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="k"&gt;HARMLESS&lt;/span&gt;
  &lt;span class="k"&gt;DURATION&lt;/span&gt; &lt;span class="k"&gt;SHORT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;       &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcl_order_processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;mo_repo_stub&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;ltc_material_repo_stub&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;should_succeed_when_material_found&lt;/span&gt;    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;should_fail_when_material_not_found&lt;/span&gt;   &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;TESTING&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;ltc_order_processor&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mo_repo_stub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt; &lt;span class="n"&gt;ltc_material_repo_stub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="n"&gt;mo_cut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt; &lt;span class="n"&gt;zcl_order_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;mo_repo_stub&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;should_succeed_when_material_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Arrange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Configure&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;valid&lt;/span&gt; &lt;span class="n"&gt;material&lt;/span&gt;
    &lt;span class="n"&gt;mo_repo_stub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ms_return_material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;MAT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="n"&gt;mo_repo_stub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mv_should_raise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_false&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Act&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;zs_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;MAT&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_true&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_success&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;succeed&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="n"&gt;material&lt;/span&gt; &lt;span class="k"&gt;exists&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;should_fail_when_material_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Arrange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Configure&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;simulate&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="n"&gt;material&lt;/span&gt;
    &lt;span class="n"&gt;mo_repo_stub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mv_should_raise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Act&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;zs_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;GHOST&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;MAT&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_false&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_success&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="k"&gt;fail&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="n"&gt;material&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="n"&gt;exist&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No database. No RFC calls. These tests run in under 10 milliseconds, and they prove exactly what you need them to prove.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Exception Handling: Don’t Skip This
&lt;/h2&gt;

&lt;p&gt;One of the most overlooked aspects of unit testing is verifying that your exception handling logic—which we explored deeply in &lt;a href="https://aixsap.com/sap-abapta-exception-handling-temiz-guvenilir-ve-surdurulebilir-hata-yonetimi/" rel="noopener noreferrer"&gt;ABAP Exception Handling: Clean, Reliable Error Management&lt;/a&gt;—actually works as designed. Here’s how to assert that an exception is raised:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;should_raise_exception_on_null_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;lx_exception&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;zcx_invalid_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;mo_cut&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;If&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;reach&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;test&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="k"&gt;fail&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Expected&lt;/span&gt; &lt;span class="n"&gt;ZCX_INVALID_INPUT&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;raised&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_invalid_input&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;lx_exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Assert&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;exception&lt;/span&gt; &lt;span class="n"&gt;carries&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;right&lt;/span&gt; &lt;span class="k"&gt;message&lt;/span&gt;
    &lt;span class="n"&gt;cl_abap_unit_assert&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assert_not_initial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;act&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx_exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;carry&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;meaningful&lt;/span&gt; &lt;span class="k"&gt;message&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Pitfalls to Avoid
&lt;/h2&gt;

&lt;p&gt;I’ve reviewed hundreds of ABAP test suites. Here are the mistakes I see most often:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Testing Implementation, Not Behavior
&lt;/h3&gt;

&lt;p&gt;Your test should answer “does this method do what I expect?” not “does this method call these internal methods in this order?” If your tests break every time you refactor internals, they’re testing the wrong thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. One Giant Setup Method
&lt;/h3&gt;

&lt;p&gt;When your setup method tries to configure everything for every possible test scenario, tests become impossible to understand. Instead, create helper methods that each test can call to set up only what it needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Magic Numbers Without Explanation
&lt;/h3&gt;

&lt;p&gt;Why is the quantity limit 99999? Document it. A test is documentation first, verification second.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Ignoring the Risk Level Annotation
&lt;/h3&gt;

&lt;p&gt;Use RISK LEVEL HARMLESS for pure unit tests. If a test really does need database access (for integration-style tests), set it to CRITICAL and separate it from your unit test suite. Mixing them destroys your fast feedback loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Unit Tests Into Your Development Workflow
&lt;/h2&gt;

&lt;p&gt;Writing tests is only half the battle. The other half is making sure they actually get run. Here’s the workflow I recommend for teams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run unit tests before every transport release&lt;/strong&gt; — Use transaction SE80 or ABAP Development Tools (ADT) in Eclipse to run tests for all affected objects&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set a code coverage target&lt;/strong&gt; — I recommend starting at 60% and moving toward 80% over time. Perfect coverage is a myth; meaningful coverage is the goal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use ATC (ABAP Test Cockpit) rules&lt;/strong&gt; — Configure ATC to flag objects that have zero test coverage as a code quality warning&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review test code in code reviews&lt;/strong&gt; — Test code is production code. It deserves the same scrutiny&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never skip tests to meet a deadline&lt;/strong&gt; — This is the most expensive shortcut in software development&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Reference: Key cl_abap_unit_assert Methods
&lt;/h2&gt;

&lt;p&gt;Method&lt;br&gt;
Use When&lt;/p&gt;

&lt;p&gt;assert_equals&lt;br&gt;
Exact value match expected&lt;/p&gt;

&lt;p&gt;assert_not_equals&lt;br&gt;
Value must differ from unexpected&lt;/p&gt;

&lt;p&gt;assert_true&lt;br&gt;
Boolean condition must be true&lt;/p&gt;

&lt;p&gt;assert_false&lt;br&gt;
Boolean condition must be false&lt;/p&gt;

&lt;p&gt;assert_initial&lt;br&gt;
Variable must be initial/empty&lt;/p&gt;

&lt;p&gt;assert_not_initial&lt;br&gt;
Variable must have a value&lt;/p&gt;

&lt;p&gt;assert_bound&lt;br&gt;
Reference must not be null&lt;/p&gt;

&lt;p&gt;assert_not_bound&lt;br&gt;
Reference must be null&lt;/p&gt;

&lt;p&gt;fail&lt;br&gt;
Force a test failure unconditionally&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts: Tests Are a Design Activity
&lt;/h2&gt;

&lt;p&gt;The best insight I can offer after years of working on SAP systems is this: if your code is hard to test, your design has a problem. Testability is a forcing function for good architecture. The moment you try to write a unit test and realize you need to spin up half the SAP system to do it, that’s feedback—feedback that your class is doing too much or knows too much about its surroundings.&lt;/p&gt;

&lt;p&gt;Start small. Pick one class, write three meaningful tests for it. See how it feels. Then expand. The habit, once formed, is genuinely one of the most valuable professional skills you can build as an ABAP developer.&lt;/p&gt;

&lt;p&gt;And if you’re working on the performance side of things—making your ABAP code not just correct but fast—make sure to check out &lt;a href="https://aixsap.com/sap-abap-performance-optimization-identifying-and-fixing-bottlenecks-in-real-world-systems/" rel="noopener noreferrer"&gt;SAP ABAP Performance Optimization: Identifying and Fixing Bottlenecks in Real-World Systems&lt;/a&gt;. Tests and performance go hand in hand: you can’t safely optimize code you haven’t tested.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s your current testing setup look like?&lt;/strong&gt; Are you starting from zero, or trying to add tests to an existing codebase? Drop a comment below—I read every one, and real-world questions often turn into future articles. If this was useful, share it with a colleague who’s still shipping code without tests. 🙂&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Technical Leadership in SAP Projects: How Senior Architects Make Better Decisions Under Pressure</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Mon, 30 Mar 2026 21:33:21 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/technical-leadership-in-sap-projects-how-senior-architects-make-better-decisions-under-pressure-4chi</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/technical-leadership-in-sap-projects-how-senior-architects-make-better-decisions-under-pressure-4chi</guid>
      <description>&lt;p&gt;Technical Leadership in SAP Projects: How Senior Architects Make Better Decisions Under Pressure&lt;br&gt;
Every seasoned SAP architect has been there. It’s 11 PM, production is down, the business is losing thousands of dollars per hour, and three junior developers are staring at you waiting for a clear direction. In that moment, your technical depth matters—but it’s your &lt;strong&gt;technical leadership&lt;/strong&gt; that determines the outcome. After years of navigating these high-stakes moments in SAP environments, I want to share what actually works when the pressure is on, and more importantly, how to build the decision-making muscle before you ever need it.&lt;/p&gt;

&lt;p&gt;This article is for architects and senior developers who are either stepping into leadership roles or looking to sharpen their judgment in complex SAP project environments. We’ll cover structured decision frameworks, trade-off analysis, how to communicate architectural decisions effectively, and how to grow the next generation of SAP engineers around you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Technical Leadership in SAP Is Uniquely Challenging
&lt;/h2&gt;

&lt;p&gt;SAP landscapes are not typical software environments. You’re dealing with decades of business logic baked into customizations, strict upgrade cycles, deep integration dependencies, and organizations that are often risk-averse by nature. When you layer modern technologies—SAP BTP, ABAP RESTful Application Programming Model (RAP), CDS Views, event-driven architecture—on top of a legacy core, the architectural decisions become exponentially more complex.&lt;/p&gt;

&lt;p&gt;Here’s what makes technical leadership in SAP particularly demanding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Legacy debt is invisible until it bites you.&lt;/strong&gt; Years of undocumented enhancements, Z-programs, and BADI implementations create a minefield that only becomes visible mid-project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Business stakeholders speak a different language.&lt;/strong&gt; Translating “we need to refactor the IDoc processing layer” into business risk and timeline impact is genuinely hard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The SAP ecosystem evolves faster than most teams can absorb.&lt;/strong&gt; Clean Core, BTP extensions, S/4HANA migration—the rate of change demands continuous architectural re-evaluation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Decisions have long tails.&lt;/strong&gt; A poor integration design choice made today might surface as a performance crisis two years into production. The architect who made the call may no longer even be on the project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these constraints isn’t pessimism—it’s the foundation of good leadership. You make better decisions when you honestly acknowledge the environment you’re operating in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture Decision Record (ADR): Your Most Underused Tool
&lt;/h2&gt;

&lt;p&gt;One of the most impactful habits I’ve developed over the years is consistently writing Architecture Decision Records. An ADR is a short, structured document that captures &lt;em&gt;why&lt;/em&gt; a significant technical decision was made, not just what was decided.&lt;/p&gt;

&lt;p&gt;In SAP projects, this is particularly valuable. When a team three years from now is wondering why the system uses IDocs for vendor invoice integration instead of REST services, the ADR tells the story—including the constraints, the alternatives considered, and the trade-offs accepted.&lt;/p&gt;

&lt;h3&gt;
  
  
  ADR Template for SAP Projects
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
&lt;span class="gu"&gt;## ADR-0042: Use SAP Event Mesh for Order-to-Cash Integration&lt;/span&gt;

&lt;span class="gs"&gt;**Date:**&lt;/span&gt; 2025-01-15  
&lt;span class="gs"&gt;**Status:**&lt;/span&gt; Accepted  
&lt;span class="gs"&gt;**Deciders:**&lt;/span&gt; [Lead Architect, Integration Team Lead, BTP Platform Owner]

&lt;span class="gu"&gt;### Context&lt;/span&gt;
The Order-to-Cash process requires near-real-time event propagation 
between S/4HANA and three downstream systems (CRM, WMS, external 3PL).
Current IDoc-based approach introduces 15-30 minute delays and brittle 
point-to-point coupling.

&lt;span class="gu"&gt;### Decision&lt;/span&gt;
We will adopt SAP BTP Event Mesh as the central event broker for all 
Order-to-Cash domain events, replacing current IDoc RFC calls.

&lt;span class="gu"&gt;### Alternatives Considered&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; &lt;span class="gs"&gt;**Direct REST APIs**&lt;/span&gt; – Synchronous; creates tight coupling, 
   cascading failure risk under load.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Enhanced IDocs with immediate delivery**&lt;/span&gt; – Reduces delay but 
   doesn&lt;span class="ni"&gt;&amp;amp;#039;&lt;/span&gt;t solve the coupling problem; limits future extensibility.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**SAP Integration Suite with polling**&lt;/span&gt; – Introduces unnecessary 
   complexity; polling defeats event-driven purpose.

&lt;span class="gu"&gt;### Consequences&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Positive: Loose coupling, independent scalability, audit trail via 
  event log, supports future consumer onboarding without sender changes.
&lt;span class="p"&gt;-&lt;/span&gt; Negative: Team upskilling required on event-driven patterns; 
  added BTP licensing cost; eventual consistency model requires 
  business process alignment.

&lt;span class="gu"&gt;### Review Date: 2026-01-15&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the “Review Date” field. Good architectural decisions have expiry dates. What’s correct today may be wrong tomorrow, and building in a review cycle signals intellectual honesty to your team.&lt;/p&gt;

&lt;p&gt;If you’re exploring event-driven architectures in SAP, our article on &lt;a href="https://aixsap.com/sap-btp-event-mesh-event-driven-architecture-building-resilient-integrations-that-actually-scale/" rel="noopener noreferrer"&gt;SAP BTP Event Mesh and building resilient integrations&lt;/a&gt; provides deep technical context that pairs well with the ADR approach described here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision-Making Under Pressure: A Framework That Actually Works
&lt;/h2&gt;

&lt;p&gt;When you’re in a production crisis or a contentious architecture review, structured thinking is your best ally. I use a lightweight framework I call &lt;strong&gt;SCOPE&lt;/strong&gt; for time-pressured decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;S – Situation clarity:&lt;/strong&gt; What exactly is the problem? Don’t skip this. In SAP incidents, it’s common to spend 40 minutes solving the wrong problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;C – Constraints visible:&lt;/strong&gt; What can’t we change? Business hours, system availability windows, release cycles, compliance requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O – Options on the table:&lt;/strong&gt; Generate at least three options. The worst decisions come from false binary choices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;P – Probability and impact:&lt;/strong&gt; Quick mental model—what’s the likelihood each option creates new problems, and how severe?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;E – Execute and document:&lt;/strong&gt; Make the call, own it, and write down why. Even a Slack message to the team counts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The SCOPE framework won’t eliminate bad calls—nothing will. But it dramatically reduces the &lt;em&gt;type&lt;/em&gt; of bad call where you react emotionally, skip analysis, or let the loudest voice in the room drive the decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Example: Handling an ABAP Performance Crisis
&lt;/h3&gt;

&lt;p&gt;Imagine a critical batch job in SD is timing out after the S/4HANA migration. Business is escalating. Here’s SCOPE in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;S:&lt;/strong&gt; Batch job SELECT on VBAP and VBAK with joins runs 40+ minutes in S/4HANA vs. 8 minutes in ECC. Migration was two weeks ago.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;C:&lt;/strong&gt; Can’t modify table structures; can’t postpone month-end close; only four-hour maintenance window available tomorrow morning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O:&lt;/strong&gt; Option 1—rewrite SELECT to use CDS View with proper indexing. Option 2—introduce background parallelization using CALL FUNCTION IN BACKGROUND TASK. Option 3—apply SAP Note for known HANA optimizer issue with this query pattern.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;P:&lt;/strong&gt; Option 3 is lowest risk if a relevant SAP Note exists (check first). Option 1 is medium risk—requires testing. Option 2 is highest risk—architecture change under time pressure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;E:&lt;/strong&gt; Check SAP Notes immediately. If no note, proceed with Option 1 in the maintenance window with a clear rollback plan.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For deeper context on ABAP performance investigation techniques, I recommend reading our &lt;a href="https://aixsap.com/sap-abap-performance-optimization-identifying-and-fixing-bottlenecks-in-real-world-systems/" rel="noopener noreferrer"&gt;ABAP performance optimization guide covering real-world bottleneck identification&lt;/a&gt;—the query analysis patterns there apply directly to scenarios like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communicating Architecture to Non-Technical Stakeholders
&lt;/h2&gt;

&lt;p&gt;One of the skills that separates good technical leads from great ones is the ability to make complex architectural concepts legible to business stakeholders—without dumbing them down or being condescending.&lt;/p&gt;

&lt;p&gt;Here’s a technique I’ve refined over many project steering committees: the &lt;strong&gt;Three-Layer Communication Model&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: Business Impact (30 seconds)
&lt;/h3&gt;

&lt;p&gt;Lead with what changes for the business. “This change means your finance team will see vendor payment statuses update in near-real time instead of with a 30-minute delay.”&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: Why It Works (60 seconds)
&lt;/h3&gt;

&lt;p&gt;Explain the mechanism without jargon. “Currently, our systems use a messaging format called IDoc that requires a scheduler to run every 30 minutes. We’re replacing it with an event-driven approach—think of it like switching from scheduled email digests to instant push notifications.”&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: Risk and Cost (as long as needed)
&lt;/h3&gt;

&lt;p&gt;Be honest about trade-offs. This is where architects lose credibility by overselling. Acknowledge the upskilling cost, the testing effort, and the rollback complexity. Stakeholders respect honesty far more than false confidence.&lt;/p&gt;

&lt;p&gt;The moment you start using acronyms in a business meeting without explaining them first, you’ve lost the room. Every IDoc, BAPI, RFC, and CDS acronym needs to earn its place in the conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Growing the Next Generation: Mentorship as a Leadership Responsibility
&lt;/h2&gt;

&lt;p&gt;Technical leadership isn’t just about making the right calls yourself—it’s about building a team that makes good calls when you’re not in the room. This is the hardest part of the job, and the most rewarding.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Guided Discovery Method
&lt;/h3&gt;

&lt;p&gt;When a junior developer brings you a problem, resist the urge to immediately give the answer. Instead, use what I call Guided Discovery:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ask what they’ve already tried.&lt;/strong&gt; This surfaces their reasoning process, not just their conclusion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ask what they think the root cause is.&lt;/strong&gt; Often they’re closer to the answer than they realize.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Offer a directional hint, not the solution.&lt;/strong&gt; “Have you looked at how the selection conditions interact with the buffering strategy here?”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Let them implement and debrief together.&lt;/strong&gt; The learning sticks when they own the fix.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, this takes longer than just fixing the bug yourself. But you’re not optimizing for today’s ticket—you’re building tomorrow’s senior developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Reviews as Teaching Moments
&lt;/h3&gt;

&lt;p&gt;Your code reviews are one of your highest-leverage teaching tools. A few principles that have served me well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comment on the code, never the person.&lt;/strong&gt; “This approach may cause a performance issue under high load” vs. “You wrote this wrong.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explain the why behind every critique.&lt;/strong&gt; If you can’t explain why something should change, question whether it actually needs to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Acknowledge good work explicitly.&lt;/strong&gt; Positive reinforcement in code reviews is criminally underused. If someone wrote a clean ABAP OOP implementation, say so.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use questions, not directives.&lt;/strong&gt; “What happens if this internal table is empty when we reach this loop?” teaches better than “Add a CHECK statement here.”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clean code practices in ABAP are a great foundation for these review conversations. Our &lt;a href="https://aixsap.com/abap-clean-code-okunabilir-ve-surdurulebilir-sap-kodu-yazmanin-10-altin-kurali/" rel="noopener noreferrer"&gt;guide on ABAP Clean Code and writing maintainable SAP code&lt;/a&gt; provides concrete standards that you can reference during reviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-Off Analysis: The Core Skill That Separates Architects from Developers
&lt;/h2&gt;

&lt;p&gt;Anyone can learn ABAP syntax. Anyone can configure a BTP service. The skill that genuinely differentiates a senior architect is the ability to reason clearly about trade-offs—and to make that reasoning transparent to the team.&lt;/p&gt;

&lt;p&gt;A simple but powerful exercise: for every major technical decision, explicitly map it against four dimensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintainability:&lt;/strong&gt; How hard will this be to change in 2 years?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt; What’s the behavior under peak load?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Extensibility:&lt;/strong&gt; Can we add new requirements without structural changes?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Team capability:&lt;/strong&gt; Does the team have the skills to build and operate this? If not, what’s the upskilling cost?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you make these four axes explicit, decisions that seemed purely technical become organizational conversations. A microservices approach on BTP might score high on extensibility but low on team capability right now—and that’s a legitimate reason to choose a simpler architecture today with a clear migration path for later.&lt;/p&gt;

&lt;p&gt;This kind of trade-off thinking is exactly what informs good decisions around process automation in SAP. The architectural considerations around RPA and AI integration—covered in our &lt;a href="https://aixsap.com/sap-btp-ile-akilli-surec-otomasyonu-rpa-ve-ai-entegrasyonunda-mimari-kararlar/" rel="noopener noreferrer"&gt;SAP BTP intelligent process automation article&lt;/a&gt;—are a practical application of this four-dimension framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your Personal Decision-Making Track Record
&lt;/h2&gt;

&lt;p&gt;Here’s a practice almost no one does but everyone should: keep a personal architecture journal. Not a formal document—a running log of decisions you made, why you made them, and what happened.&lt;/p&gt;

&lt;p&gt;Every six months, review it. You’ll start to see patterns in where your instincts are strong and where they consistently lead you astray. This self-awareness is the foundation of genuine technical wisdom—the kind that can’t be taught in a course or read in a book.&lt;/p&gt;

&lt;p&gt;Some questions worth journaling after major decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What information did I have, and what was I missing?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which constraints did I underestimate?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Whose input did I not seek that I should have?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If I made this call again tomorrow, would I change anything?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architects I respect most are not the ones who never make mistakes. They’re the ones who learn from each decision at a structural level—and who actively look for their own blind spots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use Architecture Decision Records to capture the &lt;em&gt;why&lt;/em&gt; behind technical choices—not just the what.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apply a structured framework (like SCOPE) when making high-pressure decisions to avoid reactive, emotional choices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Communicate architecture in three layers: business impact first, mechanism second, risks and costs third.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Invest in mentorship through Guided Discovery and high-quality code reviews—this is how you multiply your architectural impact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make trade-off reasoning explicit across maintainability, performance, extensibility, and team capability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep a personal decision journal and review it regularly to identify and address your own blind spots.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s Your Experience?
&lt;/h2&gt;

&lt;p&gt;Technical leadership in SAP is a craft that takes years to develop—and it’s still evolving. I’d genuinely like to hear from you: what’s the hardest architectural decision you’ve had to make under pressure in an SAP project, and what did you learn from it? Drop your thoughts in the comments below, or reach out directly. The conversations that happen in the comments section are often as valuable as the article itself.&lt;/p&gt;

&lt;p&gt;If this resonated with you, share it with a colleague who’s stepping into an architect role—it might save them from a few painful lessons I had to learn the hard way.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>SAP MES Integration with PP/QM: Building a Real-Time Production Monitoring Architecture That Actually Works</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Mon, 30 Mar 2026 21:32:44 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-mes-integration-with-ppqm-building-a-real-time-production-monitoring-architecture-that-27f0</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-mes-integration-with-ppqm-building-a-real-time-production-monitoring-architecture-that-27f0</guid>
      <description>&lt;p&gt;If you’ve spent any time in a manufacturing environment, you know the dirty secret nobody talks about in conference rooms: the gap between what the ERP system thinks is happening on the shop floor and what’s &lt;em&gt;actually&lt;/em&gt; happening is often enormous. Orders that are “in process” for three days. Quality defects discovered at final inspection that could have been caught at operation two. Machine downtime that gets logged retroactively—if it gets logged at all.&lt;/p&gt;

&lt;p&gt;This is the problem that &lt;strong&gt;SAP MES integration with PP/QM&lt;/strong&gt; is designed to solve. And after years of designing and delivering these architectures, I can tell you: when it works well, it genuinely transforms manufacturing operations. When it’s done poorly, you end up with a system nobody trusts and a shop floor that goes back to paper.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through the architectural decisions, integration patterns, and real-time monitoring strategies that make the difference between a successful MES-SAP integration and an expensive failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We’re Actually Trying to Solve: The Shop Floor Data Problem
&lt;/h2&gt;

&lt;p&gt;Before we talk architecture, let’s be honest about the problem. Most manufacturing companies have SAP S/4HANA (or ECC) handling their production orders, quality inspection lots, and material movements. What they typically lack is &lt;strong&gt;real-time feedback from the shop floor&lt;/strong&gt;. The MES system—whether that’s a third-party product like Siemens Opcenter, Rockwell Plex, or a custom-built solution—sits in the middle, capturing machine signals, operator inputs, and process data that the ERP was never designed to collect.&lt;/p&gt;

&lt;p&gt;The integration challenge is bidirectional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Downward (SAP → MES)&lt;/strong&gt;: Production orders, routing operations, BOM components, quality inspection plans, and scheduling data need to flow to the shop floor system so operators know what to build and how.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upward (MES → SAP)&lt;/strong&gt;: Confirmations, actual quantities, quality results, scrap declarations, and material consumption need to flow back so the ERP reflects reality.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real-time requirement is what makes this hard. A batch upload once an hour might have been acceptable in 2005. Today, with lean manufacturing targets and customer commitments that require hour-by-hour production visibility, you need confirmations flowing back within seconds or minutes of an event occurring on the floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core SAP Objects You Need to Understand
&lt;/h2&gt;

&lt;p&gt;Before designing any integration, make sure you’re fluent in the SAP side of this equation. Here are the objects that matter most:&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Orders (PP)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AUFK&lt;/strong&gt;: Order header data (status, plant, MRP controller)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AFKO&lt;/strong&gt;: Order header for PP orders (scheduling dates, quantities)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AFPO&lt;/strong&gt;: Order items&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AFVC&lt;/strong&gt;: Operations within the order&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AFVV&lt;/strong&gt;: Quantities and times for operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RESB&lt;/strong&gt;: Reservation/component requirements&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quality Management (QM)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;QMEL&lt;/strong&gt;: Quality notifications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;QALS&lt;/strong&gt;: Inspection lots&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;QASE&lt;/strong&gt;: Inspection characteristics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;QAMR&lt;/strong&gt;: Inspection results (mean values)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;QAMV&lt;/strong&gt;: Inspection results (single values)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these tables isn’t optional. When your MES team tells you “the confirmation isn’t working,” you need to know exactly which BAPI is being called, which fields are required, and which database tables to check for debugging. Ignorance of the underlying data model is where most integrations go wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Patterns: Choosing the Right Approach
&lt;/h2&gt;

&lt;p&gt;I’ve seen three main architectural patterns used for MES-SAP integration. Each has its place, and choosing the wrong one for your context is a mistake you’ll be living with for years.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 1: Direct BAPI/RFC Integration
&lt;/h3&gt;

&lt;p&gt;The oldest and most common approach. The MES calls SAP BAPIs directly via RFC connection. For production confirmations, the primary BAPI is BAPI_PRODORDCONF_CREATE_TT. For goods movements, it’s BAPI_GOODSMVT_CREATE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When it works well&lt;/strong&gt;: Simple, low-volume scenarios with a single MES system and a stable SAP landscape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When it fails&lt;/strong&gt;: Network latency kills you in real-time scenarios. If the MES has to wait for a synchronous RFC response before allowing an operator to proceed, and SAP is having a slow moment, you’ve just created a bottleneck on the production line. I’ve seen this exact scenario halt a production line during a critical period. Not a good day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 2: Message-Based Integration via Middleware
&lt;/h3&gt;

&lt;p&gt;The MES publishes events to a message broker (Apache Kafka, RabbitMQ, or SAP Integration Suite), and an integration layer consumes those messages and pushes them to SAP asynchronously. For the reverse direction, SAP IDocs or change pointers trigger outbound messages.&lt;/p&gt;

&lt;p&gt;This is the pattern I recommend for most modern implementations. The decoupling is essential. The shop floor system doesn’t need to wait for SAP. If SAP is temporarily unavailable, messages queue up and process when connectivity is restored. You get retry logic, dead-letter queues for failed messages, and monitoring out of the box.&lt;/p&gt;

&lt;p&gt;If you’re building event-driven architectures in your SAP landscape, the patterns I discussed in &lt;a href="https://aixsap.com/sap-btp-event-mesh-event-driven-architecture-building-resilient-integrations-that-actually-scale/" rel="noopener noreferrer"&gt;SAP BTP Event Mesh: Building Resilient Integrations That Actually Scale&lt;/a&gt; apply directly here—especially the guidance around guaranteed delivery and consumer group management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern 3: IoT-First with Edge Processing
&lt;/h3&gt;

&lt;p&gt;The most modern approach: machine signals are collected at the edge (using OPC-UA, MQTT, or similar protocols), processed locally to generate business events (“operation completed,” “quality threshold exceeded”), and then those business events are forwarded to both the MES and SAP. The MES becomes a consumer of events rather than the sole source of truth.&lt;/p&gt;

&lt;p&gt;This is the direction the industry is moving, particularly in Industrie 4.0 contexts. It enables real-time anomaly detection without requiring SAP to be in the critical path of machine operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Implementation: Production Order Confirmation Flow
&lt;/h2&gt;

&lt;p&gt;Let me walk through the most common use case: confirming a production order operation from the MES back to SAP. Here’s the ABAP side of that equation—a wrapper function that handles the BAPI call with proper error handling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Wrapper&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MES&lt;/span&gt; &lt;span class="n"&gt;Production&lt;/span&gt; &lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;Confirmation&lt;/span&gt;
&lt;span class="n"&gt;Calls&lt;/span&gt; &lt;span class="n"&gt;BAPI_PRODORDCONF_CREATE_TT&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;proper&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt;
&lt;span class="n"&gt;Prerequisite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Valid&lt;/span&gt; &lt;span class="n"&gt;production&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;exists&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;AUFK&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;operations&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;AFVC&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_mes_prod_confirmation&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;FINAL&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;PUBLIC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;TYPES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ty_conf_result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;success&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;abap_bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;message&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;conf_number&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;rueck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ty_conf_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;confirm_operation&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt;
        &lt;span class="n"&gt;iv_order_number&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;aufnr&lt;/span&gt;
        &lt;span class="n"&gt;iv_operation&lt;/span&gt;    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;vornr&lt;/span&gt;
        &lt;span class="n"&gt;iv_conf_qty&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;menge_d&lt;/span&gt;
        &lt;span class="n"&gt;iv_scrap_qty&lt;/span&gt;    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;menge_d&lt;/span&gt;
        &lt;span class="n"&gt;iv_actual_work&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;ae_arbmng&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Actual&lt;/span&gt; &lt;span class="n"&gt;labor&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;iv_posting_date&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;budat&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt;
        &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;ty_conf_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;build_conf_header&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt;
        &lt;span class="n"&gt;iv_posting_date&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;budat&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt;
        &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs_header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;bapi_bus2105_conf_head_create&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;METHODS&lt;/span&gt; &lt;span class="n"&gt;handle_return_messages&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt;
        &lt;span class="n"&gt;it_return&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;bapiret2_tab&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt;
        &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv_success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;abap_bool&lt;/span&gt;
      &lt;span class="k"&gt;CHANGING&lt;/span&gt;
        &lt;span class="n"&gt;cv_message&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_mes_prod_confirmation&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;confirm_operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;ls_header&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;bapi_bus2105_conf_head_create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lt_timetickets&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;bapi_bus2105_conf_tt_create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;  &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;bapi_bus2105_conf_tt_create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lt_return&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;bapiret2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lv_conf_num&lt;/span&gt;   &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;rueck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;confirmation&lt;/span&gt; &lt;span class="k"&gt;header&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ls_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_conf_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;iv_posting_date&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Populate&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;time&lt;/span&gt; &lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;orderid&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_order_number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;yield&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_conf_qty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;scrap&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_scrap_qty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;work_actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_actual_work&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;work_unit&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Hours&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fin_conf&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_false&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Not&lt;/span&gt; &lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="n"&gt;confirmation&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ls_timeticket&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;postg_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_posting_date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;APPEND&lt;/span&gt; &lt;span class="n"&gt;ls_timeticket&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;lt_timetickets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Call&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;BAPI&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;BAPI_PRODORDCONF_CREATE_TT&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
        &lt;span class="n"&gt;headdata&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_header&lt;/span&gt;
      &lt;span class="k"&gt;TABLES&lt;/span&gt;
        &lt;span class="n"&gt;timetickets&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lt_timetickets&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lt_return&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Handle&lt;/span&gt; &lt;span class="k"&gt;results&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;rs_result&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handle_return_messages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;EXPORTING&lt;/span&gt; &lt;span class="n"&gt;it_return&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lt_return&lt;/span&gt;
      &lt;span class="k"&gt;CHANGING&lt;/span&gt;  &lt;span class="n"&gt;cv_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs_result&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;message&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;rs_result&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Commit&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;work&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;critical&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="n"&gt;often&lt;/span&gt; &lt;span class="n"&gt;missed&lt;/span&gt;&lt;span class="o"&gt;!&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;BAPI_TRANSACTION_COMMIT&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
          &lt;span class="k"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;Wait&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="k"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;ELSE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Roll&lt;/span&gt; &lt;span class="k"&gt;back&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="k"&gt;any&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;BAPI_TRANSACTION_ROLLBACK&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;build_conf_header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rs_header&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;postg_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_posting_date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rs_header&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;conf_text&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;MES&lt;/span&gt; &lt;span class="n"&gt;Automatic&lt;/span&gt; &lt;span class="n"&gt;Confirmation&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Audit&lt;/span&gt; &lt;span class="n"&gt;trail&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;handle_return_messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rv_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="n"&gt;string_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;it_return&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_return&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="n"&gt;ls_return&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="k"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
          &lt;span class="n"&gt;rv_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;abap_false&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
          &lt;span class="k"&gt;APPEND&lt;/span&gt; &lt;span class="p"&gt;|{&lt;/span&gt; &lt;span class="n"&gt;ls_return&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ls_return&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ls_return&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}|&lt;/span&gt;
            &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;lv_errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;W&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
          &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt; &lt;span class="n"&gt;but&lt;/span&gt; &lt;span class="n"&gt;don&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="kt"&gt;t&lt;/span&gt; &lt;span class="k"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="n"&gt;s001&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmesint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;ls_return&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;ENDCASE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;lv_errors&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;INITIAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;cv_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;concat_lines_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_errors&lt;/span&gt; &lt;span class="n"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth highlighting in this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The BAPI_TRANSACTION_COMMIT with wait = abap_true is critical. Without it, the update runs asynchronously and you can’t be certain the data is committed before you respond to the MES. I’ve debugged production issues that boiled down to this missing parameter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Always distinguish between Error/Abort messages and Warnings. Warnings shouldn’t block processing—log them for monitoring but let the transaction proceed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The rollback on error is non-negotiable. Partial confirmations create data integrity nightmares that are very hard to clean up.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quality Inspection Results: Closing the Loop
&lt;/h2&gt;

&lt;p&gt;The QM side of MES integration is often underestimated. Most teams focus on production confirmations and treat quality as an afterthought. This is a mistake.&lt;/p&gt;

&lt;p&gt;When an operator performs an in-process quality check at a workstation, those results need to flow back to SAP’s inspection lot (QALS) and update the inspection characteristics (QASE). The BAPI for recording inspection results is BAPI_INSPOPER_RECORDRESULTS.&lt;/p&gt;

&lt;p&gt;The architectural consideration here is about &lt;strong&gt;usage decision triggering&lt;/strong&gt;. In SAP QM, the usage decision is the formal acceptance or rejection of an inspection lot. In an MES-integrated scenario, you have a choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Let the MES trigger the usage decision automatically based on measurement results vs. tolerances&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Record results in SAP and let the QM team make the usage decision manually in QA11&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a hybrid: auto-approve lots where all results are within tolerance, flag exceptions for manual review&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Option 3 is almost always the right answer. Full automation sounds appealing but removes human judgment from critical quality decisions. Pure manual processes defeat the purpose of integration. The hybrid approach gives you efficiency where it’s safe and human oversight where it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-Time Monitoring: What Good Looks Like
&lt;/h2&gt;

&lt;p&gt;The goal of MES-SAP integration isn’t just data synchronization—it’s operational visibility. Here’s what a mature implementation should provide:&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Performance Indicators to Track
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Confirmation lag&lt;/strong&gt;: Time between operation completion (MES timestamp) and SAP confirmation posting. Target: under 2 minutes for real-time scenarios.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration error rate&lt;/strong&gt;: Percentage of MES messages that fail to process in SAP. Target: below 0.5%.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quality result turnaround&lt;/strong&gt;: Time from inspection completion to usage decision in SAP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Schedule adherence&lt;/strong&gt;: Comparing planned vs. actual operation times using AFVV data.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Building a Custom Monitoring Dashboard
&lt;/h3&gt;

&lt;p&gt;Don’t rely solely on standard SAP transactions for monitoring your integration. Build a custom ABAP CDS view that joins your integration log table with production order data. If you want to go deep on how CDS views can power real-time reporting scenarios like this, the techniques covered in &lt;a href="https://aixsap.com/abap-cds-views-ile-performansli-veri-modelleme-ileri-seviye-mimari-rehberi/" rel="noopener noreferrer"&gt;ABAP CDS Views ile Performanslı Veri Modelleme — İleri Seviye Mimari Rehberi&lt;/a&gt; (advanced CDS modeling) apply directly—particularly parameterized CDS views for time-range filtering.&lt;/p&gt;

&lt;p&gt;Your monitoring view should expose at minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;All orders with confirmations pending beyond your threshold (e.g., operations completed in MES but not yet confirmed in SAP)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failed messages with their error details and retry count&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quality lots awaiting usage decision past SLA&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Failure Modes and How to Avoid Them
&lt;/h2&gt;

&lt;p&gt;Let me share the failure modes I’ve seen most often, so you don’t have to learn them the hard way:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Order Status Not Checked Before Confirmation
&lt;/h3&gt;

&lt;p&gt;Your MES will sometimes try to confirm an operation on an order that’s been technically completed, locked, or deleted in SAP. Always check order status (via STATUS_CHECK function module or JEST/TJ02T tables) before attempting a confirmation. A status check that takes 50ms saves you a failed transaction and a manual correction job.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Timezone Mismatches
&lt;/h3&gt;

&lt;p&gt;MES systems often store timestamps in UTC. SAP production confirmations care about plant-local time for scheduling calculations. A timezone offset error can make your confirmation appear to occur before the order was released—which SAP will reject. Always align on timezone handling during design, not during go-live.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Missing Backflushing Logic
&lt;/h3&gt;

&lt;p&gt;If your routing operations use backflushing for component consumption, SAP will automatically post goods issues when the operation is confirmed. Your integration needs to account for this—don’t double-post goods movements that backflushing will handle automatically. Check the backflushing indicator on the operation (AFVC-MGVRG) before posting separate goods movements.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. No Idempotency Handling
&lt;/h3&gt;

&lt;p&gt;Networks fail. Message brokers retry. Your confirmation BAPI call might get executed twice for the same MES event. Design your integration to handle duplicate messages gracefully—log the MES transaction ID and check for duplicates before calling the BAPI. This is basic, but surprisingly often missed.&lt;/p&gt;

&lt;p&gt;The principles around clean error handling that I’ve referenced in &lt;a href="https://aixsap.com/sap-abap-performance-optimization-identifying-and-fixing-bottlenecks-in-real-world-systems/" rel="noopener noreferrer"&gt;SAP ABAP Performance Optimization&lt;/a&gt; apply to integration code as much as to any other ABAP program—maybe more so, because the error paths are more complex and the consequences of getting them wrong are immediate and visible on the production floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  IoT Layer: Adding Machine Signals to the Picture
&lt;/h2&gt;

&lt;p&gt;The frontier of MES-SAP integration is incorporating machine signal data directly. With OPC-UA becoming the standard industrial communication protocol, you can capture cycle times, temperatures, pressures, and machine states without operator input.&lt;/p&gt;

&lt;p&gt;The architectural principle here is &lt;strong&gt;edge intelligence&lt;/strong&gt;: don’t send every raw machine signal to SAP. Process signals at the edge or in the MES to generate business-relevant events. SAP should receive “Cycle completed—30.2 seconds, within tolerance” not a stream of raw sensor readings.&lt;/p&gt;

&lt;p&gt;When a process parameter exceeds its tolerance, the event triggers three things simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A quality notification in SAP QM (BAPI_QUALNOT_CREATE)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An alert in the MES for the operator&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An entry in your integration monitoring log&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This closed-loop quality approach—where the machine itself triggers a quality response in the ERP—is what Industrie 4.0 looks like in practice. Not just connected machines, but machines that drive business processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Choose your integration pattern deliberately: direct RFC for simple scenarios, message-based for resilience at scale, IoT-first for maximum real-time capability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The BAPI layer works well, but you must handle commits, rollbacks, and status pre-checks explicitly—SAP won’t protect you from a badly formed request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quality integration is as important as production confirmation—design the usage decision workflow early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build monitoring into your architecture from day one, not as an afterthought.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Idempotency, timezone alignment, and backflushing awareness are the details that separate implementations that work from implementations that work &lt;em&gt;in theory&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s Your Biggest MES Integration Challenge?
&lt;/h2&gt;

&lt;p&gt;Every manufacturing environment has its own quirks—custom machine protocols, legacy MES systems that predate modern APIs, organizational dynamics between IT and operations teams. The architecture patterns here give you a foundation, but the real work is always in the details of your specific context.&lt;/p&gt;

&lt;p&gt;I’d genuinely like to hear what you’re working through. Drop a comment below describing your integration scenario—whether you’re evaluating architectures for a new project or debugging an existing one—and let’s work through it together. And if this article gave you a useful framework, share it with a colleague who’s dealing with the same challenges. The shop floor deserves better than manual reconciliation and end-of-shift batch uploads.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>SAP ABAP Performance Optimization: Identifying and Fixing Bottlenecks in Real-World Systems</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Thu, 26 Mar 2026 21:37:05 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-abap-performance-optimization-identifying-and-fixing-bottlenecks-in-real-world-systems-1jld</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-abap-performance-optimization-identifying-and-fixing-bottlenecks-in-real-world-systems-1jld</guid>
      <description>&lt;p&gt;SAP ABAP Performance Optimization: Identifying and Fixing Bottlenecks in Real-World Systems&lt;br&gt;
If you’ve spent any meaningful time in SAP development, you already know the feeling: a report that worked fine in the development system crawls to a halt in production, or a background job that used to finish overnight now runs well into the next business day. &lt;strong&gt;ABAP performance optimization&lt;/strong&gt; isn’t a luxury skill—it’s a core competency for anyone who takes SAP engineering seriously. In this guide, I’ll walk you through a structured, battle-tested approach to diagnosing and resolving performance bottlenecks in ABAP programs, drawing on patterns I’ve encountered across dozens of real-world enterprise deployments.&lt;/p&gt;

&lt;p&gt;We’ll go beyond generic advice. You’ll leave with a repeatable methodology, working code examples, and a mental model for thinking about performance at a system architecture level.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why ABAP Performance Still Matters in the HANA Era
&lt;/h2&gt;

&lt;p&gt;A common misconception I hear from teams moving to S/4HANA is: “HANA is so fast, we don’t need to worry about performance anymore.” That’s dangerously wrong. HANA changes &lt;em&gt;where&lt;/em&gt; your bottleneck lives, but it doesn’t eliminate bottlenecks. You can absolutely write catastrophically slow ABAP on HANA if you’re not thinking architecturally.&lt;/p&gt;

&lt;p&gt;The good news is that many of the principles remain the same. The bad news is that some patterns that were merely suboptimal on classic databases become actively harmful on HANA because they prevent the optimizer from pushing logic down to the database layer. More on that shortly.&lt;/p&gt;

&lt;p&gt;Before we dive into solutions, let’s establish a diagnostic framework. Blindly optimizing without measurement is how you waste two weeks making the wrong thing 10% faster.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Measure Before You Optimize — The SAT and Runtime Analysis Tools
&lt;/h2&gt;

&lt;p&gt;The single most important rule in performance work is: &lt;strong&gt;never guess, always measure&lt;/strong&gt;. SAP provides excellent built-in tooling that most developers underutilize.&lt;/p&gt;
&lt;h3&gt;
  
  
  ABAP Profiler (SAT)
&lt;/h3&gt;

&lt;p&gt;Transaction SAT (the ABAP Trace) is your first stop. It gives you a hierarchical breakdown of where runtime is actually being spent, down to individual statements and method calls. Run it in the environment that exhibits the problem—ideally a production-representative system with realistic data volumes.&lt;/p&gt;

&lt;p&gt;What to look for in SAT output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database time vs. ABAP time ratio&lt;/strong&gt;: If &amp;gt;70% of time is in DB calls, your problem is SQL. If it’s in ABAP processing, look at loops, string operations, and function call overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hit counts&lt;/strong&gt;: A SELECT statement executed 50,000 times inside a loop is a classic N+1 problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self time hotspots&lt;/strong&gt;: Methods with disproportionately high self-time are prime candidates for optimization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  SQL Trace (ST05)
&lt;/h3&gt;

&lt;p&gt;For database-heavy programs, complement SAT with ST05. This shows you the actual SQL being generated, execution times, and critically—whether the database is doing full table scans. If you see a SELECT with no WHERE clause filtering on an indexed column, that’s your smoking gun.&lt;/p&gt;
&lt;h3&gt;
  
  
  HANA-Specific: EXPLAIN PLAN and PlanViz
&lt;/h3&gt;

&lt;p&gt;On S/4HANA systems, open the SAP HANA cockpit or use the SQL console in HANA Studio to run EXPLAIN PLAN on your generated SQL. This reveals whether HANA is using indexes, performing merge joins, or—worst case—spilling to disk.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: The Most Common ABAP Performance Anti-Patterns
&lt;/h2&gt;

&lt;p&gt;After years of reviewing ABAP codebases, certain patterns appear again and again. Let me walk you through the most impactful ones.&lt;/p&gt;
&lt;h3&gt;
  
  
  Anti-Pattern 1: SELECT Inside a LOOP (The N+1 Problem)
&lt;/h3&gt;

&lt;p&gt;This is the number one performance killer in ABAP systems. It looks innocent in small-data scenarios and devastating at scale.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="n"&gt;WRONG&lt;/span&gt; &lt;span class="n"&gt;APPROACH&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="kt"&gt;N&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;anti&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;pattern&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;erdat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;datum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;lt_orders&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;executes&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;EVERY&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;catastrophic&lt;/span&gt; &lt;span class="k"&gt;at&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SINGLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;vbeln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vbeln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;process&lt;/span&gt; &lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix: use a JOIN or a secondary SELECT with FOR ALL ENTRIES — but use FOR ALL ENTRIES carefully. It has its own gotchas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="n"&gt;CORRECT&lt;/span&gt; &lt;span class="n"&gt;APPROACH&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="k"&gt;Single&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;buffered&lt;/span&gt; &lt;span class="k"&gt;secondary&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Option&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;approach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;preferred&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;straightforward&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;vbeln&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;kunnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;posnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;matnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;kwmeng&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;
  &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;vbeln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;vbeln&lt;/span&gt;
  &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_order_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;erdat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;datum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Option&lt;/span&gt; &lt;span class="kt"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;ENTRIES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;impractical&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;CRITICAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Always&lt;/span&gt; &lt;span class="k"&gt;check&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;driving&lt;/span&gt; &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EMPTY&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;before&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;ENTRIES&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="k"&gt;empty&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;fetches&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;lt_orders&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;INITIAL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbap&lt;/span&gt;
    &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;ENTRIES&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lt_orders&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;vbeln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lt_orders&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;vbeln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that FOR ALL ENTRIES cannot be combined with ORDER BY, DISTINCT, or aggregate functions. It also deduplicates the driving table implicitly. Know these constraints cold.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anti-Pattern 2: Unnecessary Data Transfer — SELECT *
&lt;/h3&gt;

&lt;p&gt;Fetching all columns when you need three is wasteful both in network transfer and memory allocation. This becomes particularly problematic on wide tables like BSEG or KONV.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="n"&gt;Fetches&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="k"&gt;columns&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;BSEG&lt;/span&gt; &lt;span class="n"&gt;across&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;bseg&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_bseg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;bukrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;gjahr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;Fetch&lt;/span&gt; &lt;span class="k"&gt;only&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;need&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;bukrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;belnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gjahr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buzei&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hkont&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dmbtr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shkzg&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;bseg&lt;/span&gt;
  &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_bseg_slim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;bukrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;gjahr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On HANA, column-store architecture means this matters even more—the engine only reads the columns you specify from storage, which has real I/O implications at scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anti-Pattern 3: Inefficient Internal Table Operations
&lt;/h3&gt;

&lt;p&gt;Internal table performance is often overlooked, but with large datasets it’s significant. The key principle: use the right table type for the right access pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Table&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;selection&lt;/span&gt; &lt;span class="n"&gt;guide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;STANDARD&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt; &lt;span class="k"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;OK&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;small&lt;/span&gt; &lt;span class="k"&gt;tables&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;sequential&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Use&lt;/span&gt; &lt;span class="k"&gt;SORT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;BINARY&lt;/span&gt; &lt;span class="k"&gt;SEARCH&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;repeated&lt;/span&gt; &lt;span class="n"&gt;keyed&lt;/span&gt; &lt;span class="n"&gt;reads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lt_standard&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;STANDARD&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;SORTED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="kt"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Good&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;heavy&lt;/span&gt; &lt;span class="n"&gt;workloads&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;known&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lt_sorted&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;SORTED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;
  &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;HASHED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;access&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Best&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;large&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt; &lt;span class="k"&gt;tables&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="k"&gt;unique&lt;/span&gt; &lt;span class="k"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lt_hashed&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;HASHED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;
  &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="k"&gt;Common&lt;/span&gt; &lt;span class="n"&gt;mistake&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;READ&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;LINEAR&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;large&lt;/span&gt; &lt;span class="k"&gt;standard&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt;
&lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;lt_large_table&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;READ&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;lt_lookup&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;field1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;n&lt;/span&gt;&lt;span class="err"&gt;²&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="n"&gt;Use&lt;/span&gt; &lt;span class="k"&gt;HASHED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lt_hashed_lookup&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;HASHED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ty_ref&lt;/span&gt;
  &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Populate&lt;/span&gt; &lt;span class="n"&gt;lt_hashed_lookup&lt;/span&gt; &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;lt_large_table&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;READ&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;lt_hashed_lookup&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;field1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;field1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;O&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Anti-Pattern 4: Missing or Misused Indexes
&lt;/h3&gt;

&lt;p&gt;Always verify that your WHERE clause conditions align with existing database indexes. In transaction SE11, you can inspect table technical settings and index definitions. A WHERE clause that doesn’t lead with an indexed column—especially the first field of a composite index—will trigger a full table scan.&lt;/p&gt;

&lt;p&gt;One nuance that bites people on HANA: HANA’s column store handles non-indexed reads better than traditional row-store databases, but this doesn’t mean you should ignore indexes. For high-frequency transactional reads, a well-placed secondary index still makes a dramatic difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Pushing Logic to the Database — Code-to-Data vs. Data-to-Code
&lt;/h2&gt;

&lt;p&gt;This is where HANA-era thinking diverges most sharply from classic ABAP patterns. The guiding principle in modern SAP development is &lt;strong&gt;code-to-data&lt;/strong&gt;: let the database engine do the heavy lifting rather than fetching raw data and processing it in ABAP.&lt;/p&gt;

&lt;p&gt;If you’ve read our article on &lt;a href="https://aixsap.com/abap-cds-views-ile-performansli-veri-modelleme-ileri-seviye-mimari-rehberi/" rel="noopener noreferrer"&gt;ABAP CDS Views for High-Performance Data Modeling&lt;/a&gt;, you already know that CDS views are a central vehicle for this paradigm. Instead of fetching millions of rows and aggregating them in ABAP, push the aggregation into a CDS view or an AMDP (ABAP Managed Database Procedure).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="k"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Fetch&lt;/span&gt; &lt;span class="n"&gt;everything&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aggregate&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ABAP&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbrp&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lt_billing_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;fkdat&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lv_start&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lv_end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lv_total&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="kt"&gt;p&lt;/span&gt; &lt;span class="k"&gt;DECIMALS&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;lt_billing_items&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="n"&gt;lv_total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ls_item&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;netwr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="k"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Let&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;database&lt;/span&gt; &lt;span class="n"&gt;aggregate&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;netwr&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_revenue&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbrp&lt;/span&gt;
  &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_db_total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;fkdat&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lv_start&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lv_end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extend this thinking to GROUP BY, HAVING, subqueries, and window functions (supported in Open SQL on HANA). The database is extraordinarily good at set-based operations. ABAP loops, by contrast, are inherently sequential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Buffering Strategies — When and How to Cache
&lt;/h2&gt;

&lt;p&gt;Not all performance problems are about raw SQL efficiency. Sometimes the answer is to read data less frequently through intelligent buffering.&lt;/p&gt;

&lt;h3&gt;
  
  
  SAP Table Buffering
&lt;/h3&gt;

&lt;p&gt;For configuration and master data tables that are read frequently but change rarely, SAP’s built-in table buffering (configured in SE11 → Technical Settings) can eliminate database roundtrips entirely by serving data from the application server’s shared memory. Suitable candidates: T-code control tables, configuration entries, country/currency tables.&lt;/p&gt;

&lt;p&gt;Be aware of the synchronization lag: buffered tables have a configurable synchronization interval. For transactional data that must be current, buffering is inappropriate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application-Level Caching with Shared Objects
&lt;/h3&gt;

&lt;p&gt;For computed data that’s expensive to derive but reused across multiple requests or users, SAP Shared Objects (transaction SHMA) provides a shared memory area accessible across sessions. This is advanced territory but extremely powerful for lookup-heavy scenarios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Conceptual&lt;/span&gt; &lt;span class="k"&gt;pattern&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;shared&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="n"&gt;caching&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Full&lt;/span&gt; &lt;span class="k"&gt;implementation&lt;/span&gt; &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="k"&gt;area&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;lcl_material_cache&lt;/span&gt; &lt;span class="k"&gt;DEFINITION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PUBLIC&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;CLASS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;get_instance&lt;/span&gt; &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ro_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;lcl_material_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;METHODS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;get_material&lt;/span&gt;
      &lt;span class="k"&gt;IMPORTING&lt;/span&gt; &lt;span class="n"&gt;iv_matnr&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt;
      &lt;span class="k"&gt;RETURNING&lt;/span&gt; &lt;span class="nb"&gt;VALUE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs_material&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt;
      &lt;span class="k"&gt;RAISING&lt;/span&gt; &lt;span class="n"&gt;cx_sy_ref_is_initial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;PRIVATE&lt;/span&gt; &lt;span class="k"&gt;SECTION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mt_cache&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;HASHED&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;lcl_material_cache&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;get_material&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Check&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;memory&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="k"&gt;first&lt;/span&gt;
    &lt;span class="k"&gt;READ&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;mt_cache&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;rs_material&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_matnr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Cache&lt;/span&gt; &lt;span class="n"&gt;miss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;
      &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SINGLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mara&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;rs_material&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;matnr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_matnr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="n"&gt;rs_material&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;mt_cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Parallel Processing for CPU-Bound Workloads
&lt;/h2&gt;

&lt;p&gt;When your bottleneck is pure ABAP processing time rather than database I/O, consider parallel processing using ABAP’s background task framework or CALL FUNCTION ... STARTING NEW TASK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Parallel&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="k"&gt;pattern&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;asynchronous&lt;/span&gt; &lt;span class="n"&gt;RFC&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Partition&lt;/span&gt; &lt;span class="k"&gt;work&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dispatch&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;parallel&lt;/span&gt; &lt;span class="k"&gt;work&lt;/span&gt; &lt;span class="k"&gt;process&lt;/span&gt;

&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lt_partitions&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;ty_partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;lv_task&lt;/span&gt;       &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Build&lt;/span&gt; &lt;span class="n"&gt;partitions&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;workload&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;implementation&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;partition&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;omitted&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;brevity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lv_counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;LOOP&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="n"&gt;lt_partitions&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_partition&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="n"&gt;lv_counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;lv_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;TASK_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;lv_counter&lt;/span&gt; &lt;span class="p"&gt;}|.&lt;/span&gt;

  &lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Z_MY_PARALLEL_WORKER&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;STARTING&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt; &lt;span class="k"&gt;TASK&lt;/span&gt; &lt;span class="n"&gt;lv_task&lt;/span&gt;
    &lt;span class="k"&gt;DESTINATION&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt;
    &lt;span class="k"&gt;PERFORMING&lt;/span&gt; &lt;span class="n"&gt;on_task_complete&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="k"&gt;TASK&lt;/span&gt;
    &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
      &lt;span class="n"&gt;is_partition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_partition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Handle&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="n"&gt;limits&lt;/span&gt; &lt;span class="n"&gt;gracefully&lt;/span&gt;
  &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Fall&lt;/span&gt; &lt;span class="k"&gt;back&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;synchronous&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;partition&lt;/span&gt;
    &lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Z_MY_PARALLEL_WORKER&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;EXPORTING&lt;/span&gt; &lt;span class="n"&gt;is_partition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_partition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDLOOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;Wait&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="k"&gt;tasks&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt;
&lt;span class="k"&gt;WAIT&lt;/span&gt; &lt;span class="k"&gt;UNTIL&lt;/span&gt; &lt;span class="n"&gt;lv_counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;UP&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="k"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A word of caution from experience: parallel processing introduces complexity around error handling and result aggregation. Only reach for it when profiling clearly shows ABAP CPU time as your bottleneck and the work is naturally parallelizable without shared state conflicts. Also check with your basis team about available work process capacity before enabling this in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together: A Performance Review Checklist
&lt;/h2&gt;

&lt;p&gt;When you’re reviewing ABAP code for performance—your own or a colleague’s—run through this checklist systematically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Profile first&lt;/strong&gt;: Use SAT and ST05 to identify the actual bottleneck before touching any code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Eliminate N+1 queries&lt;/strong&gt;: No SELECTs inside loops. Use JOINs or FOR ALL ENTRIES (with the empty-check guard).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Select only needed columns&lt;/strong&gt;: Never use SELECT * on wide tables in production code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Align WHERE clauses with indexes&lt;/strong&gt;: Verify in SE11 that your filter fields have index coverage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Choose the right internal table type&lt;/strong&gt;: HASHED for lookup, SORTED for ranged reads, STANDARD for sequential processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Push logic to the database&lt;/strong&gt;: Aggregations, filters, joins—let the database engine handle these.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consider buffering&lt;/strong&gt;: Stable master/config data should leverage table buffering or application caching.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallelize only when warranted&lt;/strong&gt;: Profile-driven decision, not premature optimization.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This connects closely to the clean code principles I discussed in &lt;a href="https://aixsap.com/abap-clean-code-okunabilir-ve-surdurulebilir-sap-kodu-yazmanin-10-altin-kurali/" rel="noopener noreferrer"&gt;ABAP Clean Code: 10 Golden Rules for Readable and Maintainable SAP Code&lt;/a&gt;—performance and readability aren’t in conflict when you understand both deeply. And if you’re working with modern CDS-based architectures, the data modeling decisions covered in &lt;a href="https://aixsap.com/abap-cds-views-ile-performansli-veri-modelleme-ileri-seviye-mimari-rehberi/" rel="noopener noreferrer"&gt;ABAP CDS Views for High-Performance Data Modeling&lt;/a&gt; directly impact the performance patterns discussed here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Performance optimization in ABAP is a discipline, not a bag of tricks. The developers and architects who consistently deliver fast, scalable SAP solutions aren’t the ones who memorize every optimization hack—they’re the ones who measure rigorously, understand their data access patterns, and choose the right tool for each situation.&lt;/p&gt;

&lt;p&gt;The patterns in this article—eliminating N+1 queries, selecting only needed data, choosing appropriate table types, and embracing the code-to-data paradigm—will address the majority of real-world performance issues you’ll encounter. Start with measurement, fix the biggest bottleneck first, and measure again. That feedback loop is more valuable than any single optimization technique.&lt;/p&gt;

&lt;p&gt;As your systems grow and data volumes increase, revisit these fundamentals regularly. What performs acceptably at 100,000 records can become critically slow at 10 million. Build performance awareness into your code review culture now, and you’ll spend far less time firefighting in production later.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;In a follow-up article, we’ll dive into &lt;strong&gt;ABAP Unit Testing and Test-Driven Development&lt;/strong&gt;—because the discipline of writing testable code is deeply connected to writing performant, maintainable code. A well-structured, decoupled ABAP program is almost always easier to optimize than a tightly coupled monolith.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you encountered a particularly tricky ABAP performance problem in your work?&lt;/strong&gt; Drop it in the comments below. I read every one, and real-world war stories often make the best follow-up content. If this article saved you debugging time, share it with your team—performance awareness is most effective when it’s a team culture, not an individual habit.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>SAP BTP Event Mesh &amp;#038; Event-Driven Architecture: Building Resilient Integrations That Actually Scale</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Thu, 26 Mar 2026 21:36:12 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-btp-event-mesh-038-event-driven-architecture-building-resilient-integrations-that-actually-3ed8</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-btp-event-mesh-038-event-driven-architecture-building-resilient-integrations-that-actually-3ed8</guid>
      <description>&lt;p&gt;If you’ve spent any significant time working on SAP integration projects, you know the pain: point-to-point connections that grow into unmaintainable spaghetti, synchronous calls that create cascading failures, and integration landscapes that buckle under load. I’ve seen enterprise systems brought to their knees not by complex business logic, but by brittle, tightly-coupled integration patterns. That’s exactly why &lt;strong&gt;SAP BTP Event Mesh and event-driven architecture&lt;/strong&gt; deserve serious attention from every architect working in the SAP ecosystem today.&lt;/p&gt;

&lt;p&gt;In this article, I want to go beyond the marketing slides. We’ll look at what event-driven architecture really means in an SAP context, when it genuinely solves your problems, and how to implement it pragmatically using SAP Business Technology Platform’s Event Mesh service. By the end, you’ll have concrete patterns and code you can start applying in your own landscape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Point-to-Point Integration Is Quietly Killing Your Architecture
&lt;/h2&gt;

&lt;p&gt;Let’s be honest about something most consultants won’t say in a kickoff meeting: most SAP integration landscapes are architectural accidents, not architectural decisions. They grew organically—one RFC call here, one IDoc there, a SOAP service added because someone needed it urgently. Before long, you’re maintaining hundreds of direct connections with no clear ownership.&lt;/p&gt;

&lt;p&gt;The fundamental problem is &lt;strong&gt;tight coupling&lt;/strong&gt;. When System A calls System B synchronously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A’s availability depends on B’s availability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A’s performance depends on B’s response time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any change in B’s interface requires coordinated changes in A&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scaling A independently of B is practically impossible&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Event-driven architecture inverts this dependency. Instead of System A &lt;em&gt;calling&lt;/em&gt; System B, System A &lt;em&gt;announces&lt;/em&gt; that something happened. System B (and C, and D) decide independently whether they care about that event. The producer doesn’t know or care about consumers. That’s a fundamentally different—and far more resilient—way to build integrations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Decoupling is not a nice-to-have. In distributed enterprise systems, it’s the difference between a system that recovers from failure gracefully and one that fails completely.”&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding SAP BTP Event Mesh: The Basics You Need
&lt;/h2&gt;

&lt;p&gt;SAP BTP Event Mesh is a fully managed, cloud-based messaging service that acts as the central broker in your event-driven landscape. It’s built on open standards—AMQP 1.0 and MQTT—which means it’s not a proprietary black box you’ll regret in five years.&lt;/p&gt;

&lt;p&gt;Here are the core concepts you need to internalize before designing anything:&lt;/p&gt;

&lt;h3&gt;
  
  
  Topics vs. Queues
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Topics&lt;/strong&gt; support a publish-subscribe model. A producer publishes an event to a topic, and any number of subscribers receive it. This is ideal for broadcasting business events like sap/s4/BusinessPartner/Changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Queues&lt;/strong&gt; support point-to-point or competing consumers. Messages persist until consumed. Use queues when you need guaranteed delivery and exactly-once processing semantics.&lt;/p&gt;

&lt;p&gt;In practice, the most robust pattern combines both: publish events to a topic, then create queue subscriptions that bind to specific topic patterns. This gives you broadcast capability &lt;em&gt;and&lt;/em&gt; guaranteed delivery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event Mesh Namespaces and Topic Naming Conventions
&lt;/h3&gt;

&lt;p&gt;This is where I see architects make costly mistakes early on. Topic names in Event Mesh follow a hierarchical structure, and SAP recommends a specific convention for business events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;namespace&amp;gt;/&amp;lt;source-type&amp;gt;/&amp;lt;source-name&amp;gt;/&amp;lt;event-type&amp;gt;/&amp;lt;version&amp;gt;

# Example:
mycompany/sap/s4hana/BusinessPartner/Created/v1
mycompany/custom/warehouseapp/StockLevel/Updated/v2

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define this naming convention &lt;em&gt;before&lt;/em&gt; you start building. Retrofitting topic names across a live system is genuinely painful—trust me on this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SAP S/4HANA Event-Driven Integration Pattern
&lt;/h2&gt;

&lt;p&gt;SAP S/4HANA natively supports outbound event publishing via its Business Event Handling framework. When a business object changes—a Business Partner is created, a Sales Order is posted—S/4HANA can publish a structured CloudEvent directly to SAP BTP Event Mesh.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring S/4HANA Outbound Bindings
&lt;/h3&gt;

&lt;p&gt;The configuration path in S/4HANA is: &lt;strong&gt;SAP Fiori → Enterprise Event Enablement → Channel Bindings&lt;/strong&gt;. You’ll create a channel pointing to your Event Mesh service instance, then configure topic bindings for specific business events.&lt;/p&gt;

&lt;p&gt;The events S/4HANA publishes conform to the &lt;strong&gt;CloudEvents 1.0 specification&lt;/strong&gt;—an important detail because it means your consumers can be built with any language or framework that understands this open standard.&lt;/p&gt;

&lt;p&gt;A typical CloudEvent payload from S/4HANA looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;specversion&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;type&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;sap.s&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;.beh.businesspartner.v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;.BusinessPartner.Created.v&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;source&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;/default/sap.s&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="err"&gt;.beh/MYCLNT&amp;amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;id&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;a&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="err"&gt;f&lt;/span&gt;&lt;span class="mi"&gt;2e1-4&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;-4&lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="mi"&gt;9e-8&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="mi"&gt;-2&lt;/span&gt;&lt;span class="err"&gt;f&lt;/span&gt;&lt;span class="mi"&gt;5e3&lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="err"&gt;b&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="err"&gt;c&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;d&amp;amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;time&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="mi"&gt;2025-03-25&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;Z&amp;amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;datacontenttype&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;application/json&amp;amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;data&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;BusinessPartner&amp;amp;quot;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="mi"&gt;1000012345&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something important: the payload contains only the &lt;strong&gt;key&lt;/strong&gt; of the changed object, not its full state. This is called the &lt;em&gt;notification event pattern&lt;/em&gt;. The consumer receives a notification that something changed, then queries the source system (via OData API) to retrieve the full, current state. This avoids data consistency issues when events are processed out of order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an Event Consumer: Python Example with SAP BTP
&lt;/h2&gt;

&lt;p&gt;Let’s get practical. Here’s how you’d build a Python-based event consumer that listens to Business Partner creation events and processes them. This would run as a Cloud Foundry application or Kyma workload on SAP BTP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# requirements.txt
# solace-pubsubplus==1.7.0
# requests==2.31.0
# python-dotenv==1.0.0
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;solace.messaging.messaging_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MessagingService&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;solace.messaging.resources.queue&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;solace.messaging.receiver.message_receiver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MessageHandler&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BusinessPartnerEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessageHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Handles&lt;/span&gt; &lt;span class="n"&gt;incoming&lt;/span&gt; &lt;span class="n"&gt;Business&lt;/span&gt; &lt;span class="n"&gt;Partner&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;SAP&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;Mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Implements&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s4_base_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oauth_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s4_base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s4_base_url&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oauth_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oauth_token&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_payload_as_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Received&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;type&amp;amp;#039;)}&amp;amp;quot;)
&lt;/span&gt;
            &lt;span class="c1"&gt;# Extract the Business Partner key from the event
&lt;/span&gt;            &lt;span class="n"&gt;bp_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;data&amp;amp;#039;, {}).get(&amp;amp;#039;BusinessPartner&amp;amp;#039;)
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;bp_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;BusinessPartner&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Skipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="c1"&gt;# Fetch full Business Partner data from S/4HANA OData API
&lt;/span&gt;            &lt;span class="n"&gt;bp_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_fetch_business_partner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bp_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bp_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_process_business_partner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bp_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Failed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Unexpected&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
            &lt;span class="c1"&gt;# In production: implement dead-letter queue logic here
&lt;/span&gt;            &lt;span class="k"&gt;raise&lt;/span&gt;  &lt;span class="c1"&gt;# Re-raise to trigger redelivery
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_fetch_business_partner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bp_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Fetch&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;Business&lt;/span&gt; &lt;span class="n"&gt;Partner&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;HANA&lt;/span&gt; &lt;span class="n"&gt;OData&lt;/span&gt; &lt;span class="n"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;notification-then-fetch&amp;amp;#039; pattern in action.
&lt;/span&gt;        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s4_base_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sap&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opu&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;odata&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sap&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;API_BUSINESS_PARTNER&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nc"&gt;A_BusinessPartner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;{bp_id}&amp;amp;#039;)&amp;amp;quot;
&lt;/span&gt;        &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Bearer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oauth_token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;,&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;d&amp;amp;#039;)
&lt;/span&gt;        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="n"&gt;fetching&lt;/span&gt; &lt;span class="n"&gt;BP&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bp_id&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt; &lt;span class="n"&gt;Will&lt;/span&gt; &lt;span class="n"&gt;retry&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="n"&gt;redelivery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt;  &lt;span class="c1"&gt;# Trigger message redelivery
&lt;/span&gt;        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;BP&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bp_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="n"&gt;may&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;been&lt;/span&gt; &lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Ignoring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_process_business_partner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bp_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Your&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;goes&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Examples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt; &lt;span class="n"&gt;CRM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;MDM&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;bp_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bp_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;BusinessPartner&amp;amp;#039;)
&lt;/span&gt;        &lt;span class="n"&gt;bp_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bp_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;BusinessPartnerFullName&amp;amp;#039;)
&lt;/span&gt;        &lt;span class="n"&gt;bp_category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bp_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="c1"&gt;#039;BusinessPartnerCategory&amp;amp;#039;)
&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Processing&lt;/span&gt; &lt;span class="n"&gt;BP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bp_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bp_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bp_category&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
        &lt;span class="c1"&gt;# TODO: Add your downstream system integration here
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_messaging_service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MessagingService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Creates&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;connects&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;Solace&lt;/span&gt; &lt;span class="n"&gt;messaging&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;Mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;broker_props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;solace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;EVENT_MESH_HOST&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;],&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;solace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vpn&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;EVENT_MESH_VPN&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;],&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;solace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;EVENT_MESH_USER&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;],&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;solace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;EVENT_MESH_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MessagingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;from_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;broker_props&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Starting&lt;/span&gt; &lt;span class="n"&gt;Business&lt;/span&gt; &lt;span class="n"&gt;Partner&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;

    &lt;span class="n"&gt;messaging_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_messaging_service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BusinessPartnerEventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;s4_base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;S4_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;],&lt;/span&gt;
        &lt;span class="n"&gt;oauth_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;S4_OAUTH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;queue_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;EVENT_MESH_QUEUE_NAME&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;]&lt;/span&gt;  &lt;span class="c1"&gt;# e.g., &amp;amp;quot;bp-created-consumer&amp;amp;quot;
&lt;/span&gt;    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;durable_exclusive_queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;messaging_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_persistent_message_receiver_builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;\
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_message_auto_acknowledgement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;\
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Listening&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;queue_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Press&lt;/span&gt; &lt;span class="n"&gt;Ctrl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;Shutting&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt;
        &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;messaging_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth highlighting in this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Re-raise on transient errors&lt;/strong&gt;: Timeout errors cause the exception to propagate, which prevents acknowledgement and triggers redelivery. This is correct behavior for infrastructure failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Swallow 404s&lt;/strong&gt;: If an object was deleted before your consumer processed the creation event (rare but possible), return gracefully rather than crashing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secrets from environment&lt;/strong&gt;: Never hardcode credentials. In BTP Cloud Foundry, these come from service bindings; in Kyma, from Kubernetes secrets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Critical Architectural Decisions You’ll Face
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decision 1: Notification Events vs. Event-Carried State Transfer
&lt;/h3&gt;

&lt;p&gt;I touched on this earlier, but it deserves deeper treatment. You have two options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notification event&lt;/strong&gt;: Publish only the key. Consumer fetches current state on demand. This is SAP’s default pattern and works well when consumers need fresh data and the source system is reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event-Carried State Transfer (ECST)&lt;/strong&gt;: Publish the full state snapshot in the event payload. Consumers process it without calling back. This works better for high-throughput scenarios where you want to minimize API calls, but risks stale data if events are processed out of order.&lt;/p&gt;

&lt;p&gt;My recommendation: start with notification events for SAP-sourced data. Move to ECST only if you have measured performance problems with the fetch-on-demand approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision 2: At-Least-Once vs. Exactly-Once
&lt;/h3&gt;

&lt;p&gt;Event Mesh guarantees &lt;strong&gt;at-least-once delivery&lt;/strong&gt;. This means your consumers &lt;em&gt;must&lt;/em&gt; be idempotent—processing the same event twice should produce the same result as processing it once. Design for this from day one, not as an afterthought.&lt;/p&gt;

&lt;p&gt;A simple idempotency strategy: maintain a processed-events table keyed by CloudEvent id. Check before processing; insert after. This adds latency but prevents duplicate processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision 3: Error Handling and Dead Letter Queues
&lt;/h3&gt;

&lt;p&gt;Define your dead letter queue (DLQ) strategy before going live. In Event Mesh, you configure maximum redelivery attempts on a queue. After those attempts, the message lands in a DLQ. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A monitored DLQ per consumer queue&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alerting when DLQ depth exceeds a threshold&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A replay mechanism for batch reprocessing after fixes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is operational discipline, not just architecture. Skipping it will cost you a late-night incident eventually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Mesh and SAP Integration Suite: How They Fit Together
&lt;/h2&gt;

&lt;p&gt;If you’re working with SAP Integration Suite (formerly Cloud Platform Integration), you can use the AMQP Sender and Receiver adapters to connect integration flows to Event Mesh. This creates a powerful hybrid: event-driven triggering combined with Integration Suite’s rich transformation and orchestration capabilities.&lt;/p&gt;

&lt;p&gt;A common pattern I’ve implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;S/4HANA publishes a Business Partner Changed event to Event Mesh&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An Integration Suite iFlow subscribes to the queue&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The iFlow fetches full data from the S/4HANA OData API, transforms it, and calls a downstream REST API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On failure, Integration Suite’s error handling framework manages retries and alerting&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps your integration logic in Integration Suite (where your team already has tooling and expertise) while gaining the resilience benefits of event-driven triggering. You don’t have to choose one or the other.&lt;/p&gt;

&lt;p&gt;If you’re also exploring how RPA and AI automation integrate with SAP BTP’s broader architecture, you might find the approach we discussed in &lt;a href="https://aixsap.com/sap-btp-ile-akilli-surec-otomasyonu-rpa-ve-ai-entegrasyonunda-mimari-kararlar/" rel="noopener noreferrer"&gt;SAP BTP ile Akıllı Süreç Otomasyonu: RPA ve AI Entegrasyonunda Mimari Kararlar&lt;/a&gt; relevant—many of the same decoupling principles apply when triggering automation from events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Observability: Don’t Skip This
&lt;/h2&gt;

&lt;p&gt;An event-driven system without proper observability is a debugging nightmare. At minimum, implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Distributed tracing&lt;/strong&gt;: Propagate the CloudEvent id as a correlation ID through your entire processing chain. This lets you trace a single business event across multiple services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Queue depth monitoring&lt;/strong&gt;: Sustained queue depth growth means your consumers can’t keep up. Alert on this before it becomes a crisis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consumer lag metrics&lt;/strong&gt;: Track the age of the oldest unprocessed message. Stale messages indicate processing problems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DLQ depth alerting&lt;/strong&gt;: Any message in a DLQ needs investigation. Zero tolerance here.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SAP BTP Event Mesh exposes metrics through SAP Cloud ALM and the BTP Cockpit. Integrate these into your existing monitoring stack, whether that’s Dynatrace, Grafana, or SAP Cloud ALM itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  When NOT to Use Event-Driven Architecture
&lt;/h2&gt;

&lt;p&gt;I’d be doing you a disservice if I only told you about the benefits. Event-driven architecture adds operational complexity. Here’s when it’s &lt;em&gt;not&lt;/em&gt; the right choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You need an immediate response&lt;/strong&gt;: If the user is waiting for a result, synchronous REST is simpler and more appropriate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simple, stable integrations&lt;/strong&gt;: A single integration between two systems that rarely changes doesn’t need the overhead of an event broker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your team lacks operational maturity&lt;/strong&gt;: Running a message broker well requires expertise. Don’t introduce Event Mesh if your team can’t support it properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strict ordering requirements&lt;/strong&gt;: While Event Mesh supports ordering within a partition, complex ordering guarantees add significant architectural complexity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mark of a good architect isn’t using sophisticated patterns everywhere—it’s knowing when simplicity serves you better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Let me distill the most important points from everything we’ve covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event-driven architecture solves tight coupling&lt;/strong&gt;, which is the root cause of most integration fragility in SAP landscapes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SAP BTP Event Mesh&lt;/strong&gt; is a production-grade, standards-based broker that integrates natively with S/4HANA’s event publishing framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use the notification-then-fetch pattern&lt;/strong&gt; for SAP-sourced events to avoid data consistency issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Design consumers to be idempotent from day one&lt;/strong&gt;—at-least-once delivery is guaranteed, so duplicate processing must be harmless.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Invest in observability&lt;/strong&gt; before you go live: distributed tracing, queue monitoring, and DLQ alerting are non-negotiable in production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Choose synchronous patterns when appropriate&lt;/strong&gt;—event-driven is not universally superior, just suited to specific problems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Event-driven architecture is one of those shifts that feels abstract until you’ve lived through a cascading failure caused by synchronous coupling. After that experience, the value of decoupling becomes viscerally clear. Start small—pick one high-value integration, implement it with Event Mesh, and let the operational experience inform your broader strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Your Experience?
&lt;/h2&gt;

&lt;p&gt;Have you implemented event-driven patterns in your SAP landscape? I’d love to hear what challenges you encountered—particularly around idempotency, ordering, and team adoption. Drop your thoughts in the comments below, and if you found this useful, share it with your team. These are the conversations that help our entire community build better systems.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Intelligent Process Automation with SAP BTP: Architectural Decisions in RPA and AI Integration</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Wed, 25 Mar 2026 18:29:34 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-btp-ile-akilli-surec-otomasyonu-rpa-ve-ai-entegrasyonunda-mimari-kararlar-2n1m</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-btp-ile-akilli-surec-otomasyonu-rpa-ve-ai-entegrasyonunda-mimari-kararlar-2n1m</guid>
      <description>&lt;p&gt;Intelligent Process Automation with SAP BTP: Architectural Decisions in RPA and AI Integration&lt;br&gt;
When an anomaly is detected on the production line, the first to notice isn't an employee; it's a real-time AI model. The model immediately signals the SAP PP (Production Planning) module, the relevant work order is automatically revised, and a notification reaches the quality team via Slack—all happening in those few seconds while you sip your coffee. This is no longer a dream; these are real production scenarios where SAP Business Technology Platform (BTP) and intelligent automation tools are brought together with the right architecture.&lt;/p&gt;

&lt;p&gt;In this article, we will examine integration architectures within the SAP BTP ecosystem that utilize RPA (Robotic Process Automation) and Artificial Intelligence components in tandem. We won’t just talk about theory—I will share why certain architectural decisions were made, which trade-offs were accepted, and the lessons I’ve learned from real-world projects.&lt;/p&gt;

&lt;p&gt;Note: This article assumes you have a general familiarity with the SAP integration ecosystem. For those who want to learn about migrating from IDoc to REST/OData services, I recommend reading our guide: Transitioning from IDoc to REST/JSON/OData Services in SAP.&lt;/p&gt;

&lt;p&gt;Why Unmanned Processes Have Become Mandatory&lt;br&gt;
According to a 2023 McKinsey study, 60% to 70% of repetitive tasks in finance and supply chain functions fall within the scope of full automation. Yet, many organizations using SAP still manage a large portion of this potential through manual processes.&lt;/p&gt;

&lt;p&gt;But why? Because "automating" SAP is not easy. The system is multi-layered, the data model is complex, and business rules have grown through thousands of internal customizations. While traditional RPA tools (UiPath, Blue Prism, Automation Anywhere) try to cope with this complexity, they often produce fragile automation scenarios—if the SAP interface changes, the bot crashes.&lt;/p&gt;

&lt;p&gt;This is where SAP BTP comes into play: an API-first, event-driven, and AI-ready platform born from SAP's own ecosystem. However, to use BTP effectively, architectural decisions must be clearly defined.&lt;/p&gt;

&lt;p&gt;Understanding the SAP BTP Intelligent Automation Ecosystem: The Components&lt;br&gt;
The core components we use when building intelligent process automation on BTP are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SAP Build Process Automation (formerly SAP Intelligent RPA)
This is SAP’s native RPA engine. Its most significant advantage over external tools like UiPath is its ability to control SAP GUI and Fiori interfaces via native integration. There is no need for screen scraping; BAPI/RFC calls can be made directly by the bots.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use Cases:&lt;/p&gt;

&lt;p&gt;Invoice verification and GR/IR matching processes.&lt;/p&gt;

&lt;p&gt;Purchase order approval cycles.&lt;/p&gt;

&lt;p&gt;Customer master data cleansing and standardization.&lt;/p&gt;

&lt;p&gt;Periodic report generation and distribution via email.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;SAP Integration Suite (Cloud Integration + API Management)&lt;br&gt;
This is the enterprise integration layer. It manages the message flow between SAP systems and between SAP and third-party systems. In event-driven scenarios, it is used in conjunction with SAP Event Mesh.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SAP AI Core &amp;amp; AI Launchpad&lt;br&gt;
Used to deploy and manage machine learning models within the SAP ecosystem. You can bring your own models (e.g., a scikit-learn model trained for anomaly detection) into production here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SAP HANA Cloud (including Vector Engine)&lt;br&gt;
As of 2024, HANA Cloud comes with vector store support. This allows for RAG (Retrieval-Augmented Generation) scenarios to be run directly on the HANA layer using SAP data, eliminating the need for an external vector database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SAP Joule (GenAI Assistant)&lt;br&gt;
SAP’s built-in generative AI assistant. It works integrated with S/4HANA, SuccessFactors, and Ariba, allowing users to initiate SAP transactions using natural language commands.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Reference Architecture: Event-Driven Intelligent Automation&lt;br&gt;
Let’s look at an anonymized scenario from a manufacturing firm I worked with. The problem: when production orders were completed, manual entry of quality control documents into the SAP QM (Quality Management) module caused delays of 2-3 hours. This delay directly affected the next production step and shipment planning.&lt;/p&gt;

&lt;p&gt;The architecture we designed works as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
[MES System] 
    │ HTTP POST (Quality Data)
    ▼
[SAP Integration Suite - Cloud Integration]
    │ Data Transformation + Validation
    ▼
[SAP Event Mesh] ← Event Published: "QualityDataReceived"
    │
    ├──▶ [AI Core - Anomaly Detection Model]
    │         │ If Anomaly → Alert Event
    │         │ No Anomaly → Approval Signal
    │
    └──▶ [SAP Build Process Automation - Bot]
              │ Call BAPI_INSPOPER_RECORDRESULTS
              ▼
          [SAP QM Module - Automatic Recording]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this architecture, the delay was reduced from 2-3 hours to an average of 4 minutes. More importantly, once the anomaly detection model was live, the quality team could focus 80% of their time on truly problematic batches.&lt;/p&gt;

&lt;p&gt;Architectural Decision Points and Trade-off Analysis&lt;br&gt;
What makes a project difficult isn't just a lack of technical knowledge; it's the ability to see the right trade-offs. Here are the most frequent decision points I encounter:&lt;/p&gt;

&lt;p&gt;Decision 1: SAP Native RPA or External RPA?&lt;br&gt;
SAP Build Process Automation: Native and stable SAP GUI integration. Recommended if processes are predominantly within SAP.&lt;/p&gt;

&lt;p&gt;External (UiPath/Blue Prism): Wider library support for non-SAP systems but can be fragile with screen scraping.&lt;/p&gt;

&lt;p&gt;Recommendation: Use SAP Build for SAP-heavy tasks. Consider a hybrid approach for mixed ecosystems where BTP triggers events and external tools handle legacy endpoints.&lt;/p&gt;

&lt;p&gt;Decision 2: Synchronous or Asynchronous?&lt;br&gt;
RPA bots usually work synchronously (take task, process, finish). In high-volume systems like SAP, this creates bottlenecks.&lt;br&gt;
Asynchronous Event-Driven Architecture (via SAP Event Mesh) provides:&lt;/p&gt;

&lt;p&gt;Resilience: If a bot fails, the event isn't lost; it stays in the queue.&lt;/p&gt;

&lt;p&gt;Scalability: You can dynamically increase bot counts during peak loads.&lt;/p&gt;

&lt;p&gt;Observability: Tracking event flows is easier than digging through synchronous call logs.&lt;/p&gt;

&lt;p&gt;Decision 3: Where Should the AI Model Run?&lt;br&gt;
SAP AI Core: Integrated with the SAP ecosystem, close to HANA data, but management follows the SAP lifecycle.&lt;/p&gt;

&lt;p&gt;External Cloud (Azure ML, AWS SageMaker): More mature MLOps tools but requires extra effort for data synchronization.&lt;/p&gt;

&lt;p&gt;Hybrid Approach: Train models in the external cloud and run inference on SAP AI Core. This allows you to get predictions without moving data outside the ecosystem.&lt;/p&gt;

&lt;p&gt;Practical Code: Triggering Events with SAP Integration Suite&lt;br&gt;
Below is a Groovy script running on SAP Cloud Integration. This script parses incoming quality data and prepares it to be forwarded to SAP Event Mesh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.sap.gateway.ip.core.customdev.util.Message&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;groovy.json.JsonSlurper&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;groovy.json.JsonOutput&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Groovy Script: Quality Data Transformation and Event Preparation
 * Environment: SAP Cloud Integration (CPI)
 */&lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="nf"&gt;processData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;jsonSlurper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JsonSlurper&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonSlurper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Validate mandatory fields&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inspectionLot&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;material&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Missing mandatory fields: inspectionLot, material, or results"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Transform to SAP QM compatible structure (CloudEvents 1.0)&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;eventPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
            &lt;span class="nl"&gt;specversion:&lt;/span&gt; &lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="s2"&gt;"com.company.quality.resultsReceived"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;source:&lt;/span&gt; &lt;span class="s2"&gt;"/mes/qualityControl"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;randomUUID&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="nl"&gt;time:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"yyyy-MM-dd'T'HH:mm:ss'Z'"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;datacontenttype:&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="nl"&gt;inspectionLot:&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inspectionLot&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;material:&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;plant:&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;plant&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="s2"&gt;"1000"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;results:&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="nl"&gt;characteristic:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charac&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;measuredValue:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;uom:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nl"&gt;isWithinSpec:&lt;/span&gt; &lt;span class="n"&gt;isValueWithinSpec&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lowerLimit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;upperLimit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;// Add flag for AI inspection if anomalies are detected&lt;/span&gt;
        &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;hasAnomalies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eventPayload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;any&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isWithinSpec&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;eventPayload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requiresAIInspection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hasAnomalies&lt;/span&gt;

        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JsonOutput&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventPayload&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"X-Quality-HasAnomalies"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hasAnomalies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"X-Processing-Error"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"X-Routing-Target"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"deadLetterQueue"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isValueWithinSpec&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;numValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Double&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;numValue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upper&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;numValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upper&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Critical Design Decisions of This Script&lt;br&gt;
Compliance with CloudEvents Spec: The event payload is formatted according to the CloudEvents 1.0 standard. This ensures seamless compatibility when adding additional event consumers in the future.&lt;/p&gt;

&lt;p&gt;Dead Letter Queue (DLQ) Routing: In case of an error, the message is not lost; it is marked with a specific header and routed to a failure queue. This is critical for tracking and retry mechanisms.&lt;/p&gt;

&lt;p&gt;AI Inspection Flag: If results fall outside of specifications, a flag is added to the event. The AI model does not run unnecessarily for every event; it is triggered only for suspicious cases. This is vital for both cost optimization and reducing latency.&lt;/p&gt;

&lt;p&gt;Observability and Monitoring: Don't Let Automation Run Blind&lt;br&gt;
The biggest risk after taking an automation into production is the "we think it's working, but it's silently failing" scenario. I have painful experience in this area.&lt;/p&gt;

&lt;p&gt;For intelligent process automation, your monitoring layer should encompass the following:&lt;/p&gt;

&lt;p&gt;Process Instance Tracking: Start-to-finish logs for every automation flow—how many steps were completed and where it waited.&lt;/p&gt;

&lt;p&gt;AI Model Drift Monitoring: The prediction accuracy of your model may decrease over time. Periodically monitor model metrics via SAP AI Launchpad.&lt;/p&gt;

&lt;p&gt;Business KPI Integration: Technical logs are not enough. Business metrics like "How many invoices were processed automatically?" or "How much did the average processing time decrease?" should flow into SAP Analytics Cloud.&lt;/p&gt;

&lt;p&gt;Anomaly Alerting: Notifications should be sent via SAP Alert Management or external tools (PagerDuty, OpsGenie) when a bot stops unexpectedly or the error rate exceeds a certain threshold.&lt;/p&gt;

&lt;p&gt;Common Architectural Mistakes&lt;br&gt;
There are recurring mistakes I see in projects where I consult:&lt;/p&gt;

&lt;p&gt;❌ Mistake 1: Overloading the Entire Process onto a Single Bot&lt;br&gt;
Long, monolithic bot flows are both difficult to debug and fragile. Break down each business step into independent, small bot components. If one fails, you shouldn't have to restart the entire process.&lt;/p&gt;

&lt;p&gt;❌ Mistake 2: Going to Production Without a Test Environment&lt;br&gt;
A bot not fully tested in the SAP QAS (Quality Assurance) environment behaves differently in production. Discrepancies in authorization objects and master data inconsistencies often surface here.&lt;/p&gt;

&lt;p&gt;❌ Mistake 3: Managing the AI Model as "Set-and-Forget"&lt;br&gt;
Deploying a model once and forgetting it is a grave error. Production data changes over time, and seasonal patterns emerge. Retrain the model regularly or at least monitor performance metrics.&lt;/p&gt;

&lt;p&gt;❌ Mistake 4: Excluding the Business Unit from the Process&lt;br&gt;
IT designs a great automation, but the business unit hasn't fully explained the process. Result: The automation works technically but fails to meet business rules. Involve process owners from the very beginning, not just during final testing.&lt;/p&gt;

&lt;p&gt;Future Outlook: How GenAI is Transforming SAP Automation&lt;br&gt;
SAP's Joule assistant and Generative AI capabilities on BTP are fundamentally changing the concept of automation. In traditional RPA, you had to hard-code every step. With GenAI:&lt;/p&gt;

&lt;p&gt;The bot can make decisions in ambiguous situations (e.g., if there isn't enough info to approve an invoice, it automatically requests the missing data from the supplier).&lt;/p&gt;

&lt;p&gt;You can define processes using natural language: "Create a purchase suggestion when stock levels fall below the critical threshold and send a summary email to the relevant manager."&lt;/p&gt;

&lt;p&gt;With SAP HANA's Vector Engine, past similar cases are found, and new decisions are made with historical context.&lt;/p&gt;

&lt;p&gt;A word of caution: GenAI-based automation requires much more careful governance than deterministic RPA. There is a risk of the model making wrong decisions that affect transactional data in SAP. Always design a human-in-the-loop approval step and a rollback mechanism for every GenAI-supported bot.&lt;/p&gt;

&lt;p&gt;Conclusion: Architecture First, Tools Second&lt;br&gt;
Building intelligent process automation on SAP BTP is more a matter of architectural discipline than tool selection. Decisions on which service to use where, how to design data flow, and where to position the AI component determine the long-term success of the project.&lt;/p&gt;

&lt;p&gt;To summarize:&lt;/p&gt;

&lt;p&gt;Prefer SAP Build Process Automation for SAP-centric processes.&lt;/p&gt;

&lt;p&gt;Adopt an event-driven architecture for resilient and scalable flows.&lt;/p&gt;

&lt;p&gt;Manage AI models independently in training and inference.&lt;/p&gt;

&lt;p&gt;Don't leave automation blind; build a comprehensive observability culture.&lt;/p&gt;

&lt;p&gt;Prepare your governance framework before integrating GenAI capabilities.&lt;/p&gt;

&lt;p&gt;I also want to remind you of the fundamental importance of clean, sustainable ABAP code in these automation processes. Bot workflows triggered via BAPIs and RFCs directly depend on the quality of the underlying ABAP code. I recommend checking out our article: ABAP Clean Code: 10 Golden Rules for Writing Readable and Sustainable SAP Code.&lt;/p&gt;

&lt;p&gt;What’s Your Experience?&lt;br&gt;
Are you working on RPA or AI integration in an SAP environment? Which architectural decisions did you find most challenging? Share your comments below—discussions arising from real experiences are the most valuable resources in this field.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>SAP ABAP Exception Handling: Clean, Reliable, and Sustainable Error Management</title>
      <dc:creator>Oktay Ates</dc:creator>
      <pubDate>Mon, 23 Mar 2026 21:10:20 +0000</pubDate>
      <link>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-abap-exception-handling-temiz-guvenilir-ve-surdurulebilir-hata-yonetimi-4f7p</link>
      <guid>https://dev.to/oktay_a56a5e9cc26cc1df8fe/sap-abap-exception-handling-temiz-guvenilir-ve-surdurulebilir-hata-yonetimi-4f7p</guid>
      <description>&lt;p&gt;SAP ABAP Exception Handling: Clean, Reliable, and Sustainable Error Management&lt;br&gt;
One of the most critical issues I’ve noticed while working on dozens of SAP projects over the years is this: the vast majority of developers treat error management as an afterthought. They write the code first, add a CATCH block only when things crash, and move on. While this approach might work in the short term, it leads to systems that are impossible to maintain in the long run—systems that hide errors and silently collapse in production environments.&lt;/p&gt;

&lt;p&gt;In this article, we will look at exception handling in ABAP from an architectural perspective. We will progress with real-world, ready-to-use examples, covering everything from classic SY-SUBRC checks to class-based exceptions, custom exception class design, and exception chaining.&lt;/p&gt;

&lt;p&gt;💡 Why you should read this article: Designing error management correctly in ABAP directly impacts both the end-user experience and developer productivity. After reading this, you will evaluate this topic through a different lens in your next code review.&lt;/p&gt;

&lt;p&gt;The Evolution of Error Management in ABAP: From SY-SUBRC to Class-Based Exceptions&lt;br&gt;
When examining the history of ABAP, two distinct error management paradigms emerge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Classic Method: SY-SUBRC and EXCEPTIONS&lt;br&gt;
In legacy ABAP code—especially in Function Modules written before the 2000s—error management was handled as follows:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Classic Method: SY-SUBRC and EXCEPTIONS&lt;br&gt;
In legacy ABAP code—especially in Function Modules written before the 2000s—error management was handled as follows:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Classic&lt;/span&gt; &lt;span class="n"&gt;approach&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;AVOID&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;CALL&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;BAPI_SALESORDER_GETLIST&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
    &lt;span class="n"&gt;customer_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_kunnr&lt;/span&gt;
  &lt;span class="k"&gt;TABLES&lt;/span&gt;
    &lt;span class="n"&gt;sales_orders&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lt_orders&lt;/span&gt;
  &lt;span class="k"&gt;EXCEPTIONS&lt;/span&gt;
    &lt;span class="n"&gt;not_found&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;OTHERS&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
     &lt;span class="c1"&gt;" Customer not found&lt;/span&gt;
     &lt;span class="k"&gt;WRITE&lt;/span&gt; &lt;span class="s1"&gt;'No records found'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ELSEIF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Bilinmeyen&lt;/span&gt; &lt;span class="n"&gt;hata&lt;/span&gt;
  &lt;span class="k"&gt;WRITE&lt;/span&gt; &lt;span class="s1"&gt;'An error occurred'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The core issues with this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Error information is reduced to a &lt;strong&gt;numeric code&lt;/strong&gt;, and the context is lost.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is very easy to skip the check — you might not check &lt;code&gt;sy-subrc&lt;/code&gt; at all.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is impossible to establish an error chain (you cannot express when one exception causes another).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is no stack trace; debugging becomes a nightmare.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Modern Method: Class-Based Exceptions (TRY-CATCH-CLEANUP)
One of the greatest advantages brought by ABAP OOP is the class-based exception mechanism. The basic structure:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="c1"&gt;" Business logic here&lt;/span&gt;
  &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lo_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt; &lt;span class="n"&gt;zcl_sales_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;iv_order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_order_id&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="n"&gt;lo_order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_not_found&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="c1"&gt;" Specific error — give a meaningful message to the customer&lt;/span&gt;
  &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="n"&gt;lx_not_found&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="s1"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_business_error&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_business&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="c1"&gt;" Business rule violation&lt;/span&gt;
  &lt;span class="n"&gt;cl_demo_output&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lx_business&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_longtext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="k"&gt;cx_root&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_unexpected&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="c1"&gt;" Unexpected system error — log and notify the administrator&lt;/span&gt;
  &lt;span class="n"&gt;zcl_error_logger&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;log_exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lx_unexpected&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_system_error&lt;/span&gt;
    &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
      &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx_unexpected&lt;/span&gt;
      &lt;span class="n"&gt;textid&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zcx_system_error&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;unexpected_error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;CLEANUP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="c1"&gt;" Resource cleanup — runs in all cases&lt;/span&gt;
  &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;lo_order&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;BOUND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;lo_order&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pay attention here: The CLEANUP block runs regardless of whether an exception is caught or not. This is the ABAP equivalent of a finally block and is critical for resource cleanup.&lt;/p&gt;

&lt;p&gt;Designing Your Own Exception Classes: Hierarchy and Semantics&lt;br&gt;
One of the most common mistakes is using generic system exceptions like cx_sy_arithmetic_error for all errors or creating a single custom exception class and stuffing everything into it. The correct approach is to build a meaningful hierarchy that reflects your business domain.&lt;/p&gt;

&lt;p&gt;Designing an Exception Class Hierarchy&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
ZCX_BASE_ERROR (Base class for all custom exceptions)
├── ZCX_BUSINESS_ERROR (Business rule violations — displayable to user)
│   ├── ZCX_ORDER_NOT_FOUND
│   ├── ZCX_INVALID_MATERIAL
│   └── ZCX_STOCK_INSUFFICIENT
└── ZCX_TECHNICAL_ERROR (System/technical errors — reported to admin)
    ├── ZCX_DB_CONNECTION_FAILED
    └── ZCX_RFC_CALL_FAILED

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The advantage of this hierarchy: You can perform both specific and generic catches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="c1"&gt;" Specific catch:&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="c1"&gt;" Catching all business errors:&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_business_error&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="c1"&gt;" Catching all your custom errors:&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_base_error&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating an Exception Class in SE24&lt;br&gt;
Create a new class in transaction SE24:&lt;/p&gt;

&lt;p&gt;Class Name: ZCX_ORDER_NOT_FOUND&lt;/p&gt;

&lt;p&gt;Superclass: ZCX_BUSINESS_ERROR (or directly CX_STATIC_CHECK)&lt;/p&gt;

&lt;p&gt;Instantiation: Public&lt;/p&gt;

&lt;p&gt;To add custom message texts to your exception class, define Text IDs in the Texts tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="c1"&gt;" ZCX_ORDER_NOT_FOUND class — In the Constants tab:&lt;/span&gt;
&lt;span class="k"&gt;CONSTANTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;order_not_found&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;sotr_conc&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="s1"&gt;'ZCX_ORDER_NOT_FOUND ORDER_NOT_FOUND'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;order_locked&lt;/span&gt;    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;sotr_conc&lt;/span&gt; &lt;span class="k"&gt;VALUE&lt;/span&gt; &lt;span class="s1"&gt;'ZCX_ORDER_NOT_FOUND ORDER_LOCKED'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="c1"&gt;" Raising an exception:&lt;/span&gt;
&lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt;
  &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
    &lt;span class="n"&gt;textid&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;order_not_found&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lv_order_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="c1"&gt;" Defined as an attribute&lt;/span&gt;

&lt;span class="c1"&gt;" Catching and retrieving the message:&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="n"&gt;lv_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;  &lt;span class="c1"&gt;" Automatically retrieves the message from OTR&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exception Chaining: Preserve the Error Chain&lt;br&gt;
In large systems, one error is usually the result of another. For example: RFC call failed → Order could not be created → Business process stopped. Preserving this chain is a lifesaver during debugging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="c1"&gt;" RFC call&lt;/span&gt;
    &lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;call_remote_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

  &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_rfc_call_failed&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_rfc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="c1"&gt;" Convert technical error to business error, but PRESERVE THE CHAIN&lt;/span&gt;
    &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_order_creation_failed&lt;/span&gt;
      &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
        &lt;span class="n"&gt;textid&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zcx_order_creation_failed&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rfc_error&lt;/span&gt;
        &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx_rfc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="c1"&gt;" &amp;lt;-- This is critical! We are storing the original error&lt;/span&gt;
  &lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To read the chain later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_creation_failed&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="c1"&gt;" Log the full error chain&lt;/span&gt;
  &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;CAST&lt;/span&gt; &lt;span class="n"&gt;cx_root&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lx_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;WHILE&lt;/span&gt; &lt;span class="n"&gt;lx_current&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;BOUND&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;cl_demo_output&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lx_current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="n"&gt;lx_current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx_current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="c1"&gt;" Go to the previous error&lt;/span&gt;
  &lt;span class="k"&gt;ENDWHILE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Checked vs Unchecked Exceptions: When to Choose Which?
&lt;/h2&gt;

&lt;p&gt;ABAP offers three options for exception superclasses, and this choice is significant:&lt;/p&gt;

&lt;p&gt;Superclass&lt;br&gt;
Type&lt;br&gt;
When to Use?&lt;/p&gt;

&lt;p&gt;CX_STATIC_CHECK&lt;br&gt;
Checked&lt;br&gt;
Predictable errors that the calling code must handle. File not found, record does not exist, etc.&lt;/p&gt;

&lt;p&gt;CX_DYNAMIC_CHECK&lt;br&gt;
Semi-checked&lt;br&gt;
Errors that can occur at runtime but do not always require mandatory handling. Parameter validation errors.&lt;/p&gt;

&lt;p&gt;CX_NO_CHECK&lt;br&gt;
Unchecked&lt;br&gt;
System-related errors that cannot be programmatically handled. Memory errors, system crashes, etc.&lt;/p&gt;

&lt;p&gt;Practical Rule: Generally prefer CX_STATIC_CHECK for your own business exceptions. This forces the exception to appear in the method signature and compels the calling code to either handle the exception or propagate it upward. In this way, you prevent exceptions from being ignored at compile time.&lt;/p&gt;

&lt;p&gt;Real-World Scenario: Error Management in Layered Architecture&lt;br&gt;
Typical layers in an SAP application are: Presentation → Application → Business Logic → Data Access. Each layer has a different responsibility regarding error management.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="c1"&gt;""" DATA ACCESS LAYER — Convert technical errors into business errors """&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_repository&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SINGLE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;vbak&lt;/span&gt;
      &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;vbeln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;iv_order_id&lt;/span&gt;
      &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;sy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subrc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt;
        &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
          &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_order_id&lt;/span&gt;
          &lt;span class="n"&gt;textid&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;order_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;rv_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="c1"&gt;""" BUSINESS LOGIC LAYER — Apply business rules """&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_service&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;process_order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mo_repository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;iv_order_id&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

      &lt;span class="c1"&gt;" Business rule check&lt;/span&gt;
      &lt;span class="k"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;netwr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;zcx_invalid_order&lt;/span&gt;
          &lt;span class="k"&gt;EXPORTING&lt;/span&gt;
            &lt;span class="n"&gt;textid&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zcx_invalid_order&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;zero_value_order&lt;/span&gt;
            &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iv_order_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="k"&gt;ENDIF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

      &lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;execute_workflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ls_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_not_found&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="c1"&gt;" This error is already meaningful — propagate upward&lt;/span&gt;
      &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="n"&gt;lx_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="c1"&gt;" Re-raise: preserve the reference&lt;/span&gt;
    &lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="c1"&gt;""" PRESENTATION LAYER — Display appropriate message to the user """&lt;/span&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_order_controller&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;handle_process_request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;mo_service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;process_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;iv_order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p_order&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="s1"&gt;'Order processed successfully.'&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="s1"&gt;'S'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_business_error&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_biz&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="c1"&gt;" Meaningful message for the user, containing no technical details&lt;/span&gt;
      &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="n"&gt;lx_biz&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="s1"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_technical_error&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx_tech&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="c1"&gt;" Log the technical error, give a generic message to the user&lt;/span&gt;
      &lt;span class="n"&gt;zcl_error_logger&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lx_tech&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
      &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="s1"&gt;'A system error occurred. Please contact your administrator.'&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="s1"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu yapının güzelliğine dikkat edin: Her katman &lt;strong&gt;sadece kendi sorumluluğundaki hatayı&lt;/strong&gt; ele alıyor. Data access layer teknik hataları, business layer iş kuralı hatalarını, presentation layer ise kullanıcıya ne gösterileceğini biliyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sık Yapılan Hatalar ve Nasıl Kaçınılır?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ Hata 1: Boş CATCH Bloğu — Exception’ı Yutmak
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;YANLI&lt;/span&gt;&lt;span class="err"&gt;Ş&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;Hata&lt;/span&gt; &lt;span class="n"&gt;sessizce&lt;/span&gt; &lt;span class="n"&gt;kayboluyor&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;mo_service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;risky_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="k"&gt;cx_root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Hi&lt;/span&gt;&lt;span class="err"&gt;ç&lt;/span&gt;&lt;span class="n"&gt;bir&lt;/span&gt; &lt;span class="err"&gt;ş&lt;/span&gt;&lt;span class="n"&gt;ey&lt;/span&gt; &lt;span class="n"&gt;yap&lt;/span&gt;&lt;span class="err"&gt;ı&lt;/span&gt;&lt;span class="n"&gt;lm&lt;/span&gt;&lt;span class="err"&gt;ı&lt;/span&gt;&lt;span class="n"&gt;yor&lt;/span&gt;
&lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="k"&gt;DO&lt;/span&gt;&lt;span class="err"&gt;Ğ&lt;/span&gt;&lt;span class="n"&gt;RU&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;En&lt;/span&gt; &lt;span class="n"&gt;az&lt;/span&gt;&lt;span class="err"&gt;ı&lt;/span&gt;&lt;span class="n"&gt;ndan&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;#&lt;/span&gt;&lt;span class="mi"&gt;039&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="n"&gt;la&lt;/span&gt;
&lt;span class="k"&gt;TRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;mo_service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;risky_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="k"&gt;cx_root&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="n"&gt;zcl_error_logger&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;quot&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Veya&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;RAISE&lt;/span&gt; &lt;span class="k"&gt;EXCEPTION&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDTRY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ Mistake 2: Catching CX_ROOT Everywhere&lt;br&gt;
Catch cx_root only at the highest level (entry point). Target specific exception classes in lower layers. Broad catching hides the wrong errors.&lt;/p&gt;

&lt;p&gt;❌ Mistake 3: Executing Business Logic Within an Exception&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="n"&gt;WRONG&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;handling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;business&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="c1"&gt;" Trying to create a new order here is WRONG&lt;/span&gt;
  &lt;span class="n"&gt;mo_service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create_default_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="c1"&gt;" CORRECT — Handle the error state, manage the business flow elsewhere&lt;/span&gt;
&lt;span class="k"&gt;CATCH&lt;/span&gt; &lt;span class="n"&gt;zcx_order_not_found&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;MESSAGE&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="s1"&gt;'W'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="c1"&gt;" Or perform an appropriate action&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exception Logging: Centralized Error Recording Infrastructure&lt;br&gt;
In production systems, centrally logging exceptions is critical. You can use SAP's standard SLG1 (Application Log) mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight abap"&gt;&lt;code&gt;
&lt;span class="k"&gt;CLASS&lt;/span&gt; &lt;span class="n"&gt;zcl_error_logger&lt;/span&gt; &lt;span class="k"&gt;IMPLEMENTATION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="k"&gt;METHOD&lt;/span&gt; &lt;span class="n"&gt;log_exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lo_log&lt;/span&gt;     &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;if_bali_log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;lo_item&lt;/span&gt;    &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="k"&gt;REF&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;if_bali_item_base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="c1"&gt;" Create Application Log&lt;/span&gt;
    &lt;span class="n"&gt;lo_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cl_bali_log&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create_with_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;iv_object&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ZORDER_PROC'&lt;/span&gt;
      &lt;span class="n"&gt;iv_subobject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ERRORS'&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="c1"&gt;" Add Exception as a log item&lt;/span&gt;
    &lt;span class="n"&gt;lo_item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cl_bali_exception_item&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;ix_exception&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
    &lt;span class="n"&gt;lo_log&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;lo_item&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;

    &lt;span class="c1"&gt;" Save the Log&lt;/span&gt;
    &lt;span class="n"&gt;cl_bali_log_db&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;io_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lo_log&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="k"&gt;ENDMETHOD&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;ENDCLASS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes all errors traceable, filterable, and reportable within the SLG1 transaction.&lt;/p&gt;

&lt;p&gt;Exception Design from a Clean Code Perspective&lt;br&gt;
As emphasized in our article ABAP Clean Code: 10 Golden Rules for Writing Readable and Sustainable SAP Code, where we discuss broader best practices, a good exception design directly impacts code readability. Here are the clean code principles specific to exceptions:&lt;/p&gt;

&lt;p&gt;Make exception class names descriptive: Instead of vague names like ZCX_ORDER_NOT_FOUND or ZCX_DB_ERROR, use names that clearly express intent, such as ZCX_SALES_ORDER_NOT_FOUND_FOR_CUSTOMER.&lt;/p&gt;

&lt;p&gt;Keep exception messages user-friendly: Provide messages that explain what happened and what needs to be done, rather than just a stack trace.&lt;/p&gt;

&lt;p&gt;One exception, one responsibility: Avoid creating generic exceptions that cover too many different scenarios.&lt;/p&gt;

&lt;p&gt;Throw early, catch late: Throw the exception as soon as you detect the error, but leave the catching to the point where it can actually be handled.&lt;/p&gt;

&lt;p&gt;Conclusion: Error Management is a First-Class Citizen&lt;br&gt;
Exception handling is not an afterthought; it is an integral part of software architecture. We learned this over the years through the cost of errors. Let's summarize what we've learned today:&lt;/p&gt;

&lt;p&gt;✅ Switch from classic SY-SUBRC to class-based exceptions—do not delay this.&lt;/p&gt;

&lt;p&gt;✅ Establish a meaningful hierarchy: Separate business errors and technical errors into different branches.&lt;/p&gt;

&lt;p&gt;✅ Preserve the error chain with exception chaining—your debugging time will be cut in half.&lt;/p&gt;

&lt;p&gt;✅ Ensure each layer handles errors within its own responsibility.&lt;/p&gt;

&lt;p&gt;✅ Never use empty CATCH blocks—at the very least, log the error.&lt;/p&gt;

&lt;p&gt;✅ Set up a centralized logging infrastructure—detect production issues quickly.&lt;/p&gt;

&lt;p&gt;As a next step, I recommend reviewing the SY-SUBRC checks in your current code and starting to design a custom exception hierarchy for your most critical business workflows. A small investment now will bring significant ease of maintenance later.&lt;/p&gt;

&lt;p&gt;Also, if you're curious about how to apply OOP design patterns in ABAP, check out our article Design Patterns with ABAP OOP: Real-World Applications of the Strategy Pattern—you will use similar principles in your exception class design.&lt;/p&gt;

&lt;p&gt;How do you organize exception management in your ABAP projects? Which approach has yielded the best results for you? Leave a comment below and share your experiences—also, let me know if you'd like me to prepare a more detailed series on these topics!&lt;/p&gt;

</description>
      <category>sap</category>
      <category>abap</category>
      <category>programming</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
