DEV Community

Cover image for SAP ABAP Exception Handling: Temiz, Güvenilir ve Sürdürülebilir Hata Yönetimi
Oktay Ates
Oktay Ates

Posted on • Originally published at aixsap.com

SAP ABAP Exception Handling: Temiz, Güvenilir ve Sürdürülebilir Hata Yönetimi

SAP ABAP’ta Exception Handling: Temiz, Güvenilir ve Sürdürülebilir Hata Yönetimi
Yıllar içinde onlarca SAP projesinde çalışırken fark ettiğim en kritik sorunlardan biri şu: Geliştiricilerin büyük çoğunluğu hata yönetimine sonradan düşünüyor. Önce kodu yazıyor, işler tıklandığında bir CATCH bloğu ekliyor ve oradan devam ediyor. Bu yaklaşım, kısa vadede işe yarasa da uzun vadede bakımı imkânsız, hatayı gizleyen ve production ortamında sessizce çöken sistemlere yol açıyor.

Bu makalede ABAP’ta exception handling’e mimari bir perspektiften bakacağız. Klasik SY-SUBRC kontrolünden sınıf tabanlı exception’lara, özel exception sınıfı tasarımından hata zincirlerine (exception chaining) kadar gerçek dünyada uygulanabilir, kopya-yapıştır hazır örneklerle ilerleyeceğiz.

💡 Bu makaleyi okumalısınız çünkü: ABAP’ta hata yönetimini doğru tasarlamak, hem son kullanıcı deneyimini hem de geliştirici verimliliğini doğrudan etkiler. Bir sonraki kod incelemenizde bu konuyu farklı gözlerle değerlendireceksiniz.

ABAP’ta Hata Yönetiminin Evrimi: SY-SUBRC’den Class-Based Exceptions’a

ABAP’ın tarihi incelendiğinde iki farklı hata yönetimi paradigması görülür:

1. Klasik Yöntem: SY-SUBRC ve EXCEPTIONS

Eski ABAP kodlarında —özellikle 2000’ler öncesi yazılmış Function Module’lerde— hata yönetimi şu şekilde yapılırdı:


" Klasik yaklaşım  KAÇININ!
CALL FUNCTION 'BAPI_SALESORDER_GETLIST'
  EXPORTING
    customer_number = lv_kunnr
  TABLES
    sales_orders    = lt_orders
  EXCEPTIONS
    not_found       = 1
    OTHERS          = 2.

IF sy-subrc = 1.
  " Müşteri bulunamadı
  WRITE 'Kayıt yok'.
ELSEIF sy-subrc = 2.
  " Bilinmeyen hata
  WRITE 'Bir hata oluştu'.
ENDIF.

Enter fullscreen mode Exit fullscreen mode

Bu yaklaşımın temel sorunları:

  • Hata bilgisi sayısal bir kode indirgeniyor, bağlam kayboluyor

  • Kontrolü atlamak çok kolay — sy-subrc‘yi hiç kontrol etmeyebilirsiniz

  • Hata zinciri kurmak imkânsız (bir exception başka bir exception’ı neden olduğunda bunu ifade edemezsiniz)

  • Stack trace yok, debug etmek kâbus

2. Modern Yöntem: Class-Based Exceptions (TRY-CATCH-CLEANUP)

ABAP OOP’un getirdiği en büyük avantajlardan biri sınıf tabanlı exception mekanizmasıdır. Temel yapı:


TRY.
  " İş mantığı buraya
  DATA(lo_order) = NEW zcl_sales_order( iv_order_id = lv_order_id ).
  lo_order->process( ).

CATCH zcx_order_not_found INTO DATA(lx_not_found).
  " Spesifik hata  müşteriye anlamlı mesaj ver
  MESSAGE lx_not_found->get_text( ) TYPE 'E'.

CATCH zcx_business_error INTO DATA(lx_business).
  " İş kuralı ihlali
  cl_demo_output=>display( lx_business->get_longtext( ) ).

CATCH cx_root INTO DATA(lx_unexpected).
  " Beklenmedik sistem hatası  log'la ve yöneticiye bildir
  zcl_error_logger=>log_exception( lx_unexpected ).
  RAISE EXCEPTION TYPE zcx_system_error
    EXPORTING
      previous = lx_unexpected
      textid   = zcx_system_error=>unexpected_error.

CLEANUP.
  " Kaynak temizliği  her durumda çalışır
  IF lo_order IS BOUND.
    lo_order->rollback( ).
  ENDIF.

ENDTRY.

Enter fullscreen mode Exit fullscreen mode

Burada dikkat edin: CLEANUP bloğu exception yakalanıp yakalanmadığından bağımsız olarak çalışır. Bu, finally bloğunun ABAP karşılığıdır ve kaynak temizliği için kritiktir.

Kendi Exception Sınıflarınızı Tasarlamak: Hiyerarşi ve Semantik

En sık yapılan hatalardan biri, tüm hatalar için cx_sy_arithmetic_error gibi genel sistem exception’larını kullanmak ya da tek bir custom exception sınıfı yaratıp her şeyi oraya tıkmak. Doğru yaklaşım, iş alanınızı yansıtan anlamlı bir hiyerarşi kurmaktır.

Exception Sınıfı Hiyerarşisi Tasarımı


ZCX_BASE_ERROR (Tüm custom exception'ların base class'ı)
├── ZCX_BUSINESS_ERROR (İş kuralı ihlalleri — kullanıcıya gösterilebilir)
│   ├── ZCX_ORDER_NOT_FOUND
│   ├── ZCX_INVALID_MATERIAL
│   └── ZCX_STOCK_INSUFFICIENT
└── ZCX_TECHNICAL_ERROR (Sistem/teknik hatalar — yöneticiye raporlanır)
    ├── ZCX_DB_CONNECTION_FAILED
    └── ZCX_RFC_CALL_FAILED

Enter fullscreen mode Exit fullscreen mode

Bu hiyerarşinin avantajı: Hem spesifik hem de genel yakalama yapabilirsiniz.


" Spesifik yakalama:
CATCH zcx_order_not_found INTO DATA(lx).

" Tüm iş hatalarını yakalama:
CATCH zcx_business_error INTO DATA(lx).

" Tüm custom hatalarınızı yakalama:
CATCH zcx_base_error INTO DATA(lx).

Enter fullscreen mode Exit fullscreen mode

SE24’te Exception Sınıfı Oluşturma

Transaction SE24‘te yeni bir class oluşturun:

  • Class Name: ZCX_ORDER_NOT_FOUND

  • Superclass: ZCX_BUSINESS_ERROR (ya da doğrudan CX_STATIC_CHECK)

  • Instantiation: Public

Exception sınıfınıza özel mesaj metinleri eklemek için Texts sekmesinde Text ID’ler tanımlayın:


" ZCX_ORDER_NOT_FOUND sınıfı  Constants sekmesinde:
CONSTANTS:
  order_not_found TYPE sotr_conc VALUE 'ZCX_ORDER_NOT_FOUND ORDER_NOT_FOUND',
  order_locked    TYPE sotr_conc VALUE 'ZCX_ORDER_NOT_FOUND ORDER_LOCKED'.

Enter fullscreen mode Exit fullscreen mode

Kullanım:


" Exception fırlatma:
RAISE EXCEPTION TYPE zcx_order_not_found
  EXPORTING
    textid   = zcx_order_not_found=>order_not_found
    order_id = lv_order_id.  " Attribute olarak tanımlanmış

" Yakalama ve mesaj alma:
CATCH zcx_order_not_found INTO DATA(lx).
  lv_message = lx->get_text( ).  " OTR'dan mesajı otomatik alır

Enter fullscreen mode Exit fullscreen mode

Exception Chaining: Hata Zincirini Koruyun

Büyük sistemlerde bir hata genellikle başka bir hatanın sonucudur. Örneğin: RFC çağrısı başarısız oldu → Sipariş oluşturulamadı → İş süreci durdu. Bu zinciri korumak, debug sırasında hayat kurtarır.


METHOD create_order.
  TRY.
    " RFC çağrısı
    me->call_remote_system( ).

  CATCH zcx_rfc_call_failed INTO DATA(lx_rfc).
    " Teknik hatayı iş hatasına dönüştür, ama ZINCIRI KORU
    RAISE EXCEPTION TYPE zcx_order_creation_failed
      EXPORTING
        textid   = zcx_order_creation_failed=>rfc_error
        previous = lx_rfc.  &quot; <-- Bu kritik! Orijinal hatayı saklıyoruz
  ENDTRY.
ENDMETHOD.

Enter fullscreen mode Exit fullscreen mode

Daha sonra zinciri okumak için:


CATCH zcx_order_creation_failed INTO DATA(lx_order).
  &quot; Tam hata zincirini log&#039;la
  DATA(lx_current) = CAST cx_root( lx_order ).
  WHILE lx_current IS BOUND.
    cl_demo_output=>display( lx_current->get_text( ) ).
    lx_current = lx_current->previous.  &quot; Bir önceki hataya git
  ENDWHILE.

Enter fullscreen mode Exit fullscreen mode

Checked vs Unchecked Exceptions: Ne Zaman Hangisini Seçmeli?

ABAP’ta exception sınıflarının üç süperclass seçeneği var ve bu seçim önemli:

Superclass
Tür
Ne Zaman Kullanılır?

CX_STATIC_CHECK
Checked
Çağıran kodun mutlaka handle etmesi gereken, öngörülebilir hatalar. Dosya bulunamadı, kayıt yok vb.

CX_DYNAMIC_CHECK
Yarı-checked
Runtime’da oluşabilecek ama her zaman handle edilmesi gerekmeyen hatalar. Parametre doğrulama hataları.

CX_NO_CHECK
Unchecked
Sistem kaynaklı, programatik olarak handle edilemeyen hatalar. Bellek hatası, sistem çöküşü vb.

Pratik kural: Kendi iş exception’larınız için genellikle CX_STATIC_CHECK‘i tercih edin. Bu, method imzasında exception’ın görünmesini zorlar ve çağıran kodu exception’ı handle etmeye ya da yukarı iletmeye mecbur bırakır. Bu sayede exception’ların görmezden gelinmesini derleme zamanında engellersiniz.

Gerçek Dünya Senaryosu: Katmanlı Mimaride Hata Yönetimi

Bir SAP uygulamasında tipik katmanlar şunlardır: Presentation → Application → Business Logic → Data Access. Her katmanın hata yönetiminden farklı sorumluluğu vardır.


&quot;&quot;&quot; DATA ACCESS LAYER  Teknik hataları iş hatalarına dönüştür &quot;&quot;&quot;
CLASS zcl_order_repository IMPLEMENTATION.
  METHOD get_by_id.
    SELECT SINGLE * FROM vbak
      WHERE vbeln = @iv_order_id
      INTO @DATA(ls_order).

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_order_not_found
        EXPORTING
          order_id = iv_order_id
          textid   = zcx_order_not_found=>order_not_found.
    ENDIF.

    rv_order = ls_order.
  ENDMETHOD.
ENDCLASS.

&quot;&quot;&quot; BUSINESS LOGIC LAYER  İş kurallarını uygula &quot;&quot;&quot;
CLASS zcl_order_service IMPLEMENTATION.
  METHOD process_order.
    TRY.
      DATA(ls_order) = mo_repository->get_by_id( iv_order_id ).

      &quot; İş kuralı kontrolü
      IF ls_order-netwr <= 0.
        RAISE EXCEPTION TYPE zcx_invalid_order
          EXPORTING
            textid   = zcx_invalid_order=>zero_value_order
            order_id = iv_order_id.
      ENDIF.

      me->execute_workflow( ls_order ).

    CATCH zcx_order_not_found INTO DATA(lx_not_found).
      &quot; Bu hata zaten anlamlı  yukarı ilet
      RAISE EXCEPTION lx_not_found.  &quot; Re-raise: referansı koru
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

&quot;&quot;&quot; PRESENTATION LAYER  Kullanıcıya uygun mesaj göster &quot;&quot;&quot;
CLASS zcl_order_controller IMPLEMENTATION.
  METHOD handle_process_request.
    TRY.
      mo_service->process_order( iv_order_id = p_order ).
      MESSAGE &#039;Sipariş başarıyla işlendi.&#039; TYPE &#039;S&#039;.

    CATCH zcx_business_error INTO DATA(lx_biz).
      &quot; Kullanıcıya anlamlı, teknik detay içermeyen mesaj
      MESSAGE lx_biz->get_text( ) TYPE &#039;E&#039;.

    CATCH zcx_technical_error INTO DATA(lx_tech).
      &quot; Teknik hatayı log&#039;la, kullanıcıya genel mesaj ver
      zcl_error_logger=>log( lx_tech ).
      MESSAGE &#039;Sistem hatası oluştu. Lütfen yöneticinize başvurun.&#039; TYPE &#039;E&#039;.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

Enter fullscreen mode Exit fullscreen mode

Bu yapının güzelliğine dikkat edin: Her katman sadece kendi sorumluluğundaki hatayı 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.

Sık Yapılan Hatalar ve Nasıl Kaçınılır?

❌ Hata 1: Boş CATCH Bloğu — Exception’ı Yutmak


&quot; YANLIŞ  Hata sessizce kayboluyor!
TRY.
  mo_service->risky_operation( ).
CATCH cx_root.  &quot; Hiçbir şey yapılmıyor
ENDTRY.

&quot; DOĞRU  En azından log&#039;la
TRY.
  mo_service->risky_operation( ).
CATCH cx_root INTO DATA(lx).
  zcl_error_logger=>log( lx ).
  &quot; Veya re-raise et:
  RAISE EXCEPTION lx.
ENDTRY.

Enter fullscreen mode Exit fullscreen mode

❌ Hata 2: Her Yerde CX_ROOT Yakalamak

Yalnızca en üst düzeyde (entry point’te) cx_root yakalayın. Alt katmanlarda spesifik exception sınıflarını hedefleyin. Geniş yakalama, yanlış hataları gizler.

❌ Hata 3: Exception’da Iş Mantığı Yürütmek


&quot; YANLIŞ  CATCH bloğu iş mantığı için değil, hata yönetimi için
CATCH zcx_order_not_found.
  &quot; Yeni sipariş oluşturmaya çalışmak YANLIŞ
  mo_service->create_default_order( ).

&quot; DOĞRU  Hata durumunu ele al, iş akışını başka yerde yönet
CATCH zcx_order_not_found INTO DATA(lx).
  MESSAGE lx->get_text( ) TYPE &#039;W&#039;.
  RETURN.  &quot; Ya da uygun bir işlem yap

Enter fullscreen mode Exit fullscreen mode

Exception Logging: Merkezi Hata Kayıt Altyapısı

Production sistemlerde exception’ların merkezi olarak loglanması kritiktir. SAP’ın standard SLG1 (Application Log) mekanizmasını kullanabilirsiniz:


CLASS zcl_error_logger IMPLEMENTATION.
  METHOD log_exception.
    DATA: lo_log     TYPE REF TO if_bali_log,
          lo_item    TYPE REF TO if_bali_item_base.

    &quot; Application Log oluştur
    lo_log = cl_bali_log=>create_with_header(
      iv_object    = &#039;ZORDER_PROC&#039;
      iv_subobject = &#039;ERRORS&#039; ).

    &quot; Exception&#039 log item olarak ekle
    lo_item = cl_bali_exception_item=>create( ix_exception ).
    lo_log->add_item( lo_item ).

    &quot; Log&#039;u kaydet
    cl_bali_log_db=>save( io_log = lo_log ).
  ENDMETHOD.
ENDCLASS.

Enter fullscreen mode Exit fullscreen mode

Bu şekilde tüm hatalar SLG1 transaction‘ında izlenebilir, filtrelenebilir ve raporlanabilir hale gelir.

Clean Code Perspektifinden Exception Tasarımı

Bu konuda daha kapsamlı best practice’leri ele aldığımız ABAP Clean Code: Okunabilir ve Sürdürülebilir SAP Kodu Yazmanın 10 Altın Kuralı makalemizde de vurgulandığı gibi, iyi bir exception tasarımı kodun okunabilirliğini doğrudan etkiler. İşte exception’lara özgü clean code prensipleri:

  • Exception sınıfı adları konuşkan olsun: ZCX_ORDER_NOT_FOUND, ZCX_DB_ERROR gibi değil; ZCX_SALES_ORDER_NOT_FOUND_FOR_CUSTOMER gibi niyeti net ifade etsin

  • Exception mesajları kullanıcı dostu olsun: Stack trace değil, ne olduğunu ve ne yapılması gerektiğini açıklayan mesajlar

  • Bir exception, bir sorumluluk: Çok fazla farklı durumu kapsayan genel exception’lar yaratmaktan kaçının

  • Erken fırlat, geç yakala: Hatayı tespit ettiğiniz yerde hemen fırlatın, yakalamayı ise handle edebileceğiniz yere bırakın

Sonuç: Hata Yönetimi Bir Birinci Sınıf Vatandaştır

Exception handling, sonradan eklenen bir detay değil; yazılım mimarisinin ayrılmaz bir parçasıdır. Bunu yıllarca hata bedeliyle öğrendik. Bugün öğrendiklerimizi özetleyelim:

  • Klasik SY-SUBRC’den class-based exception’lara geçin — bunu ertelemeyin

  • Anlamlı bir hiyerarşi kurun: iş hataları ve teknik hatalar ayrı dallar

  • Exception chaining ile hata zincirini koruyun — debug süreleriniz yarı yarıya azalacak

  • Her katmanın kendi sorumluluğundaki hataları handle etmesini sağlayın

  • Boş CATCH bloğu asla — en azından logla

  • Merkezi logging altyapısı kur — production sorunlarını hızlıca tespit et

Bir sonraki adım olarak mevcut kodlarınızdaki SY-SUBRC kontrollerini gözden geçirmenizi ve en kritik iş akışları için özel exception hiyerarşinizi tasarlamaya başlamanızı öneririm. Küçük bir yatırım, büyük bir bakım kolaylığı getirecektir.

Ayrıca OOP tasarım desenlerini ABAP’ta nasıl uygulayabileceğinizi merak ediyorsanız, ABAP OOP ile Tasarım Desenleri: Strategy Pattern Gerçek Dünya Uygulamaları makalemize göz atın — exception sınıfı tasarımınızda da benzer prensipleri kullanacaksınız.

Siz ABAP projelerinizde exception yönetimini nasıl organize ediyorsunuz? Hangi yaklaşım sizin için en iyi sonucu verdi? Aşağıya yorum bırakın, deneyimlerinizi paylaşın — bu konular hakkında daha detaylı bir yazı dizisi hazırlamamı istiyorsanız da belirtin.

Top comments (0)