Nasıl Kullanılır
Genel Bakış
Bu kılavuz, Robert C. Martin'in Clean Code kitabının ABAP diline uyarlanmasıdır. Kod kalitesini artırmak isteyen her ABAP geliştiricisi için vazgeçilmez bir kaynaktır. Aşağıda bu kılavuzu nasıl kullanacağınızı, legacy kodu nasıl refactor edeceğinizi ve otomatik kontrolleri nasıl yapacağınızı bulabilirsiniz.
1.1 Clean Code'a Nasıl Başlanır Orijinal Kaynak
Clean Code'a yeni başlıyorsanız, önce Robert C. Martin'in Clean Code kitabını okumanızı tavsiye ederiz. Clean Code Developer girişimi konuya aşamalı ve didaktik bir giriş yapmanıza yardımcı olabilir.
Boolean'lar, Koşullar ve If İfadeleri gibi kolayca anlaşılan ve genel kabul gören konularla başlamanızı öneririz. En fazla faydayı Metodlar bölümünden göreceksiniz; özellikle "Bir şey yap, iyi yap, sadece onu yap" ve "Metodları küçük tut" kuralları kodunuzun genel yapısını büyük ölçüde iyileştirir.
Yorumlar, İsimler ve Biçimlendirme gibi daha tartışmalı konulara sonradan geçin; bu konular neredeyse dini tartışmalara yol açabilir ve yalnızca Clean Code'un olumlu etkilerini zaten görmüş ekipler tarafından ele alınmalıdır.
Uzman Yorumu: Başlangıç için en iyi yol, küçük adımlarla ilerlemektir. Her sprint'te bir ya da iki kural seçin ve ekibinizle birlikte o kurallara odaklanın. Bütün kuralları aynı anda uygulamaya çalışmak bunaltıcı olabilir.
1.2 Legacy Kod Nasıl Refactor Edilir Orijinal Kaynak
Boolean'lar, Koşullar, If İfadeleri ve Metodlar bölümleri, çok fazla kodu değiştirmeden ya da değiştirmek istemediğiniz durumlarda bile yeni koda uygulanabildiği için legacy projelerinde en ödüllendirici olanlardır.
İsimler bölümü, eski ve yeni kod arasında bir uçurum oluşturabileceği için legacy projelerde çok zorlu olabilir. Kodlama öneklerinden kaçınma gibi bazı kurallar, legacy projelerde görmezden gelinmesi daha doğru olabilir.
Refactoring sırasında aynı geliştirme nesnesi içinde farklı geliştirme stillerini karıştırmamaya özen gösterin. Eğer legacy kod yalnızca ön bildirimler içeriyorsa ve inline bildirimlere tam geçiş yapılabilir değilse, iki stili karıştırmak yerine legacy stile bağlı kalmak daha iyi olabilir.
💡 Uzman Yorumu: Legacy kodu refactor ederken "boy haritası" yaklaşımını benimseyin: önce testleri yazın, sonra refactor edin. Bu sayede değişikliklerinizin mevcut davranışı bozmadığından emin olursunuz.
1.3 Otomatik Nasıl Kontrol Edilir Orijinal Kaynak
SAP'nin ABAP Test Cockpit (ATC) bu kılavuzdaki kuralların büyük çoğunluğunu otomatik olarak kontrol edebilir. Clean Code kısıtlamalarını CI/CD pipeline'larınıza entegre etmek için bu araca başvurun. Code Inspector ve ATC araçlarını kullanarak otomatik kalite güvencesi sağlayabilirsiniz.
💡 Uzman Yorumu: ATC kontrollerini CI/CD pipeline'ınıza entegre edin ve her commit öncesinde otomatik kontrol yapın. Bu, kalite sorunlarını üretim ortamına ulaşmadan yakalamanın en etkili yoludur.
1.4 Diğer Kılavuzlarla İlişki Orijinal Kaynak
Bu kılavuz, Robert C. Martin'in Clean Code'unu ABAP'a uyarlamasıdır ve ABAP Programlama Kılavuzu ile uyumludur. Bazı durumlarda bu kılavuz, resmi SAP kılavuzundan farklı öneriler sunabilir; bu durumlarda bu kılavuzda gerekçeler açıklanmaktadır. Ekibinizin tercihine bağlı olarak hangi kılavuzun öncelikli olduğuna karar verebilirsiniz.
💡 Uzman Yorumu: Birden fazla kılavuz kullanıyorsanız, hangisinin öncelikli olduğunu ekip içinde belirleyin ve bu kararı dokümante edin. Tutarsızlık, kılavuzların hiç olmamasından daha kötüdür.
1.5 Nasıl İtiraz Edilir Orijinal Kaynak
Bu kılavuzdaki bazı önerilere katılmayabilirsiniz. Katılmıyorsanız, alternatif bir yaklaşım önerirken gerekçenizi açıklayın. SAP, bu kılavuzun topluluktan gelen önerilerle sürekli geliştiğini belirtmektedir. GitHub üzerinden issue açarak veya pull request göndererek katkıda bulunabilirsiniz.
💡 Uzman Yorumu: Eleştiri, gelişimin anahtarıdır. Bir kuralla aynı fikirde değilseniz, ekibinizle açık bir tartışma yapın. Sonunda takım olarak bir karara varın ve o karara bağlı kalın.
2. İsimlendirmeler
2.1 Açıklayıcı İsimler Kullanın Orijinal Kaynak
İsimler, nesnenin ne olduğunu veya metodun ne yaptığını yansıtmalıdır. İsmin uzunluğundan çekinmeyin; okunabilirlik her şeyden önce gelir.
✓ İYİ KULLANIM
DATA(days_to_delivery) = calculate_delivery_date( order_key ).
METHODS read_customizing_entries
IMPORTING
customizing_id TYPE /clean/cust_id.
CLASS /clean/account_balance_calculator DEFINITION.
✗ KÖTÜ KULLANIM
DATA(d) = calc( k ).
METHODS read
IMPORTING
id TYPE /dirty/id.
CLASS /dirty/abc DEFINITION.
💡 Uzman Yorumu: "Eğer bir ismi açıklamak için yorum yazmanız gerekiyorsa, isim yeterince açıklayıcı değildir." Geliştirme ortamındaki otomatik tamamlama özelliği uzun isimler yazmanızı kolaylaştırır, bu nedenle kısalıktan yana olmaya gerek yoktur.
2.2 Çözüm ve Problem Alanı Terimlerini Tercih Edin Orijinal Kaynak
Yazılım biliminin yerleşik terminolojisini (çözüm alanı terimleri) ve iş alanının terminolojisini (problem alanı terimleri) kullanın. Kendi icat ettiğiniz terimlerden kaçının.
✓ İYİ KULLANIM
CLASS /clean/iterator DEFINITION. " çözüm alanı terimi
DATA delivery_note TYPE /clean/deliv. " problem alanı terimi
✗ KÖTÜ KULLANIM
CLASS /dirty/my_helper DEFINITION. " ne demek isteniyor?
DATA my_stuff TYPE /dirty/stuff. " hangi iş kavramına karşılık geliyor?
💡 Uzman Yorumu: Takım olarak hem teknik hem de iş terminolojisini birleştiren bir sözlük oluşturun. Bu, yeni ekip üyelerinin hızla uyum sağlamasına yardımcı olur.
2.3 Çoğul Kullanın Orijinal Kaynak
Koleksiyonları çoğul isimlerle adlandırın. Bu, bir değişkenin bir koleksiyon mu yoksa tek bir öğe mi içerdiğini hemen anlaşılır kılar.
✓ İYİ KULLANIM
DATA orders TYPE STANDARD TABLE OF order_type.
DATA messages TYPE STANDARD TABLE OF message_type.
LOOP AT orders INTO DATA(order).
✗ KÖTÜ KULLANIM
DATA order TYPE STANDARD TABLE OF order_type. " tekil ama tablo
DATA message_list TYPE STANDARD TABLE OF message_type. " gereksiz sonek
💡 Uzman Yorumu: Tablo değişkenlerini tekil formda adlandırmak yaygın bir hatadır. Döngü içinde tablo satırı için tekil, tablonun kendisi için çoğul kullanın.
2.4 Telaffuz Edilebilir İsimler Kullanın Orijinal Kaynak
Kod incelemeleri veya tartışmalar sırasında yüksek sesle okuyabileceğiniz isimler kullanın. Telaffuz edilemeyen isimler iletişimi zorlaştırır.
✓ İYİ KULLANIM
DATA class_name TYPE seoclsname.
DATA order_quantity TYPE i.
✗ KÖTÜ KULLANIM
DATA cls_nm TYPE seoclsname. " "cls nm" diye mi okunuyor?
DATA ord_qty TYPE i. " kısaltmalar iletişimi zorlaştırır
💡 Uzman Yorumu: Kod incelemesi sırasında ismi yüksek sesle okuyun. Eğer kendinizi harfleri tek tek heceliyorken buluyorsanız, ismi değiştirmeniz gerekiyor demektir.
2.5 snake_case Kullanın Orijinal Kaynak
Değişkenler ve metodlar için alt çizgi ile ayrılmış küçük harf kullanın (snake_case). ABAP büyük/küçük harf duyarsız olduğundan sınıf ve metod adlarında küçük harf tercih edilir.
✓ İYİ KULLANIM
DATA customer_name TYPE string.
METHODS read_customer_data.
CLASS /clean/customer_validator DEFINITION.
✗ KÖTÜ KULLANIM
DATA CustomerName TYPE string. " CamelCase ABAP'a uygun değil
METHODS ReadCustomerData. " ABAP geleneklerine aykırı
💡 Uzman Yorumu: ABAP topluluğu snake_case konusunda genel bir uzlaşıya varmıştır. Bu konvansiyona uymak, kodunuzun diğer ABAP geliştiricilerine tanıdık gelmesini sağlar.
2.6 Kısaltmalardan Kaçının Orijinal Kaynak
Kısaltmalar, okuyucunun bunların ne anlama geldiğini bilmesini gerektirir. Tam isimler kullanmayı tercih edin.
✓ İYİ KULLANIM
DATA company_code TYPE bukrs.
DATA business_partner_number TYPE bu_partner.
METHODS calculate_delivery_date.
✗ KÖTÜ KULLANIM
DATA ccode TYPE bukrs. " "ccode" ne demek? company code mu?
DATA bpnum TYPE bu_partner.
METHODS calc_del_dt. " kısaltmalar anlamı gizler
💡 Uzman Yorumu: "Kısaltma kullanmak kodunuzu kısa yazmayı kolaylaştırır ama okumayı zorlaştırır." Kod çok daha fazla okunur, bu nedenle okuma kolaylığı yazma kolaylığından önce gelir.
2.7 Her Yerde Aynı Kısaltmayı Kullanın Orijinal Kaynak
Kısaltma kullanmak zorundaysanız, ilgili kavram için her yerde aynı kısaltmayı kullanın. Bu, arama yapılabilirliği artırır ve kodu tahmin edilebilir kılar.
✓ İYİ KULLANIM
" "detection object type" her zaman "dobjt" olarak kısaltılır
DATA dobjt TYPE /clean/detection_object_type.
METHODS get_dobjt RETURNING VALUE(result) TYPE /clean/detection_object_type.
✗ KÖTÜ KULLANIM
" aynı kavram için farklı kısaltmalar
DATA dot TYPE /dirty/detection_object_type.
DATA dotype TYPE /dirty/detection_object_type.
DATA detobjtype TYPE /dirty/detection_object_type.
💡 Uzman Yorumu: Kısaltma sözlüğü oluşturun ve ekiple paylaşın. Bu, tutarsız kısaltmaların önüne geçer ve kodu aranabilir kılar.
2.8 Sınıflar için İsim, Metodlar için Fiil Kullanın Orijinal Kaynak
Sınıflar ve arayüzler isimler veya isim öbekleriyle, metodlar ise fiiller veya fiil öbekleriyle adlandırılmalıdır. Boolean metodları "is_" veya "has_" ile başlatmak akıcı bir okunuş sağlar.
✓ İYİ KULLANIM
" Sınıflar - isimler
CLASS /clean/account DEFINITION.
CLASS /clean/user_preferences DEFINITION.
INTERFACE /clean/customizing_reader.
" Metodlar - fiiller
METHODS withdraw.
METHODS add_message.
METHODS read_entries.
" Boolean metodlar
IF is_empty( table ).
IF has_entries( orders ).
✗ KÖTÜ KULLANIM
CLASS /dirty/do_calculation DEFINITION. " sınıf ama fiil
METHODS account. " metod ama isim
💡 Uzman Yorumu: Bu kural İngilizce dil bilgisini taklit eder: sınıflar "nesne", metodlar ise "eylem"dir. Bu ayrım kodu okurken akış hissini artırır.
2.9 Gürültü Kelimelerden Kaçının Orijinal Kaynak
"data", "info", "object" gibi anlamsız ek sözcükleri atın ya da gerçekten değer katan özel bir isimle değiştirin.
✓ İYİ KULLANIM
account " account_data yerine
alert " alert_object yerine
user_preferences " user_info yerine
response_time_seconds " response_time_variable yerine
✗ KÖTÜ KULLANIM
account_data " "data" gereksiz - zaten account bir veridir
alert_object " "object" gereksiz - zaten nesne yönelimli kodda nesne
user_info " "info" belirsiz - hangi bilgiler?
💡 Uzman Yorumu: "data", "info", "object", "manager", "handler" gibi sözcükler genellikle hiçbir anlam taşımaz. Bu sözcükleri isimden çıkardığınızda anlam değişmiyorsa, gereksizler demektir.
2.10 Kavram Başına Bir Kelime Seçin Orijinal Kaynak
Bir kavram için bir terim seçin ve her yerde onu kullanın. Eş anlamlıları karıştırmak okuyucuyu aradaki farkı bulmaya çalışırken zaman kaybettirir.
✓ İYİ KULLANIM
METHODS read_this.
METHODS read_that.
METHODS read_those.
✗ KÖTÜ KULLANIM
METHODS read_this.
METHODS retrieve_that. " read ile retrieve arasındaki fark nedir?
METHODS query_those. " query neden farklı kullanılıyor?
💡 Uzman Yorumu: Eş anlamlılar okuyucuyu yanıltır. "Retrieve" ve "read" farklı terimler kullanılıyorsa okuyucu aralarında anlamlı bir fark olduğunu varsayar. Bu gereksiz bilişsel yük yaratır.
2.11 Pattern İsimlerini Sadece Gerçekten Kullanıyorsanız Kullanın Orijinal Kaynak
Tasarım deseni isimlerini (Factory, Singleton, Facade, Composite, Decorator, Iterator, Observer, Strategy) yalnızca gerçekten o deseni uyguluyorsanız kullanın.
✓ İYİ KULLANIM
" Gerçekten Factory deseni uygulayan bir sınıf
CLASS /clean/customer_factory DEFINITION.
CLASS-METHODS create_by_id
IMPORTING customer_id TYPE kunnr
RETURNING VALUE(result) TYPE REF TO /clean/customer.
ENDCLASS.
✗ KÖTÜ KULLANIM
" Factory deseni uygulamıyor ama ismi öyle
CLASS /dirty/file_factory DEFINITION.
" Aslında sadece bir dosya okuyucusu
METHODS read_file.
ENDCLASS.
💡 Uzman Yorumu: Tasarım deseni isimleri okuyucuya güçlü beklentiler yaratır. Bu beklentileri karşılamayan bir isim, okuyucuyu derinden yanıltır ve kodu anlamayı zorlaştırır.
2.12 Kodlamalardan Kaçının Orijinal Kaynak
Tüm kodlama öneklerini (Macar notasyonu gibi) kaldırmanızı teşvik ediyoruz. Modern IDE'ler tür bilgisini görsel olarak gösterdiğinden bu önekler artık gereksizdir.
✓ İYİ KULLANIM
METHOD add_two_numbers.
result = a + b.
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD add_two_numbers.
rv_result = iv_a + iv_b. " iv_ = importing value, rv_ = returning value - gereksiz
ENDMETHOD.
💡 Uzman Yorumu: Macar notasyonu, IDE'lerin tür bilgisi gösteremediği dönemden kalmadır. Modern ABAP geliştirme araçları bu bilgiyi zaten gösteriyor; bu nedenle önekler yalnızca gürültü ekler.
2.13 Yerleşik Fonksiyonları Gölgelemeyin Orijinal Kaynak
Yerleşik ABAP fonksiyonlarıyla aynı isimde metodlar tanımlamayın. Bu durum, metodların yerleşik fonksiyonların önüne geçmesine ve beklenmedik davranışlara yol açar.
✗ KÖTÜ KULLANIM - Yerleşik fonksiyonları gölgeleyen metodlar
METHODS lines RETURNING VALUE(result) TYPE i. " lines() yerleşik fonksiyon
METHODS line_exists RETURNING VALUE(result) TYPE i. " line_exists() yerleşik fonksiyon
CLASS-METHODS condense RETURNING VALUE(result) TYPE i.
CLASS-METHODS strlen RETURNING VALUE(result) TYPE i.
💡 Uzman Yorumu: condense(), lines(), line_exists(), strlen() gibi yerleşik fonksiyonlar ABAP'ta çok kullanılır. Bunlarla aynı isimde metodlar tanımlamak ciddi kafa karışıklığına yol açar.
3. Dil
3.1 Legacy'i Göz Önünde Bulundurun Orijinal Kaynak
Daha eski ABAP sürümleri için kod yazıyorsanız, bu kılavuzdaki tavsiyeleri dikkatle uygulayın. Birçok öneri, eski ABAP sürümlerinde desteklenmeyen nispeten yeni sözdizimi ve yapıları kullanmaktadır. Desteklemeniz gereken en eski sürümde takip etmek istediğiniz kuralları doğrulayın.
💡 Uzman Yorumu: Clean Code'u bir bütün olarak reddetmeyin. Kuralların büyük çoğunluğu (isimlendirme, yorumlama gibi) her ABAP sürümünde çalışır. Yalnızca yeni sözdizimi gerektiren kuralları sürüm uyumluluğuna göre filtreleyin.
3.2 Performansı Göz Önünde Bulundurun Orijinal Kaynak
Yüksek performanslı bileşenler yazıyorsanız bu kılavuzdaki tavsiyeleri dikkatle değerlendirin. Clean Code bazı şeyleri daha yavaş yapabilir (daha fazla metod çağrısı) veya daha fazla bellek tüketebilir.
Ancak belirsiz korkulara dayalı erken optimizasyon yapmamanızı şiddetle tavsiye ederiz. Tipik bir uygulamada çalışma süresinin büyük çoğunluğu kodun çok küçük bir bölümünde harcanır. Önce temiz, nesne yönelimli bir şekilde inşa edin, sonra bir performans ölçümü yapın. Yalnızca o zaman seçili kuralları atmak için gerçeğe dayalı bir karar alın.
💡 Uzman Yorumu: ABAP'ta çalışma süresinin büyük kısmı genellikle veritabanı işlemlerine harcanır. Metod çağrı maliyetleri nadiren darboğaz oluşturur. Profiler kullanmadan performans optimizasyonu yapmaya çalışmak kaynak israfıdır.
3.3 Nesne Yönelimini Tercih Edin Orijinal Kaynak
Nesne yönelimli programlar (sınıflar, arayüzler) prosedürel koda (fonksiyonlar, programlar) kıyasla daha iyi segmentlere ayrılır ve daha kolay refactor edilip test edilebilir.
✓ İYİ KULLANIM
FUNCTION check_business_partner [...].
DATA(validator) = NEW /clean/biz_partner_validator( ).
result = validator->validate( business_partners ).
ENDFUNCTION.
💡 Uzman Yorumu: RFC veya transaction gibi prosedürel nesneler zorunlu olduğunda bile, gerçek işi yapacak sınıfları çağıran ince bir katman olarak kullanın. Bu, iş mantığını test edilebilir tutmanın en iyi yoludur.
3.4 Fonksiyonel Dil Yapılarını Tercih Edin Orijinal Kaynak
Modern ABAP sözdizimi genellikle daha kısa ve modern programcılara daha doğal gelir.
✓ İYİ KULLANIM
DATA(variable) = 'A'.
DATA(uppercase) = to_upper( lowercase ).
index += 1.
DATA(object) = NEW /clean/my_class( ).
result = VALUE #( FOR row IN input ( row-text ) ).
DATA(line) = value_pairs[ name = 'A' ].
DATA(exists) = xsdbool( line_exists( value_pairs[ name = 'A' ] ) ).
✗ KÖTÜ KULLANIM
MOVE 'A' TO variable.
TRANSLATE lowercase TO UPPER CASE.
ADD 1 TO index.
CREATE OBJECT object TYPE /dirty/my_class.
LOOP AT input INTO DATA(row).
INSERT row-text INTO TABLE result.
ENDLOOP.
READ TABLE value_pairs INTO DATA(line) WITH KEY name = 'A'.
READ TABLE value_pairs TRANSPORTING NO FIELDS WITH KEY name = 'A'.
DATA(exists) = xsdbool( sy-subrc = 0 ).
💡 Uzman Yorumu: Modern ABAP sözdizimi yalnızca daha kısa değil, aynı zamanda daha az hata yapmaya davetiye çıkarır. Örneğin VALUE # ile inline tanım, yerel değişken unutma riskini ortadan kaldırır.
3.5 Eski Dil Öğelerinden Kaçının Orijinal Kaynak
ABAP sürümünüzü yükselttiğinizde, eski dil öğelerini kontrol edin ve bunları kullanmaktan kaçının. Yeni alternatifler genellikle okunabilirliği artırır ve daha modern programlama paradigmalarıyla çakışan tasarım çatışmalarını azaltır.
✓ İYİ KULLANIM - Modern sözdizimi (@-escaped host değişkenleri)
SELECT *
FROM spfli
WHERE carrid = @carrid AND
connid = @connid
INTO TABLE @itab.
✗ KÖTÜ KULLANIM - Eski sözdizimi (escape olmayan form)
SELECT *
FROM spfli
WHERE carrid = carrid AND
connid = connid
INTO TABLE itab.
💡 Uzman Yorumu: Eski sözdizimi, program değişkenleriyle veritabanı sütunlarını ayırt etmeyi zorlaştırır. Modern sözdizimi @-escape karakteriyle bu ayrımı açıkça gösterir.
3.6 Tasarım Desenlerini Akıllıca Kullanın Orijinal Kaynak
Tasarım desenleri uygun olduğunda ve belirgin bir fayda sağladığında kullanın. Sırf kullanmış olmak için her yere tasarım desenleri uygulamayın.
💡 Uzman Yorumu: Tasarım desenleri araçtır, amaç değil. Bir probleminiz olduğunda çözüm olarak desene başvurun, yoksa gereksiz karmaşıklık yaratırsınız. "Her problem için bir tasarım deseni aramak" anti-pattern'ın kendisidir.
4. Sabitler
4.1 Magic Number Yerine Sabit Kullanın Orijinal Kaynak
Anlamsız sayısal değerler veya metinler yerine adlandırılmış sabitler kullanın. Bu, kodun ne anlama geldiğini okuyucuya açıklar.
✓ İYİ KULLANIM
IF abap_type = cl_abap_typedescr=>typekind_date.
" Tip, tarih tipi mi diye kontrol edilir - anlam açık
ENDIF.
✗ KÖTÜ KULLANIM
IF abap_type = 'D'. " 'D' ne demek? Neden 'D'?
ENDIF.
💡 Uzman Yorumu: "Magic number" terimi, kodda sihirli gibi görünen anlamsız sayıları tanımlar. Bu sayıları sabit olarak adlandırmak, hem anlamı açıklar hem de tek bir yerde değiştirme imkânı sağlar.
4.2 Sabitler de Açıklayıcı İsme İhtiyaç Duyar Orijinal Kaynak
ABAP'ta her literal'i bir sabit içine sarmak yaygın bir eğilimdir, ancak çoğu zaman isimler yalnızca içerikleri veya tipleri tekrar eder. Sabitin içeriğini değil, anlamını yansıtın.
✓ İYİ KULLANIM
CONSTANTS status_inactive TYPE mmsta VALUE '90'.
CONSTANTS status_cancelled TYPE sww_wistat VALUE 'CANCELLED'.
✗ KÖTÜ KULLANIM
CONSTANTS:
c_01 TYPE spart VALUE '01', " c_01 ne anlama geliyor?
c_mmsta TYPE mmsta VALUE '90'. " sadece tipi tekrar ediyor
💡 Uzman Yorumu: Sabitler kodu açıklamalıdır, sadece değerini saklamamalıdır. "c_01" veya "c_90" gibi isimler hiçbir anlam katmaz. "status_inactive" ise hem değeri saklar hem de anlamını aktarır.
4.3 ENUM Tercih Edin Orijinal Kaynak
ABAP'ın yerel ENUM yapısını kullanın (7.51 ve üzeri sürümlerde kullanılabilir). Sabit arayüzlerin karışık yapısından kaçının.
✓ İYİ KULLANIM
CLASS /clean/message_severity DEFINITION PUBLIC ABSTRACT FINAL.
PUBLIC SECTION.
TYPES: BEGIN OF ENUM type,
warning,
error,
END OF ENUM type.
ENDCLASS.
✗ KÖTÜ KULLANIM
INTERFACE /dirty/common_constants.
CONSTANTS:
warning TYPE symsgty VALUE 'W',
transitional TYPE i VALUE 1,
error TYPE symsgty VALUE 'E',
persisted TYPE i VALUE 2. " ilgisiz sabitler karıştırılmış
ENDINTERFACE.
💡 Uzman Yorumu: ENUM kullanmak, tip güvenliği sağlar ve yanlış değer atamalarını derleme zamanında yakalar. Sabit arayüzlerden farklı olarak, ENUM değerleri birbiriyle ilişkili olduğunu açıkça belirtir.
4.4 Sabitleri Gruplandırın Orijinal Kaynak
ENUM kullanamıyorsanız ve sabitleri bir arayüzde toplamanız gerekiyorsa, en azından onları gruplayın. Bu, ilişkiyi daha net ortaya koyar.
✓ İYİ KULLANIM
CONSTANTS:
BEGIN OF message_severity,
warning TYPE symsgty VALUE 'W',
error TYPE symsgty VALUE 'E',
END OF message_severity,
BEGIN OF message_lifespan,
transitional TYPE i VALUE 1,
persisted TYPE i VALUE 2,
END OF message_lifespan.
✗ KÖTÜ KULLANIM
CONSTANTS:
warning TYPE symsgty VALUE 'W',
transitional TYPE i VALUE 1, " ilgisiz sabitler karışık
error TYPE symsgty VALUE 'E',
persisted TYPE i VALUE 2.
💡 Uzman Yorumu: Gruplandırma, sabitlerin birbirleriyle ilişkisini görsel olarak ifade eder ve grup üzerinden döngü ile erişim gibi ek özellikler kazandırır.
5. Değişkenler
5.1 Inline Bildirimi Tercih Edin Orijinal Kaynak
Bu kılavuzu takip ederseniz metodlarınız çok kısa olacak (3-5 ifade) ve değişkenleri ilk kullanımlarında inline olarak bildirmek daha doğal görünecektir.
✓ İYİ KULLANIM
METHOD do_something.
DATA(name) = 'something'.
DATA(reader) = /clean/reader=>get_instance_for( name ).
result = reader->read_it( ).
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD do_something.
DATA:
name TYPE seoclsname,
reader TYPE REF TO /dirty/reader.
name = 'something'.
reader = /dirty/reader=>get_instance_for( name ).
result = reader->read_it( ).
ENDMETHOD.
💡 Uzman Yorumu: Inline bildirim, değişkeni kullanım noktasına yakın tutar. Bu, okuyucunun değişkenin ne olduğunu anlamak için yukarı kaydırmasını önler ve kodun anlaşılmasını kolaylaştırır.
5.2 Bildirim Bloğu Dışında Kullanmayın Orijinal Kaynak
Bir ifade bloğunda (IF veya LOOP bloğu gibi) bildirilen bir değişken, bu bloğun dışında da kullanılabilir olsa da bunu yapmayın. Bu durum okuyucuyu yanıltır.
✓ İYİ KULLANIM
DATA value TYPE i.
IF has_entries = abap_true.
value = 1.
ELSE.
value = 2.
ENDIF.
✗ KÖTÜ KULLANIM
IF has_entries = abap_true.
DATA(value) = 1. " IF bloğunda bildiriliyor
ELSE.
value = 2. " ama dışarıda kullanılıyor - kafa karıştırıcı
ENDIF.
💡 Uzman Yorumu: ABAP'ta bir blok içinde DATA() ile bildirilen değişken o blok sona erdikten sonra da var olmaya devam eder. Bu Java veya C# gibi dillerin aksine bir davranıştır ve istemeden kötüye kullanıma yol açabilir.
5.3 Önceden Bildirimleri Zincirlemeyin Orijinal Kaynak
Zincirleme, tanımlanan değişkenlerin mantıksal düzeyde ilişkili olduğunu ima eder. Bu, gereksiz yere reformatlamayı ve refactoring'i karmaşıklaştırır.
✓ İYİ KULLANIM
DATA name TYPE seoclsname.
DATA reader TYPE REF TO reader.
✗ KÖTÜ KULLANIM
DATA:
name TYPE seoclsname,
reader TYPE REF TO reader. " zincirleme gereksiz karmaşıklık ekler
💡 Uzman Yorumu: DATA: zincirleme sözdizimi refactoring sırasında çok sorun yaratır. Bir satır eklediğinizde veya çıkardığınızda nokta, virgül ve iki nokta üst üstelerle uğraşmak zorunda kalırsınız. Ayrı DATA ifadeleri çok daha temizdir.
5.4 Alan Sembolleri için Dinamik Veri Erişimi Kullanmayın Orijinal Kaynak
ABAP Platform 2021'den itibaren, genel tipli değişkenlere erişmek veya bir değişkenin bileşenlerine dinamik erişim sağlamak için alan sembolü kullanılması gereken yerler neredeyse kalmamıştır.
✓ İYİ KULLANIM
result = dref->*.
✗ KÖTÜ KULLANIM
ASSIGN dref->* TO <fs>.
result = <fs>. " gereksiz alan sembolü
💡 Uzman Yorumu: Alan sembolleri güçlü ama tehlikeli araçlardır. Modern ABAP sözdizimi genellikle daha güvenli alternatifler sunar. Referans değişkenleri ve doğrudan erişim operatörleri çoğu durumda alan sembollerinin yerini alabilir.
5.5 Döngüler için Doğru Hedef Seçin Orijinal Kaynak
ABAP döngüsü için üç hedef seçeneği vardır: alan sembolü, referans değişkeni veya düz veri nesnesi. Her birinin farklı amaçları vardır.
✓ İYİ KULLANIM
" Veriyi okumak veya değiştirmek için alan sembolü
LOOP AT table ASSIGNING FIELD-SYMBOL(<line>).
obj->do_something( <line> ).
ENDLOOP.
" Referansa döngü dışında erişmek için referans değişkeni
LOOP AT table REFERENCE INTO DATA(line).
obj->do_something( line->* ).
ENDLOOP.
💡 Uzman Yorumu: Alan sembolleri (FIELD-SYMBOL) tablo satırını doğrudan değiştirmek için idealdir. Referans değişkenleri ise nesne yönelimli ABAP'ın genel desenine uygundur ve döngü dışında kullanılabilir.
6. Tablolar
6.1 Doğru Tablo Tipini Kullanın Orijinal Kaynak
Tablo tipini kullanım durumuna göre seçin:
- HASHED tablolar: Tek seferde doldurulan, hiç değiştirilmeyen ve anahtarıyla sık okunan büyük tablolar için kullanın. Hash tabloların belirgin değeri yalnızca büyük veri miktarları ve çok sayıda okuma erişiminde ortaya çıkar.
- SORTED tablolar: Her zaman sıralı tutulması gereken, parça parça doldurulan veya değiştirilen ve bir veya daha fazla tam veya kısmi anahtarla sık okunan büyük tablolar için kullanın.
- STANDARD tablolar: İndekslemenin ek yük yarattığı küçük tablolar ve sıra önemsiz "dizi" benzeri tablolar için kullanın.
💡 Uzman Yorumu: Yanlış tablo tipi seçimi önemli performans sorunlarına yol açabilir. Tablonuzun boyutuna ve erişim desenine bağlı olarak doğru seçim yapın. SORTED tablo, binary search otomatik uygular; STANDARD tabloda manuel SORT ve BINARY SEARCH yapmanız gerekir.
6.2 DEFAULT KEY'den Kaçının Orijinal Kaynak
DEFAULT KEY genellikle yalnızca daha yeni fonksiyonel ifadelerin çalışmasını sağlamak için eklenir. Anahtar bileşenlerini açıkça belirtin ya da anahtara gerek yoksa EMPTY KEY kullanın.
✓ İYİ KULLANIM
DATA itab2 TYPE STANDARD TABLE OF row_type WITH NON-UNIQUE KEY comp1 comp2.
DATA itab1 TYPE STANDARD TABLE OF row_type WITH EMPTY KEY.
✗ KÖTÜ KULLANIM
DATA itab TYPE STANDARD TABLE OF row_type WITH DEFAULT KEY.
" DEFAULT KEY sayısal veri tiplerini yoksayar ve beklenmedik sonuçlara yol açar
💡 Uzman Yorumu: DEFAULT KEY ile SORT veya DELETE ADJACENT kullanmak, özellikle sayısal alanlar içerdiğinde tahmin edilemez sonuçlar üretir. Her zaman anahtar bileşenlerini açıkça belirtin.
6.3 INSERT INTO TABLE Tercih Edin Orijinal Kaynak
INSERT INTO TABLE tüm tablo ve anahtar tipleriyle çalışır ve tablo tipini daha kolay değiştirmenizi sağlar. Yalnızca STANDARD tabloyu dizi gibi kullanıyorsanız APPEND TO kullanın.
✓ İYİ KULLANIM
INSERT VALUE #( ... ) INTO TABLE itab.
✗ KÖTÜ KULLANIM
APPEND VALUE #( ... ) TO itab. " yalnızca STANDARD tablo için uygundur
💡 Uzman Yorumu: INSERT INTO TABLE tabloyu SORTED veya HASHED'e dönüştürdüğünüzde otomatik olarak doğru davranışı sergiler. APPEND TO ise yalnızca STANDARD tablolarda çalışır ve refactoring'i zorlaştırır.
6.4 LINE_EXISTS Tercih Edin Orijinal Kaynak
Bir satırın varlığını kontrol etmek için line_exists() kullanın. Bu, amacı daha açık ve kısa ifade eder.
✓ İYİ KULLANIM
IF line_exists( my_table[ key = 'A' ] ).
✗ KÖTÜ KULLANIM
READ TABLE my_table TRANSPORTING NO FIELDS WITH KEY key = 'A'.
IF sy-subrc = 0. " sy-subrc kontrolü amacı gizler
LOOP AT my_table REFERENCE INTO DATA(line) WHERE key = 'A'.
line_exists = abap_true.
EXIT.
ENDLOOP. " çok daha fazla kod, aynı amaç
💡 Uzman Yorumu: line_exists() birkaç satırlık kodu tek satıra indirgeyerek kodu çok daha okunabilir kılar. Amacı da açıkça belirtir: "bu satır var mı?"
6.5 READ TABLE Tercih Edin Orijinal Kaynak
Tek bir satıra erişmek için READ TABLE kullanın, LOOP AT değil. READ TABLE amacı daha açık ifade eder ve daha kısadır.
✓ İYİ KULLANIM
READ TABLE my_table REFERENCE INTO DATA(line) WITH KEY key = 'A'.
✗ KÖTÜ KULLANIM
LOOP AT my_table REFERENCE INTO DATA(line) WHERE key = 'A'.
EXIT. " tek satır için LOOP gereksiz karmaşıklık
ENDLOOP.
💡 Uzman Yorumu: Modern tablo erişim sözdizimi (my_table[ key = 'A' ]) daha da kısadır. Satırın var olmama ihtimali varsa OPTIONAL anahtar sözcüğünü ya da TRY/CATCH bloğunu kullanın.
6.6 LOOP AT WHERE Tercih Edin Orijinal Kaynak
LOOP AT WHERE kullanmak, döngü içinde iç içe IF kullanmaktan daha açık ve kısadır.
✓ İYİ KULLANIM
LOOP AT my_table REFERENCE INTO DATA(line) WHERE key = 'A'.
" yalnızca key = 'A' satırları işlenir
ENDLOOP.
✗ KÖTÜ KULLANIM
LOOP AT my_table REFERENCE INTO DATA(line).
IF line->key = 'A'. " WHERE koşulu döngüde tekrar yazılmış
" işlem yap
ENDIF.
ENDLOOP.
💡 Uzman Yorumu: LOOP AT WHERE sözdizimi hem daha okunabilir hem de bazı durumlarda daha performanslıdır. SORTED tablolarda WHERE koşullu LOOP, binary search kullanarak belirli satırlara doğrudan erişir.
6.7 Gereksiz Tablo Okumalarından Kaçının Orijinal Kaynak
Bir satırın orada olmasını bekliyorsanız, bir kez okuyun ve exception'a tepki verin. Çift okumadan kaçının.
✓ İYİ KULLANIM
TRY.
DATA(row) = my_table[ key = input ].
CATCH cx_sy_itab_line_not_found.
RAISE EXCEPTION NEW /clean/my_data_not_found( ).
ENDTRY.
✗ KÖTÜ KULLANIM
IF NOT line_exists( my_table[ key = input ] ). " birinci okuma
RAISE EXCEPTION NEW /clean/my_data_not_found( ).
ENDIF.
DATA(row) = my_table[ key = input ]. " ikinci okuma - gereksiz
💡 Uzman Yorumu: Çift okuma hem performans açısından kötüdür hem de kod karmaşıklığını artırır. TRY/CATCH yaklaşımı hem daha temiz hem de daha verimlidir.
7. Dizgiler
7.1 Backtick ile Literal Tanımlayın Orijinal Kaynak
String literal tanımlamak için tek tırnak yerine backtick (`) kullanın. Tek tırnak gereksiz tip dönüşümüne ve okuyucunun CHAR mı STRING mi kullandığını merak etmesine yol açar.
✓ İYİ KULLANIM
CONSTANTS some_constant TYPE string VALUE `ABC`.
DATA(some_string) = `ABC`. " --> TYPE string kesin
✗ KÖTÜ KULLANIM
DATA some_string TYPE string.
some_string = 'ABC'. " tek tırnak: CHAR mı STRING mi? gereksiz dönüşüm
DATA(some_string2) = |ABC|. " sabit değer için | gereksiz yük ekler
💡 Uzman Yorumu: Backtick her zaman STRING tipini üretir. Tek tırnak ise CHAR üretir ve string değişkenine atandığında implicit dönüşüm gerektirir. Bu küçük fark bazen beklenmedik davranışlara yol açabilir.
7.2 | ile Metin Birleştirin Orijinal Kaynak
Birden fazla parçayı birleştirirken string şablonları (| |) kullanın. Bu, sabit metnin nerede bitip değişkenin nerede başladığını çok daha belirgin kılar.
✓ İYİ KULLANIM
DATA(message) = |Received HTTP code { status_code } with message { text }|.
✗ KÖTÜ KULLANIM
DATA(message) = `Received an unexpected HTTP ` && status_code && ` with message ` && text.
" && ile birleştirme okunması zor, değişkenleri ayırt etmek güç
💡 Uzman Yorumu: String şablonları yalnızca birleştirme için değil, biçimlendirme için de kullanılabilir. { variable ALPHA = IN }, { variable DATE = USER } gibi biçimlendirme seçenekleri ek güç sağlar.
8. Boolean'lar
8.1 Boolean'ları Akıllıca Kullanın Orijinal Kaynak
Boolean'lar doğal bir seçim gibi görünse de, genellikle bir numaralandırma kullanmak daha iyi olur. Boolean'lar, biri veya diğeri dışında durumların ortaya çıkacağı durumlarda kötü bir seçimdir.
✓ İYİ KULLANIM
archiving_status = /clean/archivation_status=>archiving_in_process.
" Enum, ara durumları açıkça temsil edebilir
✗ KÖTÜ KULLANIM
is_archived = abap_true.
" Ya "kısmen arşivlendi" durumu? Boolean bunu ifade edemez
💡 Uzman Yorumu: Boolean'lar genellikle "şu an için yeterli" görünür ama iş gereksinimleri büyüdükçe yetersiz kalır. Baştan enum kullanmak uzun vadede daha iyi bir tasarım sağlar.
8.2 ABAP_BOOL Kullanın Orijinal Kaynak
Boolean değişkenler için abap_bool tipini kullanın. Genel char1 tipinden kaçının; bu tip, Boolean değişkenle karşı karşıya olduğumuzu gizler.
✓ İYİ KULLANIM
DATA has_entries TYPE abap_bool.
✗ KÖTÜ KULLANIM
DATA has_entries TYPE char1. " Boolean olduğu belli değil
DATA has_entries TYPE boolean. " üçüncü "undefined" değeri sorun yaratır
💡 Uzman Yorumu: ABAP, evrensel bir Boolean tipiyle gelmez. abap_bool, type pool'da tanımlanmış olan standarttır. DynPro alanları için abap_boolean kullanın.
8.3 ABAP_TRUE ve ABAP_FALSE Kullanın Orijinal Kaynak
Boolean karşılaştırmaları için abap_true ve abap_false sabitlerini kullanın. 'X' ve ' ' (space) gibi karakter eşdeğerlerinden kaçının.
✓ İYİ KULLANIM
has_entries = abap_true.
IF has_entries = abap_false.
" açık ve anlaşılır
ENDIF.
✗ KÖTÜ KULLANIM
has_entries = 'X'. " 'X' Boolean olduğunu gizler
IF has_entries = space. " space: false demek - açık değil
IF has_entries IS NOT INITIAL. " INITIAL mi false anlamına geliyor?
💡 Uzman Yorumu: abap_true ve abap_false kullanmak, Boolean ifadeyi açıkça ortaya koyar. Okuyucu 'X' yerine abap_true gördüğünde hemen Boolean ile karşı karşıya olduğunu anlar.
8.4 XSDBOOL Kullanın Orijinal Kaynak
Boolean değişkenleri ayarlamak için xsdbool() kullanın. Uzun IF-THEN-ELSE bloklarının yerini alır.
✓ İYİ KULLANIM
DATA(has_entries) = xsdbool( line IS NOT INITIAL ).
DATA(has_entries2) = COND abap_bool( WHEN line IS NOT INITIAL THEN abap_true ).
✗ KÖTÜ KULLANIM
IF line IS INITIAL.
has_entries = abap_false.
ELSE.
has_entries = abap_true. " 5 satır yerine 1 satır yeterli
ENDIF.
💡 Uzman Yorumu: xsdbool() doğrudan char1 üretir, bu nedenle abap_bool tipiyle mükemmel uyum sağlar. boolc() ve boolx() farklı tipler üretir ve implicit tip dönüşümü gerektirir.
9. Koşullar
9.1 Koşulları Pozitif Yapın Orijinal Kaynak
Koşulları mümkün olduğunda pozitif formda yazın. Olumsuz koşullar okuyucunun zihinsel olarak tersine çevirmesini gerektirir.
✓ İYİ KULLANIM
IF has_entries = abap_true.
" açık ve doğal okuma akışı
ENDIF.
✗ KÖTÜ KULLANIM
IF has_no_entries = abap_false.
" çifte olumsuzlama - zihinsel çaba gerektirir
ENDIF.
💡 Uzman Yorumu: "Çifte olumsuzlama" anlamayı önemli ölçüde zorlaştırır. "IF NOT has_no_entries" gibi ifadeler bir an için duraksamanıza neden olur. Pozitif koşullar beyin için daha doğaldır.
9.2 IS NOT Tercih Edin Orijinal Kaynak
NOT IS yerine IS NOT tercih edin. Olumsuzlama, koşulun tam ortasına değil, doğal bir yere yerleşmelidir.
✓ İYİ KULLANIM
IF variable IS NOT INITIAL.
IF variable NP 'TODO*'.
IF variable <> 42.
✗ KÖTÜ KULLANIM
IF NOT variable IS INITIAL. " NOT en sona yerleştirilmeli
IF NOT variable CP 'TODO*'.
IF NOT variable = 42.
💡 Uzman Yorumu: "NOT IS" yerine "IS NOT" kullanmak, olumsuzlamayı daha doğal bir konuma taşır ve koşulu okurken daha az zihinsel çaba gerektirir.
9.3 Yüklemsel Metod Çağrısı Düşünün Orijinal Kaynak
Boolean metodlar için yüklemsel metod çağrısı kullanın. Bu, kodu doğal dile daha yakın kılar.
✓ İYİ KULLANIM
IF condition_is_fulfilled( ).
IF NOT condition_is_fulfilled( ).
✗ KÖTÜ KULLANIM
IF condition_is_fulfilled( ) = abap_true.
IF condition_is_fulfilled( ) = abap_false. " karşılaştırma gereksiz
💡 Uzman Yorumu: Yüklemsel metod çağrısı (meth()) tam olarak meth() IS NOT INITIAL'ın kısaltmasıdır. Yalnızca başlangıç değeri "false", başlangıç dışı değeri "true" anlamına gelen metodlarda kullanın.
9.4 Karmaşık Koşulları Parçalayın Orijinal Kaynak
Karmaşık koşulları parçalara bölerek ara değişkenlere atayın. Bu, her bölümün ne anlama geldiğini açıklamayı kolaylaştırır.
✓ İYİ KULLANIM
DATA(example_provided) = xsdbool( example_a IS NOT INITIAL OR
example_b IS NOT INITIAL ).
DATA(one_example_fits) = xsdbool( applies( example_a ) = abap_true OR
applies( example_b ) = abap_true OR
fits( example_b ) = abap_true ).
IF example_provided = abap_true AND
one_example_fits = abap_true.
✗ KÖTÜ KULLANIM
IF ( example_a IS NOT INITIAL OR
example_b IS NOT INITIAL ) AND
( applies( example_a ) = abap_true OR
applies( example_b ) = abap_true OR
fits( example_b ) = abap_true ). " tek IF'te çok fazla mantık
💡 Uzman Yorumu: Karmaşık koşulları adlandırılmış değişkenlere bölmek, her parçanın ne anlama geldiğini belgelemenize olanak tanır. ABAP Development Tools'un hızlı düzeltme özelliğiyle bunu otomatik yapabilirsiniz.
9.5 Karmaşık Koşulları Ayıklayın Orijinal Kaynak
Karmaşık koşulları ayrı metodlara çıkarmak neredeyse her zaman iyi bir fikirdir.
✓ İYİ KULLANIM
IF is_provided( example ).
METHOD is_provided.
DATA(is_filled) = xsdbool( example IS NOT INITIAL ).
DATA(is_working) = xsdbool( applies( example ) = abap_true OR
fits( example ) = abap_true ).
result = xsdbool( is_filled = abap_true AND
is_working = abap_true ).
ENDMETHOD.
💡 Uzman Yorumu: Karmaşık bir koşulu ayrı bir metodda toplamak, o koşulun mantığını izole eder ve bağımsız olarak test edilmesini sağlar. Ayrıca metodun okunabilirliğini büyük ölçüde artırır.
10. If İfadeleri
10.1 Boş IF Dalları Kullanmayın Orijinal Kaynak
Boş IF dalları kullanmak yerine koşulu ters çevirin. Boş bir IF gövdesi okuyucuyu şaşırtır.
✓ İYİ KULLANIM
IF has_entries = abap_false.
" do some magic
ENDIF.
✗ KÖTÜ KULLANIM
IF has_entries = abap_true.
" boş - hiçbir şey yok
ELSE.
" do some magic " mantık ELSE'de, IF gövdesi boş - kafa karıştırıcı
ENDIF.
💡 Uzman Yorumu: Boş bir IF gövdesi "neden burada IF var?" sorusunu akla getirir. Koşulu tersine çevirmek ve boş gövdeden kurtulmak kodu çok daha temiz yapar.
10.2 CASE Tercih Edin Orijinal Kaynak
Birden fazla alternatif koşul için ELSE IF yerine CASE kullanın. CASE, birbirini dışlayan alternatifleri kolayca gösterir ve yeni durumları hızla eklemenize izin verir.
✓ İYİ KULLANIM
CASE type.
WHEN type-some_type.
" ...
WHEN type-some_other_type.
" ...
WHEN OTHERS.
RAISE EXCEPTION NEW /clean/unknown_type_failure( ).
ENDCASE.
✗ KÖTÜ KULLANIM
IF type = type-some_type.
" ...
ELSEIF type = type-some_other_type.
" ... " type değişkeni her seferinde tekrar
ELSE.
RAISE EXCEPTION NEW /dirty/unknown_type_failure( ).
ENDIF.
💡 Uzman Yorumu: CASE ifadesi bazı durumlarda birden fazla IF/ELSEIF'ten daha hızlı çalışır çünkü farklı bir mikroişlemci komutu kullanabilir. Ayrıca CASE yanlışlıkla IF-ELSEIF iç içe geçirme hatalarını önler.
10.3 İç İçe Geçme Derinliğini Düşük Tutun Orijinal Kaynak
İç içe IF'ler hızla anlaşılmaz hale gelir ve tam kapsam için üstel sayıda test case gerektirir. Alt metodlar oluşturarak veya koşulları birleştirerek iç içe geçmeyi azaltın.
✓ İYİ KULLANIM
IF <this> AND <that>.
" düz yapı, koşullar birleştirildi
ENDIF.
✗ KÖTÜ KULLANIM
IF <this>.
IF <that>.
ENDIF.
ELSE.
IF <other>.
ELSE.
IF <something>.
ENDIF.
ENDIF.
ENDIF. " dört seviye iç içe geçme - anlamak çok zor
💡 Uzman Yorumu: İç içe geçme derinliği 3'ü aştığında kodu anlamak katlanarak zorlaşır. Erken çıkış (RETURN/RAISE) kullanmak ve koşulları alt metodlara çıkarmak derinliği azaltır.
11. Düzenli İfadeler (Regex)
11.1 Daha Basit Metodları Tercih Edin Orijinal Kaynak
Regex yerine daha basit string metodları kullanın. Basit durumlar genellikle regex olmadan daha anlaşılırdır. Regex ayrıca çalışma zamanında derlenmesi gerektiğinden ek bellek ve işlemci zamanı tüketir.
✓ İYİ KULLANIM
IF input IS NOT INITIAL.
WHILE contains( val = input sub = 'abc' ).
✗ KÖTÜ KULLANIM
IF matches( val = input regex = '.+' ). " basit durumlar için regex gereksiz
WHILE contains( val = input regex = 'abc' ).
💡 Uzman Yorumu: Regex çok güçlüdür ama okunması da çok zordur. "Bazı insanlar bir problemi çözmek için regex kullanmaya karar verirler. Şimdi iki problemi vardır." —Jamie Zawinski
11.2 Temel Kontrolleri Tercih Edin Orijinal Kaynak
Kendi regex'inizi yazmak yerine, SAP'nin sunduğu mevcut kontrol fonksiyonlarını kullanın. DRY (Don't Repeat Yourself) prensibine uyun.
✓ İYİ KULLANIM
CALL FUNCTION 'SEO_CLIF_CHECK_NAME'
EXPORTING
cls_name = class_name
EXCEPTIONS
...
✗ KÖTÜ KULLANIM
DATA(is_valid) = matches( val = class_name
pattern = '[A-Z][A-Z0-9_]{0,29}' ).
" SAP zaten bu kontrolü yapıyor, tekrar yazmak DRY ihlalatıdır
💡 Uzman Yorumu: SAP, pek çok doğrulama için standart fonksiyonlar sunar. Bu fonksiyonlar SAP'nin kendi standartlarına göre test edilmiştir. Kendi regex'inizi yazmak hem zaman kaybıdır hem de potansiyel hata kaynağıdır.
11.3 Karmaşık Regex'leri Birleştirin Orijinal Kaynak
Karmaşık regex'leri daha basit parçalardan oluşturarak okuyucuya nasıl kurulduğunu gösterin.
✓ İYİ KULLANIM
CONSTANTS class_name TYPE string VALUE `CL\_.*`.
CONSTANTS interface_name TYPE string VALUE `IF\_.*`.
DATA(object_name) = |{ class_name }\|{ interface_name }|.
" Regex parça parça açıkça oluşturuldu
💡 Uzman Yorumu: Karmaşık bir regex'i tek satırda yazmak zorunda değilsiniz. Parçalara bölerek hem belgeleyin hem de daha okunabilir hale getirin. Regex parçalarını sabit olarak adlandırmak amacı da açıklar.
12. Sınıflar
12.1 Nesneleri Tercih Edin Orijinal Kaynak
Statik sınıflar, nesne yöneliminin sağladığı tüm avantajları başından atar. Özellikle birim testlerinde bağımlılıkları test double'larla değiştirmeyi neredeyse imkânsız kılar.
✓ İYİ KULLANIM
CLASS /clean/string_utils DEFINITION [...].
CLASS-METHODS trim
IMPORTING
string TYPE string
RETURNING
VALUE(result) TYPE string.
ENDCLASS.
METHOD retrieve.
DATA(trimmed_name) = /clean/string_utils=>trim( name ).
result = read( trimmed_name ).
ENDMETHOD.
💡 Uzman Yorumu: Sınıf veya metod statik mi olmalı sorusunun cevabı neredeyse her zaman "hayır"dır. Kabul edilebilir istisna: tamamen durumsuz, temel yardımcı metodlar (string_utils gibi). Bunlar ABAP ifadelerine veya yerleşik fonksiyonlara o kadar yakındır ki test double'larla değiştirilmeleri gerekmez.
12.2 Bileşimi Tercih Edin Orijinal Kaynak
Kalıtım hiyerarşileri yerine bileşim kullanın. Temiz kalıtım tasarımı zordur ve Liskov ikame prensibine uymayı gerektirir. Bileşim daha küçük bağımsız nesneler oluşturmanızı ve bunları birleştirmenizi sağlar.
💡 Uzman Yorumu: "Kalıtım yerine bileşimi tercih et" GoF tasarım desenlerinin temel prensibidir. Kalıtım uygun olduğu yerlerde (Composite deseni gibi) kullanın ama her durumda kalıtıma başvurmaktan kaçının.
12.3 Stateful ve Stateless'ı Karıştırmayın Orijinal Kaynak
Aynı sınıfta durumsuz (stateless) ve durumlu (stateful) programlama paradigmalarını karıştırmayın. Her iki paradigma da geçerlidir, ancak karıştırıldığında anlaşılması zor ve hata üretmeye meyilli kod ortaya çıkar.
✓ İYİ KULLANIM - Stateless sınıf
CLASS /clean/xml_converter DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS convert
IMPORTING
file_content TYPE xstring
RETURNING
VALUE(result) TYPE /clean/some_inbound_message.
ENDCLASS.
" Stateful sınıf
CLASS /clean/log DEFINITION PUBLIC CREATE PUBLIC.
PUBLIC SECTION.
METHODS add_message IMPORTING message TYPE /clean/message.
PRIVATE SECTION.
DATA messages TYPE /clean/message_table.
ENDCLASS.
💡 Uzman Yorumu: Stateless sınıflar test edilmesi en kolay sınıflardır çünkü yan etkileri yoktur. Stateful sınıflar güçlüdür ama daha dikkatli tasarım gerektirir. İkisini karıştırmak her ikisinin dezavantajlarını birleştirir.
12.4 Global'i Varsayılan Kabul Edin Orijinal Kaynak
Varsayılan olarak global sınıflarla çalışın. Yerel sınıfları yalnızca uygun yerlerde kullanın. Yerel sınıflar yeniden kullanımı engeller ve bulunması genellikle zordur.
💡 Uzman Yorumu: Yerel sınıflar include düzeyinde kilitlenme oluşturur; bu nedenle birden fazla geliştirici aynı anda üzerinde çalışamaz. Global sınıflar bu sorunu ortadan kaldırır ve yeniden kullanılabilirliği artırır.
12.5 FINAL Yapın Orijinal Kaynak
Kalıtım için açıkça tasarlanmamış sınıfları FINAL yapın. Bu, yanlışlıkla kalıtımı önler ve tasarım kararlarınızı açıkça ifade eder.
✓ İYİ KULLANIM
CLASS /clean/my_utility DEFINITION PUBLIC FINAL CREATE PUBLIC.
" Kalıtım için tasarlanmadı, FINAL ile koruma altında
ENDCLASS.
💡 Uzman Yorumu: FINAL olmayan bir sınıf, "bu sınıftan türetebilirsiniz" demektir. Bu, dışarıya açık bir API'nin parçasıdır ve dikkatli tasarım gerektirir. Eğer kalıtım planlamıyorsanız FINAL kullanın.
12.6 Üyeler Varsayılan Olarak PRIVATE Orijinal Kaynak
Öznitelikler, metodlar ve diğer sınıf üyeleri varsayılan olarak PRIVATE olmalıdır. Yalnızca alt sınıfların bunları geçersiz kılmasını istiyorsanız PROTECTED yapın.
💡 Uzman Yorumu: "Bilmesi gereken kadar bilgi" ilkesi (need-to-know basis). Sınıf iç yapısını dışarıya açmak, beklenmedik yeniden tanımlamalar yoluyla ince hatalara yol açabilir ve refactoring'i zorlaştırır.
12.7 Immutable Kullanmayı Düşünün Orijinal Kaynak
Yapılandırıldıktan sonra hiç değişmeyen nesneler için getter metodlar yerine public salt okunur öznitelikler kullanmayı düşünün.
✓ İYİ KULLANIM
CLASS /clean/some_data_container DEFINITION.
PUBLIC SECTION.
METHODS constructor
IMPORTING
a TYPE i
b TYPE c
c TYPE d.
DATA a TYPE i READ-ONLY.
DATA b TYPE c READ-ONLY.
DATA c TYPE d READ-ONLY.
ENDCLASS.
✗ KÖTÜ KULLANIM
CLASS /dirty/some_data_container DEFINITION.
PUBLIC SECTION.
METHODS get_a ...
METHODS get_b ...
METHODS get_c ... " salt getter metodlar gereksiz karmaşıklık ekler
PRIVATE SECTION.
DATA a TYPE i.
DATA b TYPE c.
DATA c TYPE d.
ENDCLASS.
💡 Uzman Yorumu: READ-ONLY öznitelikler, getter metodlara kıyasla çok daha az kod gerektirirken aynı kapsüllemeyi sağlar. Nesne değiştirilebilirse bu yaklaşımı kullanmayın.
12.8 READ-ONLY'yi Tutumlu Kullanın Orijinal Kaynak
READ-ONLY yalnızca PUBLIC SECTION'da kullanılabilir ve beklenenin aksine sınıf içinden, friend sınıflardan ve alt sınıflardan değiştirilebilir. Bu durum diğer dillerdeki beklentilerden farklıdır.
💡 Uzman Yorumu: READ-ONLY diğer dillerdeki "final" veya "readonly" gibi davranmaz. ABAP'ta sınıf içinden hâlâ değiştirilebilir. Bu, yanlış anlaşılmalara yol açabilir; kullanım amacını ekibinizle açıkça paylaşın.
12.9 NEW Tercih Edin Orijinal Kaynak
Nesne oluşturmak için CREATE OBJECT yerine NEW kullanın. Yalnızca dinamik tipler gerektirdiğinde CREATE OBJECT kullanın.
✓ İYİ KULLANIM
DATA object TYPE REF TO /clean/some_number_range.
object = NEW #( '/CLEAN/CXTGEN' )
DATA(object) = NEW /clean/some_number_range( '/CLEAN/CXTGEN' ).
DATA(object) = CAST /clean/number_range( NEW /clean/some_number_range( '/CLEAN/CXTGEN' ) ).
✗ KÖTÜ KULLANIM
DATA object TYPE REF TO /dirty/some_number_range.
CREATE OBJECT object
EXPORTING
number_range = '/DIRTY/CXTGEN'. " çok daha uzun
💡 Uzman Yorumu: NEW sözdizimi daha kısadır ve method chaining ile daha iyi çalışır. CAST ile birleştiğinde özellikle güçlüdür. Dinamik tip gerekmedikçe CREATE OBJECT kullanmaktan kaçının.
12.10 CONSTRUCTOR'ı Public Bırakın Orijinal Kaynak
Global sınıfınız CREATE PRIVATE ise, CONSTRUCTOR'ı PUBLIC SECTION'da bırakın. Bu, doğru derleme ve sözdizimi doğrulaması için gereklidir.
✓ İYİ KULLANIM
CLASS /clean/some_api DEFINITION PUBLIC FINAL CREATE PRIVATE.
PUBLIC SECTION.
METHODS constructor. " CREATE PRIVATE olmasına rağmen public
💡 Uzman Yorumu: Bu, çelişkili görünebilir ama ABAP Help belgelerine göre gereklidir. Yalnızca global sınıflara uygulanır; yerel sınıflarda constructor private olabilir.
12.11 Birden Fazla Statik Oluşturma Metodu Orijinal Kaynak
ABAP function overloading'i desteklemediğinden, isteğe bağlı parametreler yerine birden fazla statik oluşturma metodu kullanın.
✓ İYİ KULLANIM
CLASS-METHODS describe_by_data IMPORTING data TYPE any [...]
CLASS-METHODS describe_by_name IMPORTING name TYPE any [...]
CLASS-METHODS describe_by_object_ref IMPORTING object_ref TYPE REF TO object [...]
CLASS-METHODS describe_by_data_ref IMPORTING data_ref TYPE REF TO data [...]
✗ KÖTÜ KULLANIM
METHODS constructor
IMPORTING
data TYPE any OPTIONAL
name TYPE any OPTIONAL
object_ref TYPE REF TO object OPTIONAL
data_ref TYPE REF TO data OPTIONAL.
" Hangi kombinasyon geçerli? Hepsi OPTIONAL - kafa karıştırıcı
💡 Uzman Yorumu: Birden fazla oluşturma metodu, hangi parametrelerin geçerli olduğunu açıkça ifade eder. İsteğe bağlı parametreler çağırana "hangi kombinasyonu kullanayım?" sorusunu bırakır.
12.12 Açıklayıcı Oluşturma İsimleri Orijinal Kaynak
Oluşturma metodları için new_, create_, construct_ gibi sezgisel başlangıçlar kullanın ve bunları açıklayıcı isimlerle birleştirin.
✓ İYİ KULLANIM
CLASS-METHODS new_describe_by_data IMPORTING p_data TYPE any [...]
CLASS-METHODS new_describe_by_name IMPORTING p_name TYPE any [...]
CLASS-METHODS new_describe_by_object_ref IMPORTING p_object_ref TYPE REF TO object [...]
✗ KÖTÜ KULLANIM
CLASS-METHODS create_1 IMPORTING p_data TYPE any [...]
CLASS-METHODS create_2 IMPORTING p_name TYPE any [...] " numaralar hiçbir anlam taşımaz
💡 Uzman Yorumu: new_from_template, create_as_copy, construct_by_name gibi isimler hem yaratma eylemini hem de yapılandırma detayını iletir. Bu, IDE'nin otomatik tamamlama özelliğiyle de iyi çalışır.
12.13 Singleton Sadece Gerektiğinde Orijinal Kaynak
Singleton desenini yalnızca nesne yönelimli tasarımınız birden fazla örneğin mantıklı olmadığını söylediğinde uygulayın. Alışkanlıktan veya performans kuralından dolayı Singleton kullanmayın.
✓ İYİ KULLANIM
METHOD new.
IF singleton IS NOT BOUND.
singleton = NEW /clean/my_class( ).
ENDIF.
result = singleton.
ENDMETHOD.
💡 Uzman Yorumu: Singleton, en çok kötüye kullanılan tasarım desenlerinden biridir. Gereksiz çapraz etkiler yaratır ve test etmeyi ciddi ölçüde zorlaştırır. Yalnızca nesne tasarımı "tek örnek olmalı" diyorsa kullanın.
13. Metodlar
13.1 Statik Metodları Instance Üzerinden Çağırmayın Orijinal Kaynak
Statik metodu çağırmak için class=>method sözdizimini kullanın, instance değişkeni değil. Instance üzerinden statik metod çağırmak potansiyel kafa karışıklığına yol açar.
✓ İYİ KULLANIM
cl_my_class=>static_method( ).
METHOD static_method.
another_static_method( ). " aynı sınıf içinde niteleyici gerekmez
ENDMETHOD.
✗ KÖTÜ KULLANIM
lo_my_instance->static_method( ). " instance üzerinden statik çağrı - yanıltıcı
💡 Uzman Yorumu: Instance üzerinden statik metod çağrısı, kodun bakımcısını "bu metod instance durumunu mu kullanıyor?" diye merak ettirir. => sözdizimi metodun statik olduğunu açıkça gösterir.
13.2 Tiplere Instance Üzerinden Erişmeyin Orijinal Kaynak
Sınıf veya arayüzde tanımlanmış veri tipine, sınıf/arayüz üzerinden erişin, instance değil. Instance üzerinden tip erişimi, tipin instance'a özel olduğunu ima eder.
✓ İYİ KULLANIM
INTERFACE lif.
TYPES blah TYPE lcl=>foo. " sınıf üzerinden tip erişimi
ENDINTERFACE.
✗ KÖTÜ KULLANIM
INTERFACE lif.
DATA(ref) = new lcl( ).
TYPES blah TYPE ref->foo. " instance üzerinden tip erişimi - yanıltıcı
ENDINTERFACE.
💡 Uzman Yorumu: Tipler sınıfa aittir, instance'a değil. instance->foo yerine ClassName=>foo kullanmak bu gerçeği açıkça ifade eder ve semantik hatayı önler.
13.3 Fonksiyonel Çağrıları Tercih Edin Orijinal Kaynak
CALL METHOD yerine doğrudan metod çağrısı sözdizimini kullanın. Dinamik tipleme zorunlu kıldığında prosedürel stile başvurun.
✓ İYİ KULLANIM
modify->update( node = /clean/my_bo_c=>node-item
key = item->key
data = item
changed_fields = changed_fields ).
✗ KÖTÜ KULLANIM
CALL METHOD modify->update
EXPORTING
node = /dirty/my_bo_c=>node-item
key = item->key
data = item
changed_fields = changed_fields. " gereksiz uzun
💡 Uzman Yorumu: Fonksiyonel çağrı sözdizimi daha kısa ve modern görünür. CALL METHOD ABAP'ın eski dönemlerine aittir; yeni kodda kullanmaktan kaçının.
13.4 RECEIVING'i Atlayın Orijinal Kaynak
Fonksiyonel çağrı sözdiziminde RECEIVING anahtar sözcüğünü atlayın.
✓ İYİ KULLANIM
DATA(sum) = aggregate_values( values ).
✗ KÖTÜ KULLANIM
aggregate_values(
EXPORTING
values = values
RECEIVING
result = DATA(sum) ). " RECEIVING gereksiz uzunluk ekler
💡 Uzman Yorumu: DATA(sum) = method() sözdizimi hem RECEIVING'i hem de EXPORTING'i atlar. Bu modern sözdizimini kullandığınızda kod çok daha temiz görünür.
13.5 EXPORTING'i Atlayın Orijinal Kaynak
Fonksiyonel çağrılarda isteğe bağlı EXPORTING anahtar sözcüğünü atlayın.
✓ İYİ KULLANIM
modify->update( node = /clean/my_bo_c=>node-item
key = item->key
data = item
changed_fields = changed_fields ).
✗ KÖTÜ KULLANIM
modify->update(
EXPORTING " EXPORTING gereksiz
node = /dirty/my_bo_c=>node-item
key = item->key
data = item
changed_fields = changed_fields ).
💡 Uzman Yorumu: Fonksiyonel metod çağrılarında EXPORTING isteğe bağlıdır ve yalnızca gürültü ekler. Kaldırın ve kodunuzu daha temiz yapın.
13.6 Tek Parametreli Çağrılarda Adı Atlayın Orijinal Kaynak
Tek parametreli çağrılarda parametre adını atlayın (metod adı yeterince açıklayıcıysa).
✓ İYİ KULLANIM
DATA(unique_list) = remove_duplicates( list ).
car->drive( speed = 50 ). " metod adı tek başına açık değilse adı yazın
✗ KÖTÜ KULLANIM
DATA(unique_list) = remove_duplicates( list = list ). " "list = list" gereksiz tekrar
💡 Uzman Yorumu: "remove_duplicates( list )" anlaşılırdır; "remove_duplicates( list = list )" ise gereksizdir. Ancak metod adı tek başına açık değilse parametre adı netlik katabilir.
13.7 Me'yi Atlayın Orijinal Kaynak
me-> öz referansı sistem tarafından örtük olarak ayarlandığından, instance öznitelik veya metod çağrısı yaparken atlayın. Yalnızca yerel değişken ile instance özniteliği arasında çakışma olduğunda kullanın.
✓ İYİ KULLANIM
DATA(sum) = aggregate_values( values ).
me->logger = logger. " yalnızca çakışma olduğunda gerekli
✗ KÖTÜ KULLANIM
DATA(sum) = me->aggregate_values( me->values ). " me-> gereksiz gürültü
💡 Uzman Yorumu: me-> her yere eklemek kodu gürültülü yapar ve gerçekten gerekli olduğu durumu (yerel değişken çakışması) gizler. Yalnızca gerektiğinde kullanın.
13.8 Instance Metodları Tercih Edin Orijinal Kaynak
Metodlar varsayılan olarak instance üyesi olmalıdır. Instance metodları sınıfın "nesne" niteliğini daha iyi yansıtır ve birim testlerinde daha kolay mock'lanabilir.
✓ İYİ KULLANIM
METHODS publish. " instance metod
CLASS-METHODS create_instance " statik yalnızca oluşturma için
RETURNING
VALUE(result) TYPE REF TO /clean/blog_post.
💡 Uzman Yorumu: Statik metodlar, bağımlılıkları test double ile değiştirmeyi imkânsız kılar. Statik oluşturma metodları bunun kabul edilebilir istisnasıdır.
13.9 Public Metodlar Interface Parçası Olmalı Orijinal Kaynak
Public instance metodlar her zaman bir arayüzün parçası olmalıdır. Bu, bağımlılıkları ayırır ve birim testlerinde mock'lamayı kolaylaştırır.
✓ İYİ KULLANIM
METHOD /clean/blog_post~publish. " arayüz üzerinden uygulama
💡 Uzman Yorumu: Arayüz olmadan public metod, nesne yöneliminde çok az anlam taşır. Arayüzler, bağımlılık tersine çevirme prensibinin temelidir ve test edilebilirliği sağlar.
13.10 Az IMPORTING Parametresi Orijinal Kaynak
Üç ya da daha az IMPORTING parametresini hedefleyin. Çok fazla giriş parametresi, metodun karmaşıklığını katlanarak artırır ve genellikle çok şey yaptığının göstergesidir.
✓ İYİ KULLANIM
FUNCTION seo_class_copy
IMPORTING
clskey TYPE seoclskey
new_clskey TYPE seoclskey
config TYPE class_copy_config
EXPORTING
...
✗ KÖTÜ KULLANIM
FUNCTION seo_class_copy
IMPORTING
clskey TYPE seoclskey
new_clskey TYPE seoclskey
access_permission TYPE seox_boolean DEFAULT seox_true
VALUE(save) TYPE seox_boolean DEFAULT seox_true
VALUE(suppress_corr) TYPE seox_boolean DEFAULT seox_false
VALUE(suppress_dialog) TYPE seox_boolean DEFAULT seox_false
VALUE(authority_check) TYPE seox_boolean DEFAULT seox_true
lifecycle_manager TYPE REF TO if_adt_lifecycle_manager OPTIONAL
lock_handle TYPE REF TO if_adt_lock_handle OPTIONAL
EXPORTING
... " 9 parametre - çok fazla
💡 Uzman Yorumu: Her yeni parametre, metodun test edilmesi gereken kombinasyon sayısını üstel olarak artırır. Fazla parametreler, parametreleri anlamlı yapılarda birleştirerek azaltılabilir.
13.11 Metodları Bölün Orijinal Kaynak
OPTIONAL parametreler eklemek yerine metodları bölün. İsteğe bağlı parametreler çağıranı hangi kombinasyonun geçerli olduğu konusunda şaşırtır.
✓ İYİ KULLANIM
METHODS do_one_thing IMPORTING what_i_need TYPE string.
METHODS do_another_thing IMPORTING something_else TYPE i.
✗ KÖTÜ KULLANIM
METHODS do_one_or_the_other
IMPORTING
what_i_need TYPE string OPTIONAL
something_else TYPE i OPTIONAL. " hangi kombinasyon geçerli?
💡 Uzman Yorumu: İsteğe bağlı parametreler çağırana şu soruları bırakır: "Hangisi gerçekten gerekli? Hangi kombinasyonlar geçerli? Hangileri birbirini dışlar?" Ayrı metodlar bu soruları ortadan kaldırır.
13.12 PREFERRED PARAMETER'ı Tutumlu Kullanın Orijinal Kaynak
PREFERRED PARAMETER hangi parametrenin gerçekte sağlandığını görmeyi zorlaştırır. Parametreleri, özellikle isteğe bağlı olanları, en aza indirmek PREFERRED PARAMETER ihtiyacını otomatik olarak azaltır.
💡 Uzman Yorumu: PREFERRED PARAMETER, isteğe bağlı parametrelerle birlikte kullanıldığında hangi parametrenin sağlandığını anlamayı çok zorlaştırır. Genellikle metodların daha küçük ve odaklı yapıya bölünmesiyle bu sorunu tamamen önleyebilirsiniz.
13.13 Tam Olarak Bir Parametre Döndürün Orijinal Kaynak
İyi bir metod tek bir şey yapar ve bu, tam olarak bir çıktı döndürmesiyle yansıtılmalıdır. Çıktılar mantıksal bir bütün oluşturuyorsa yapı veya nesne döndürün.
✓ İYİ KULLANIM
TYPES:
BEGIN OF check_result,
result TYPE result_type,
failed_keys TYPE /bobf/t_frw_key,
messages TYPE /bobf/t_frw_message,
END OF check_result.
METHODS check_business_partners
IMPORTING
business_partners TYPE business_partners
RETURNING
VALUE(result) TYPE check_result. " yapı olarak döndür
✗ KÖTÜ KULLANIM
METHODS check_business_partners
IMPORTING
business_partners TYPE business_partners
EXPORTING
result TYPE result_type
failed_keys TYPE /bobf/t_frw_key
messages TYPE /bobf/t_frw_message. " çoklu EXPORTING kafa karıştırıcı
💡 Uzman Yorumu: RETURNING ile tek nesne döndürmek, method chaining'i mümkün kılar ve IS SUPPLIED kontrollerini ortadan kaldırır. Birden fazla EXPORTING parametresi genellikle metodun çok fazla şey yaptığının işaretidir.
13.14 RETURNING Tercih Edin Orijinal Kaynak
EXPORTING yerine RETURNING kullanın. RETURNING çağrıyı daha kısa yapar, method chaining'e izin verir ve aynı giriş/çıkış hatalarını önler.
✓ İYİ KULLANIM
METHODS square
IMPORTING
number TYPE i
RETURNING
VALUE(result) TYPE i.
DATA(result) = square( 42 ).
✗ KÖTÜ KULLANIM
METHODS square
IMPORTING
number TYPE i
EXPORTING
result TYPE i.
square(
EXPORTING
number = 42
IMPORTING
result = DATA(result) ). " çok daha uzun ve okuması zor
💡 Uzman Yorumu: RETURNING ile değer ataması (result = square(42)) matematiksel notasyona yakındır ve okunması kolaydır. EXPORTING ile çağrı ise prosedürel bir görünüm sunar ve daha fazla satır kaplar.
13.15 Büyük Tablo Döndürmek Genellikle Sorun Değil Orijinal Kaynak
ABAP dil belgeleri aksini söylese de, büyük bir tabloyu VALUE parametresinde döndürmek nadiren gerçek performans sorunlarına yol açar. Kanıtlanmış bir sorun olmadıkça RETURNING kullanmaya devam edin.
✓ İYİ KULLANIM
METHODS get_large_table
RETURNING
VALUE(result) TYPE /clean/some_table_type.
DATA(my_table) = get_large_table( ).
💡 Uzman Yorumu: Kernel optimizasyonu RETURNING performansını büyük ölçüde iyileştirmiştir. Gerçek bir performans ölçümü yapmadan erken optimizasyon yapmayın. Okunabilirliği koruyun.
13.16 Tek Tip Kullanın Orijinal Kaynak
RETURNING, EXPORTING veya CHANGING'den birini kullanın ama kombinasyon yapmayın. Farklı türde çıktı parametreleri, metodun birden fazla şey yaptığının göstergesidir.
✓ İYİ KULLANIM
METHODS copy_class
IMPORTING
old_name TYPE seoclsname
new_name TYPE seoclsname
RETURNING
VALUE(result) TYPE copy_result
RAISING
/clean/class_copy_failure.
✗ KÖTÜ KULLANIM
METHODS copy_class
...
RETURNING
VALUE(result) TYPE vseoclass
EXPORTING
error_occurred TYPE abap_bool
CHANGING
correction_request TYPE trkorr
package TYPE devclass. " üç farklı çıktı tipi - ne yapıyor bu metod?
💡 Uzman Yorumu: RETURNING, EXPORTING ve CHANGING'i karıştırmak çağıranın kafasını karıştırır. Çağıran ne beklediğini nasıl anlayacak? Tek tip seçin ve ona bağlı kalın.
13.17 CHANGING'i Tutumlu Kullanın Orijinal Kaynak
CHANGING'i yalnızca halihazırda dolu olan yerel bir değişkenin kısmi olarak güncellendiği durumlar için saklayın. Çağıranı yalnızca CHANGING parametrenizi beslemek için gereksiz yerel değişkenler oluşturmaya zorlamayın.
✓ İYİ KULLANIM
METHODS update_references
IMPORTING
new_reference TYPE /bobf/conf_key
CHANGING
bo_nodes TYPE root_nodes.
METHOD update_references.
LOOP AT bo_nodes REFERENCE INTO DATA(bo_node).
bo_node->reference = new_reference.
ENDLOOP.
ENDMETHOD.
💡 Uzman Yorumu: CHANGING, önceden dolu bir değişkeni kısmen güncelleme için doğaldır; örneğin bir tablo üzerinde döngü yaparak bazı alanları güncelleme. Boş bir değişkeni doldurmak için CHANGING kullanmayın; bunun için RETURNING daha uygun.
13.18 Boolean Giriş Yerine Metodu Bölün Orijinal Kaynak
Boolean giriş parametreleri genellikle metodun iki şey yaptığının göstergesidir. Metodu bölmek hem kodu basitleştirir hem de farklı niyetleri daha iyi anlatır.
✓ İYİ KULLANIM
update_without_saving( ).
update_and_save( ).
✗ KÖTÜ KULLANIM
METHODS update
IMPORTING
do_save TYPE abap_bool.
update( abap_true ). " 'true' ne demek? senkron mu? simüle mi? commit mi?
💡 Uzman Yorumu: Boolean parametreler çağrıyı anlamsızlaştırır: update( abap_true ) - bu true ne demek? Ayrı metodlar her birinin ne yaptığını adıyla açıklar.
13.19 RESULT Adını Düşünün Orijinal Kaynak
RETURNING parametresini basitçe RESULT olarak adlandırın. Bu, parametre adının metod adını tekrar etmesini önler ve isim çakışmalarını ortadan kaldırır.
✓ İYİ KULLANIM
METHODS get_name
RETURNING
VALUE(result) TYPE string.
METHOD get_name.
result = name. " me->name çakışması yok
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHODS get_name
RETURNING
VALUE(name) TYPE string.
METHOD get_name.
name = me->name. " me-> eklemek zorunda kalıyorsunuz
ENDMETHOD.
💡 Uzman Yorumu: RESULT, RETURNING parametresi için evrensel bir standarttır. İsim çakışmalarını önler ve metodun ne döndürdüğünü açıkça ifade eder.
13.20 EXPORTING Parametrelerini Temizleyin Orijinal Kaynak
Referans parametreleri önceden dolu bellek alanlarına işaret eder. CLEAR veya üzerine yazma ile güvenilir veri sağlayın.
✓ İYİ KULLANIM
METHOD square.
CLEAR result. " önce temizle
" ...
ENDMETHOD.
METHOD square.
result = cl_abap_math=>square( 2 ). " ya da doğrudan üzerine yaz
ENDMETHOD.
💡 Uzman Yorumu: EXPORTING parametreleri referans yoluyla geçirildiğinden önceki değerleri taşıyabilir. CLEAR yapmadan işlemek, eski verilerin sonuca karışmasına yol açabilir.
13.21 Giriş ve Çıkış Aynı Olabilirse Dikkatli Olun Orijinal Kaynak
Bazı parametreler hem giriş hem çıkış olarak kullanılabilir. Bu durumda erken CLEAR, giriş değerini silip yanlış sonuçlara yol açabilir.
✗ KÖTÜ KULLANIM
METHOD square_dirty.
CLEAR result. " erken clear - value'yu siler!
result = number * number.
ENDMETHOD.
" Çağrı: aynı değişken hem giriş hem çıkış
square_dirty(
EXPORTING number = value
IMPORTING result = value ). " değer silinir, yanlış sonuç
💡 Uzman Yorumu: Bu tür metodları RETURNING kullanacak şekilde yeniden tasarlayın. RETURNING parametreleri her zaman yeni bir bellek alanı kullanır, bu nedenle bu sorun ortaya çıkmaz.
13.22 VALUE Parametrelerini Temizlemeyin Orijinal Kaynak
VALUE parametreleri yeni, ayrı bellek alanları olarak geçirilir; başlangıçta boşturlar. Yeniden temizlemeye gerek yoktur.
✓ İYİ KULLANIM
METHODS square
RETURNING
VALUE(result) TYPE i.
METHOD square.
" result'ı temizlemeye gerek yok - zaten boş
ENDMETHOD.
💡 Uzman Yorumu: RETURNING parametreleri her zaman VALUE parametresidir ve başlangıçta boştur. Gereksiz CLEAR ifadeleri kodu karmaşıklaştırır ve yanlış bir izlenim yaratır.
13.23 Bir Şey Yapın Orijinal Kaynak
Bir metod tek bir şey yapmalı ve bunu olabildiğince iyi yapmalıdır. Bir metodun tek bir şey yaptığını gösteren işaretler: az giriş parametresi, Boolean parametre yok, tam olarak bir çıktı, küçük boyut, tek soyutlama seviyesi.
✓ İYİ KULLANIM
METHOD read_and_parse_version_filters.
DATA(active_model_version) = read_random_version_under( model_guid ).
DATA(filter_json) = read_model_version_filters( active_model_version-guid ).
result = parse_model_version_filters( filter_json ).
ENDMETHOD. " 3 ifade, tek amaca hizmet ediyor
💡 Uzman Yorumu: "Single Responsibility Principle" metodlar için de geçerlidir. Bir metodu ne yaptığını tek bir cümleyle açıklayabiliyorsanız, muhtemelen doğru yoldasınız. "Ve ayrıca..." eklemek zorunda kalıyorsanız, refactor zamanı.
13.24 Mutlu Yol veya Hata Yönetimi Orijinal Kaynak
Bir metod ya mutlu yolu (başarılı akış) ya da hata işlemeyi takip etmeli, muhtemelen ikisini birden değil. Doğrulama mantığını ayrı bir metoda taşıyın.
✓ İYİ KULLANIM
METHOD append_xs.
validate( input ). " hata işleme ayrı metodda
DATA(remainder) = input.
WHILE remainder > 0.
result = result && `X`.
remainder = remainder - 1.
ENDWHILE.
ENDMETHOD.
METHOD validate.
IF input = 0.
RAISE EXCEPTION /dirty/sorry_cant_do( ).
ELSEIF input < 0.
RAISE EXCEPTION cx_sy_illegal_argument( ).
ENDIF.
ENDMETHOD.
💡 Uzman Yorumu: Mutlu yol kodu ile hata işleme kodunu karıştırmak, her ikisini de anlaşılmaz kılar. Ayrı metodlara bölmek her iki bölümü de daha net yapar.
13.25 Bir Soyutlama Seviyesi Orijinal Kaynak
Metottaki ifadeler, metodun kendisinin bir seviye altında olmalıdır. Tüm ifadeler aynı soyutlama seviyesinde olmalıdır.
✓ İYİ KULLANIM
METHOD create_and_publish.
post = create_post( user_input ). " her ikisi de yüksek seviye
post->publish( ).
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD create_and_publish.
post = NEW blog_post( ).
DATA(user_name) = trim( to_upper( sy-uname ) ). " düşük seviye detay
post->set_author( user_name ). " karışık seviyeler
post->publish( ). " yüksek seviye
ENDMETHOD.
💡 Uzman Yorumu: Karma soyutlama seviyeleri okuyucuyu "bu neden burada?" diye merak ettirir. Yüksek seviye metod, yüksek seviye operasyonları çağırmalı; detaylar alt metodlara taşınmalıdır.
13.26 Metodları Küçük Tutun Orijinal Kaynak
Metodlar 20 ifadeden az olmalı; ideal olarak 3-5 ifade. Büyük metodlar genellikle birden fazla şey yapıyor demektir.
💡 Uzman Yorumu: Yüzlerce satırlık bir metodun DATA bildirim bloğu bile tek başına metodun ne kadar fazla şey yaptığını ortaya koyar. Küçük metodlar daha kolay anlaşılır, test edilir ve bakımı yapılır.
13.27 Hızlı Başarısız Olun Orijinal Kaynak
Doğrulama yapın ve olabildiğince erken başarısız olun. Geç doğrulamalar anlamak zordur ve kaynakları boşa harcamış olabilir.
✓ İYİ KULLANIM
METHOD do_something.
IF input IS INITIAL.
RAISE EXCEPTION cx_sy_illegal_argument( ). " erken doğrulama
ENDIF.
DATA(massive_object) = build_expensive_object_from( input ).
result = massive_object->do_some_fancy_calculation( ).
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD do_something.
DATA(massive_object) = build_expensive_object_from( input ). " pahalı işlem önce
IF massive_object IS NOT BOUND. " geç doğrulama
RAISE EXCEPTION cx_sy_illegal_argument( ).
ENDIF.
result = massive_object->do_some_fancy_calculation( ).
ENDMETHOD.
💡 Uzman Yorumu: Erken doğrulama hem kaynakları korur hem de hata nedeni daha açık olur. Geç doğrulamada "neden burada hata veriyor?" sorusunun cevabı daha belirsizdir.
CHECK vs RETURN Orijinal Kaynak
CHECK veya RETURN kullanıp kullanmayacağınız konusunda toplulukta fikir birliği yoktur. RETURN daha açıkken, CHECK daha kısadır. İkisini de kasıtlı kullanın.
✓ İYİ KULLANIM - RETURN daha açık
METHOD read_customizing.
IF keys IS INITIAL.
RETURN. " ne olduğu açık: metoddan çıkıyoruz
ENDIF.
" asıl işlem
ENDMETHOD.
" veya CHECK ile daha kısa
METHOD read_customizing.
CHECK keys IS NOT INITIAL. " koşul sağlanmazsa çık
" asıl işlem
ENDMETHOD.
💡 Uzman Yorumu: CHECK ifadesi daha kısa ama adı ne olduğunu açıklamaz. RETURN ile IF/ENDIF bloğu daha uzun ama daha açıktır. Ekibinizde bir konvansiyona karar verin ve tutarlı kalın.
CHECK'i Diğer Yerlerde Kullanmaktan Kaçının Orijinal Kaynak
CHECK'i metodun başlatma bölümünün dışında kullanmayın. LOOP içinde CHECK farklı davranır (sadece o yinelemeyi sonlandırır) ve bu beklenmedik etkilere yol açabilir.
✗ KÖTÜ KULLANIM
LOOP AT table INTO DATA(row).
CHECK row-key = 'A'. " LOOP içinde sadece o yinelemeyi atlar, metoddan çıkmaz!
process( row ).
ENDLOOP.
✓ İYİ KULLANIM
LOOP AT table INTO DATA(row).
IF row-key <> 'A'.
CONTINUE. " açık: bu yinelemeyi atla
ENDIF.
process( row ).
ENDLOOP.
💡 Uzman Yorumu: CHECK'in LOOP içindeki davranışı, metod başında kullanımından farklıdır. Bu davranış farkını bilmeyen okuyucuyu yanıltır. CONTINUE açık ve belirsizlik taşımaz.
14. Hata Yönetimi
Mesajları Bulmayı Kolaylaştırın Orijinal Kaynak
SE91 transaction'ından where-used araması yaparak mesajları kolayca bulabilmek için aşağıdaki deseni kullanın.
✓ İYİ KULLANIM
MESSAGE e001(ad) INTO DATA(message).
MESSAGE e001(ad) INTO DATA(message) ##NEEDED. " değişken kullanılmıyorsa
✗ KÖTÜ KULLANIM
IF 1 = 2. MESSAGE e001(ad). ENDIF.
" Ulaşılamaz kod içeriyor ve where-used aramasında bulunamaz
💡 Uzman Yorumu: Mesajların where-used aramasında bulunabilmesi, hangi programların hangi mesajları kullandığını anlamak için kritiktir. Erişilemeyen kodda gizli mesajlar bu imkânı ortadan kaldırır.
14.2 Exception Tercih Edin Orijinal Kaynak
Dönüş kodu yerine exception kullanın. Exception'lar metod imzalarını temiz tutar, çağıran hemen tepki vermek zorunda kalmaz ve hata detayları taşıyabilir.
✓ İYİ KULLANIM
METHOD try_this_and_that.
RAISE EXCEPTION NEW cx_failed( ).
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD try_this_and_that.
error_occurred = abap_true. " dönüş kodu olarak boolean
ENDMETHOD.
" Çağıran bu bayrağı kontrol etmeyi unutabilir!
💡 Uzman Yorumu: Dönüş kodları sessizce görmezden gelinebilir. Exception'lar ise çağıranı sözdizimsel olarak tepki vermeye (ya da açıkça iletmeye) zorlar. Bu, hataların kaybolmasını önler.
14.3 Başarısızlıkların Gözden Kaçmasına İzin Vermeyin Orijinal Kaynak
Dönüş kodu kullanmak zorundaysanız (eski fonksiyon modülleri gibi), hataların gözden kaçmasına izin vermeyin. Kontrol edin ve exception'a dönüştürün.
✓ İYİ KULLANIM
CALL FUNCTION 'BAPI_GET_CURRENT_DATE'
IMPORTING
current_date = current_date
CHANGING
response = response.
IF response-type = 'E'.
RAISE EXCEPTION NEW /clean/some_error( ). " dönüş kodunu exception'a çevir
ENDIF.
💡 Uzman Yorumu: Eski BAPI'lar genellikle BAPIRET2 tablosu veya TYPE alanı döndürür. Bu kontrolleri her seferinde unutmak kolaydır. Bir helper metod oluşturun ve BAPI çağrılarını hep orada yapın.
14.4 Exception'lar Hatalar İçindir Orijinal Kaynak
Exception'ları yalnızca beklenmedik hata durumları için kullanın. Normal, geçerli durumlar için normal dönüş parametrelerini kullanın.
✓ İYİ KULLANIM
" Normal durum: Boolean döndür
METHODS entry_exists_in_db
IMPORTING
key TYPE char10
RETURNING
VALUE(result) TYPE abap_bool.
" Hata durumu: exception fırlat
METHODS assert_user_input_is_valid
IMPORTING
user_input TYPE string
RAISING
cx_bad_user_input.
✗ KÖTÜ KULLANIM
METHODS entry_exists_in_db
IMPORTING
key TYPE char10
RAISING
cx_not_found_exception. " "bulunamadı" normal bir durumdur, hata değil!
💡 Uzman Yorumu: Exception kullanmak hem performans maliyeti (exception nesnesi oluşturma) hem de semantik bir maliyete yol açar. Okuyucu exception gördüğünde "bir şeyler yanlış gitti" anlar. Normal durumlar için bunu kullanmak yanıltıcıdır.
14.5 Class Tabanlı Exception Kullanın Orijinal Kaynak
Sınıf tabanlı exception kullanın. Eski sınıf dışı exception'lar dönüş kodlarıyla aynı özelliklere sahiptir ve artık kullanılmamalıdır.
✓ İYİ KULLANIM
TRY.
get_component_types( ).
CATCH cx_has_deep_components_error.
ENDTRY.
✗ KÖTÜ KULLANIM
get_component_types(
EXCEPTIONS
has_deep_components = 1
OTHERS = 2 ). " eski stil - dönüş kodu gibi çalışır
💡 Uzman Yorumu: Eski EXCEPTIONS sözdizimi kullanıldığında sy-subrc'yi kontrol etmek zorundasınız; yoksa hata sessizce kaybolur. TRY/CATCH ile hataları yakalamak ya da iletmek zorunda kalırsınız.
14.6 Kendi Üst Sınıflarınızı Kullanın Orijinal Kaynak
Her exception tipi için soyut üst sınıflar oluşturun; temel sınıfları doğrudan alt sınıflamak yerine. Bu, "tüm uygulamaya özgü exception'ları" yakalamayı sağlar.
✓ İYİ KULLANIM
CLASS cx_fra_static_check DEFINITION ABSTRACT INHERITING FROM cx_static_check.
CLASS cx_fra_no_check DEFINITION ABSTRACT INHERITING FROM cx_no_check.
💡 Uzman Yorumu: ABSTRACT, geliştiricilerin açıklayıcı olmayan bu üst sınıfları doğrudan kullanmasını önler. Tüm uygulama exception'larını tek CATCH bloğunda yakalama imkânı sağlar.
14.7 Bir Tip Exception Fırlatın Orijinal Kaynak
Çoğu durumda birden fazla exception tipi fırlatmak gereksizdir. Çağıran genellikle bunların hepsini aynı şekilde ele alır. Tek bir üst tip kullanın ve alt sınıflarla durumlara izin verin.
✓ İYİ KULLANIM
METHODS generate
RAISING
cx_generation_error.
✗ KÖTÜ KULLANIM
METHODS generate
RAISING
cx_abap_generation
cx_hdbr_access_error
cx_model_read_error. " çağıran bunların hepsini farklı mı işleyecek?
💡 Uzman Yorumu: Birden fazla exception tipi, çağırana "bunları farklı işleyebilirsin" demektir. Eğer çağıran bunların hepsini aynı şekilde işleyecekse, tek tip yeterlidir.
14.8 Alt Sınıflarla Hata Durumlarını Ayırt Edin Orijinal Kaynak
Tek exception üst tipi kullanın ama alt sınıflarla ayrımı isteğe bağlı olarak mümkün kılın. Bu, çağıranın gerekirse ayrım yapmasına izin verirken zorlamaz.
✓ İYİ KULLANIM
CLASS cx_bad_generation_variable DEFINITION INHERITING FROM cx_generation_error.
CLASS cx_bad_code_composer_template DEFINITION INHERITING FROM cx_generation_error.
TRY.
generator->generate( ).
CATCH cx_bad_generation_variable.
log_failure( ).
CATCH cx_bad_code_composer_template INTO DATA(bad_template_exception).
show_error_to_user( bad_template_exception ).
CATCH cx_generation_error INTO DATA(other_exception).
RAISE EXCEPTION NEW cx_application_error( previous = other_exception ).
ENDTRY.
💡 Uzman Yorumu: Bu desen, Java'nın checked/unchecked exception hiyerarşisine benzer. Üst sınıf hepsini yakalar; alt sınıflar özel durumlara izin verir. En iyi tasarım esnekliği bu şekilde sağlanır.
14.9 CX_STATIC_CHECK Kullanın Orijinal Kaynak
Yönetilebilir exception'lar için (kullanıcı giriş doğrulaması, alternatifi olan eksik kaynak) CX_STATIC_CHECK'ten türetin. Bu tip metod imzasında belirtilmeli ve yakalanmalı ya da iletilmelidir.
✓ İYİ KULLANIM
CLASS cx_file_not_found DEFINITION INHERITING FROM cx_static_check.
METHODS read_file
IMPORTING
file_name_enterd_by_user TYPE string
RAISING
cx_file_not_found.
💡 Uzman Yorumu: CX_STATIC_CHECK sözdizimi hatası olmadan geçilemez, bu nedenle çağıranlar exception'ı kabul etmek zorundadır. Bu, hata durumlarını açıkça ele almayı zorunlu kılar.
14.10 CX_NO_CHECK Kullanın Orijinal Kaynak
Genellikle kurtarılamaz durumlar için (zorunlu kaynağa erişim başarısızlığı, çözülemez bağımlılık) CX_NO_CHECK kullanın. Bu tip metod imzasında belirtilmez.
✓ İYİ KULLANIM
CLASS cx_out_of_memory DEFINITION INHERITING FROM cx_no_check.
METHODS create_guid
RETURNING
VALUE(result) TYPE /bobf/conf_key.
" cx_out_of_memory imzada yok - kurtarılamaz bir durum
💡 Uzman Yorumu: CX_NO_CHECK, bellek yetersizliği gibi kurtarılamaz durumlar için tasarlanmıştır. Bu exception'ların imzada görünmemesi kasıtlıdır; çağıranın yapabileceği bir şey yoktur.
14.11 CX_DYNAMIC_CHECK Kullanın Orijinal Kaynak
CX_DYNAMIC_CHECK için kullanım alanları nadirdir. Çağıranın bir exception'ın ortaya çıkıp çıkmayacağını tam ve bilinçli olarak kontrol edebildiği durumlarda CX_STATIC_CHECK yerine düşünün.
💡 Uzman Yorumu: CX_DYNAMIC_CHECK, çalışma zamanında kontrol edilen ama derleme zamanında zorunlu olmayan exception'lar içindir. Çok nadir kullanılır; çoğu durumda CX_STATIC_CHECK veya CX_NO_CHECK daha uygun seçenektir.
14.12 Dump Yapın Orijinal Kaynak
Durum o kadar ağırsa ki alıcının kurtarma imkânı kesinlikle yoksa (bellek tahsisi başarısızlığı, kesinlikle dolu olması gereken tablo okuma başarısızlığı gibi) dump yapın.
✓ İYİ KULLANIM
RAISE SHORTDUMP TYPE cx_sy_create_object_error. " NW 7.53 ve üzeri
MESSAGE x666(general). " NW 7.53 öncesi
💡 Uzman Yorumu: Dump, son çare olmalıdır. Sistem durumu o kadar bozuktur ki devam etmek daha büyük sorunlara yol açabilir. Bunu yalnızca programlama hatası veya tamamen kurtarılamaz sistem hataları için kullanın.
14.13 RAISE EXCEPTION NEW Tercih Edin Orijinal Kaynak
NW 7.52 ve üzeri sürümlerde RAISE EXCEPTION TYPE yerine RAISE EXCEPTION NEW kullanın. Daha kısadır.
✓ İYİ KULLANIM
RAISE EXCEPTION NEW cx_generation_error( previous = exception ).
✗ KÖTÜ KULLANIM
RAISE EXCEPTION TYPE cx_generation_error
EXPORTING
previous = exception. " gereksiz uzun
💡 Uzman Yorumu: MESSAGE eklentisini yoğun kullanıyorsanız TYPE varyantı daha uygun olabilir. Aksi takdirde NEW varyantı her zaman tercih edilmelidir.
14.14 Yabancı Exception'ları Sarın Orijinal Kaynak
Diğer bileşenlerden gelen exception'ları iletmek yerine, kendinize ait exception tipinde sarın. Bu, Demeter yasasına uyum sağlar ve bağımlılıkları azaltır.
✓ İYİ KULLANIM
METHODS generate RAISING cx_generation_failure.
METHOD generate.
TRY.
generator->generate( ).
CATCH cx_amdp_generation_failure INTO DATA(exception).
RAISE EXCEPTION NEW cx_generation_failure( previous = exception ).
ENDTRY.
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHODS generate RAISING cx_sy_gateway_failure.
" cx_sy_gateway_failure başka bileşene ait - kodunuza yabancı element giriyor
💡 Uzman Yorumu: Yabancı exception'ları doğrudan iletmek, çağıranın o bileşen hakkında bilgi sahibi olmasını gerektirir. Bu, katmanlar arası bağımlılık yaratır. Sarma işlemi sizi o bağımlılıktan izole eder.
15. Yorumlar
15.1 Kodda İfade Edin Orijinal Kaynak
Yorumların söyleyeceği şeyi kod aracılığıyla söyleyin. Kodu mümkün olduğunca açık ve anlaşılır yapın.
✓ İYİ KULLANIM
METHOD correct_day_to_last_in_month.
WHILE is_invalid( date ).
reduce_day_by_one( CHANGING date = date ).
ENDWHILE.
ENDMETHOD.
✗ KÖTÜ KULLANIM
" correct e.g. 29.02. in non-leap years as well as result of a date calculation would be
" something like the 31.06. that has to be corrected to 30.06.
METHOD fix_day_overflow.
DO 3 TIMES.
lv_dummy = cv_date.
IF ( lv_dummy EQ 0 ).
cv_date+6(2) = cv_date+6(2) - 1.
ELSE.
EXIT.
ENDIF.
ENDDO.
ENDMETHOD. " yorum gerekirken kod bozuk - kodu düzeltin
💡 Uzman Yorumu: Clean Code yorumu yasaklamaz; daha iyi alternatifleri kullanmayı teşvik eder. Eğer kod açıklama gerektiriyorsa, önce kodu daha açık hale getirmeyi deneyin.
15.2 Yorumlar Kötü İsimlerin Mazereti Değil Orijinal Kaynak
İsimleri açıklamak yerine isimleri iyileştirin. Yorumlar kötü isimlendirmenin geçici bir yamadır.
✓ İYİ KULLANIM
DATA(input_has_entries) = has_entries( input ).
✗ KÖTÜ KULLANIM
" checks whether the table input contains entries
DATA(result) = check_table( input ). " yorum gerekiyorsa isim kötü
💡 Uzman Yorumu: Yorum, değişken veya metod adının yetersizliğini gizler. İsmi açıklayan bir yorumunuz varsa, yorumu silin ve ismi düzeltin.
15.3 Metod Kullanın, Yorum Değil Orijinal Kaynak
Kodu bölümlere ayırmak için yorum yerine metodlar kullanın. Metodlar amacı, yapıyı ve bağımlılıkları çok daha açık şekilde ortaya koyar.
✓ İYİ KULLANIM
DATA(statement) = build_statement( ).
DATA(data) = execute_statement( statement ).
✗ KÖTÜ KULLANIM
" -----------------
" Build statement
" -----------------
DATA statement TYPE string.
statement = |SELECT * FROM d_document_roots|.
" -----------------
" Execute statement
" -----------------
DATA(result_set) = adbc->execute_sql_query( statement ).
result_set->next_package( IMPORTING data = data ).
💡 Uzman Yorumu: Kodunuzda başlık yorumları yazma ihtiyacı hissediyorsanız, bu bölümleri ayrı metodlara çıkarmanın zamanı gelmiş demektir. Metodlar yorumlardan daha güçlüdür: test edilebilir ve yeniden kullanılabilirler.
15.4 Neden Yorum Yazın Orijinal Kaynak
Ne yaptığınızı değil, neden yaptığınızı açıklayan yorumlar yazın. Kod "ne" yaptığını zaten söyler; "neden" ise arka planı, kısıtlamaları veya iş gereksinimini açıklar.
✓ İYİ KULLANIM
" can't fail, existence of >= 1 row asserted above
DATA(first_line) = table[ 1 ].
✗ KÖTÜ KULLANIM
" select alert root from database by key
SELECT * FROM d_alert_root WHERE key = key. " kod zaten bunu söylüyor
💡 Uzman Yorumu: "Neden" yorumu gelecekteki geliştiriciye bağlamı verir. "Neden bu yol seçildi?", "Bu neden önemli?", "Bu yaklaşımın neden sınırlılıkları var?" gibi sorulara cevap verir.
15.5 Tasarım Belgeye Gider Orijinal Kaynak
Tasarım kararları ve mimariye ilişkin uzun açıklamalar koda değil, tasarım belgelerine aittir. Kodu okumak için kitap okumak zorunda kalınmamalıdır.
💡 Uzman Yorumu: Uzun yorum blokları genellikle kimse tarafından okunmaz. Eğer tasarım belgesi gerekiyorsa, wikide veya SharePoint'te oluşturun ve kodda bağlantı verin.
15.6 " ile Yorum Yapın Orijinal Kaynak
Yorum satırları için * yerine " kullanın. Tırnak yorumları yanındaki ifadelerle birlikte girintilenir; yıldız yorumlar ise garip yerlere girintilenir.
✓ İYİ KULLANIM
METHOD do_it.
IF input IS NOT INITIAL.
" delegate pattern
output = calculate_result( input ).
ENDIF.
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD do_it.
IF input IS NOT INITIAL.
* delegate pattern " * garip bir yere girintiledi
output = calculate_result( input ).
ENDIF.
ENDMETHOD.
💡 Uzman Yorumu: Tırnak yorumlar koda yapışır ve birlikte girintilenebilir. Yıldız yorumlar her zaman satır başında kalır, bu da girintileme tutarsızlığı yaratır.
15.7 Yorumu İfadenin Önüne Koyun Orijinal Kaynak
İlişkili olduğu ifadenin önüne yorum koyun, arkasına değil. Önceki yorum, "neyi" açıklar; sonraki yorum neyle ilgili olduğunu belirsiz kılar.
✓ İYİ KULLANIM
" delegate pattern
output = calculate_result( input ).
✗ KÖTÜ KULLANIM
output = calculate_result( input ).
" delegate pattern " hangi ifadeyle ilgili? önceki mi, sonraki mi?
output = calculate_result( input ). " delegate pattern " satır sonu yorum - karışık
💡 Uzman Yorumu: Yorum, açıkladığı ifadeden önce gelmelidir. Bu, okuyucunun kodu önce anlamasını, sonra yorumu okumasını sağlar; neyin açıklandığı her zaman bellidir.
15.8 Kodu Silin, Yorum Haline Getirmeyin Orijinal Kaynak
Yorum haline getirilmiş kodu silin. Uygulama çalışıyor ve testler yeşilse, bu kod açıkça gerekli değil demektir. Gerekirse versiyonlama geçmişinden geri getirilir.
✗ KÖTÜ KULLANIM
* output = calculate_result( input ). " bu kod neden burada? güvenli mi silmek?
💡 Uzman Yorumu: Yorum haline getirilmiş kod şunu söyler: "Bunu silmek korktum." Versiyon kontrol sisteminize güvenin. Kod her zaman geçmişte mevcut olacak.
15.9 Manuel Versiyonlama Yapmayın Orijinal Kaynak
Kodda ticket/kullanıcı açıklama yorumları eklemeyin. Versiyonlama zaten versiyon kontrol sistemi tarafından yapılıyor.
✗ KÖTÜ KULLANIM
* ticket 800034775 ABC ++ Start
output = calculate_result( input ).
* ticket 800034775 ABC ++ End " versiyon kontrol sistemi bunu zaten biliyor
💡 Uzman Yorumu: Atıf yorumları kodu kirletir ve gerçek bir değer katmaz. Transport order notları neden bir şeyin değiştirildiğini açıklamak için çok daha uygun bir yerdir.
15.10 FIXME, TODO, XXX Kullanın Orijinal Kaynak
Geçici sorunları belirtmek için tanınmış etiketleri kullanın ve kendi kimliğinizi ekleyin. Bu, soruların kime yöneltileceğini belirler.
✓ İYİ KULLANIM
METHOD do_something.
" XXX FH delete this method - it does nothing
" TODO AB refactor this when ticket #1234 is resolved
" FIXME MK this crashes with empty input - bug #5678
ENDMETHOD.
💡 Uzman Yorumu: FIXME = düzeltilmesi gereken hata, TODO = yakın gelecekte yapılacak iş, XXX = çalışıyor ama daha iyi olabilir. Kimlik eklemeyi unutmayın: soruları kime yönelteceğinizi bilmek önemlidir.
15.11 Metod İmzası ve Son Yorumları Eklemeyin Orijinal Kaynak
Metod imzası yorumları veya ENDIF/ENDMETHOD yorumları eklemeyin. Modern IDE'ler bu bilgiyi kolayca gösterir.
✗ KÖTÜ KULLANIM
* <SIGNATURE>
* | Static Public Method CALIBRATION_KPIS=>CALCULATE_KPI
* | [->] STRATEGY_ID TYPE STRATEGY_ID
* | [<-] KPI TYPE T_SIMULATED_KPI
* </SIGNATURE>
METHOD get_kpi_calc.
IF has_entries = abap_false.
result = 42.
ENDIF. " IF has_entries = abap_false " gereksiz
ENDMETHOD. " get_kpi_calc " gereksiz
💡 Uzman Yorumu: ADT'de F2, SE24'te Signature düğmesi ile metod imzasına anında erişebilirsiniz. Bu yorumlar eski dönemin eserleriydi; şimdi sadece gürültü.
15.12 Mesaj Metinlerini Kopyalamayın Orijinal Kaynak
Mesaj metinlerini yorum olarak kopyalamayın. Mesajlar koddan bağımsız olarak değişir ve yorum hızla eskiyerek yanıltıcı hale gelir.
✗ KÖTÜ KULLANIM
" alert category not filled " yarın bu mesaj değişecek ama yorum kalmaya devam eder
MESSAGE e003 INTO dummy.
💡 Uzman Yorumu: ADT'de mesaj ID'si üzerine tıklayarak mesaj metnini anında görebilirsiniz. Yorumlar güncellenmez; mesaj metin deposu ise güncellenir. Kopyalamak yerine araca güvenin.
15.13 ABAP Doc Sadece Public API İçin Orijinal Kaynak
ABAP Doc'u yalnızca public API'ları belgelemek için yazın; iç yapı için değil. ABAP Doc tüm yorumlar gibi hızla eskir ve yanıltıcı hale gelebilir.
💡 Uzman Yorumu: ABAP Doc, Javadoc gibi API tüketicilerine yönelik belgeleme sağlar. Ancak her sınıf ve metoda yazmak, bakımı zor eski belgeleme yığını oluşturur. Yalnızca gerçekten public API için kullanın.
15.14 Pragma Tercih Edin Orijinal Kaynak
ATC tarafından tanımlanan ilgisiz uyarıları bastırmak için pseudo yorum yerine pragma kullanın. Pseudo yorumlar büyük ölçüde eski ve pragmalarla değiştirilmiştir.
✓ İYİ KULLANIM
MESSAGE e001(ad) INTO DATA(message) ##NEEDED.
✗ KÖTÜ KULLANIM
MESSAGE e001(ad) INTO DATA(message). "#EC NEEDED " eski stil pseudo yorum
💡 Uzman Yorumu: ABAP_SLIN_PRAGMAS programını veya SLIN_DESC tablosunu kullanarak eski pseudo yorumlar ile karşılık gelen pragmalar arasındaki eşlemeyi bulabilirsiniz.
16. Biçimlendirme
16.1 Tutarlı Olun Orijinal Kaynak
Bir projenin tüm kodunu aynı şekilde biçimlendirin. Yabancı koda dokunduğunuzda, o projenin biçimlendirme stiline uyun; kendi kişisel stilinizi dayatmayın.
💡 Uzman Yorumu: Tutarsız biçimlendirme, "bu neden farklı?" sorusunu gündeme getirir ve okuyucuyu anlamlı bir fark olduğunu düşündürür. Tutarlılık dikkat dağıtmadan koda odaklanmayı sağlar.
16.2 Okumak İçin Optimize Edin Orijinal Kaynak
Geliştiriciler zamanlarının çoğunu kod okuyarak geçirir. Kod yazmak günün çok küçük bir bölümünü kaplar. Bu nedenle okuma ve hata ayıklama için optimize edin, yazma için değil.
✓ İYİ KULLANIM
DATA:
a TYPE b,
c TYPE d,
e TYPE f.
✗ KÖTÜ KULLANIM
DATA:
a TYPE b
,c TYPE d
,e TYPE f. " virgülü başa koymak yazmayı kolaylaştırır ama okumayı zorlaştırır
💡 Uzman Yorumu: "Yazmayı kolaylaştırmak" için yapılan biçimlendirme hacks'leri, okumayı zorlaştırır. Her kod satırı onlarca kez okunur ama yalnızca bir kez yazılır.
16.3 ABAP Formatter Kullanın Orijinal Kaynak
Aktifleştirmeden önce ABAP Formatter'ı uygulayın (SE80/SE24'te Shift+F1, ADT'de Pretty Printer). Biçimlenmemiş büyük legacy kodlarda yalnızca seçili satırlara uygulamayı düşünün.
💡 Uzman Yorumu: Formatter'ı seçici kullanmak büyük diff'lerin oluşmasını önler. Legacy kodu bütünüyle formatlamak istiyorsanız, bunu ayrı bir transport request'te yapın.
16.4 Takım Ayarlarını Kullanın Orijinal Kaynak
Her zaman takımınızın ABAP Formatter ayarlarını kullanın. Büyük harf/küçük harf tercihlerini ve girinti ayarlarını proje düzeyinde belirleyin.
💡 Uzman Yorumu: ADT'de proje bazlı formatter ayarları yapabilirsiniz. Bu, tüm ekip üyelerinin aynı biçimlendirmeyi kullanmasını otomatik sağlar ve "büyük harf mi küçük harf mi?" tartışmalarını önler.
16.5 Satır Başına Bir İfade Orijinal Kaynak
Her satıra yalnızca bir ifade yazın. Birden fazla ifadeyi tek satırda birleştirmek okumayı ve hata ayıklamayı zorlaştırır.
✓ İYİ KULLANIM
DATA do_this TYPE i.
do_this = input + 3.
✗ KÖTÜ KULLANIM
DATA do_this TYPE i. do_this = input + 3. " iki ifade, bir satır
💡 Uzman Yorumu: Birden fazla ifadeyi tek satırda birleştirmek, debugger ile adım adım ilerlerken hangi ifadenin çalıştırıldığını belirsiz kılar. Her satırda tek ifade bu sorunu ortadan kaldırır.
16.6 Makul Satır Uzunluğu Orijinal Kaynak
Maksimum 120 karakter satır uzunluğuna uyun. İnsan gözü çok geniş satırları okumakta zorlanır. ADT'de 120 karakter sınırını görsel çizgi olarak yapılandırabilirsiniz.
💡 Uzman Yorumu: 80 karakter sınırı eski terminal döneminden gelir ve ABAP için çok kısıtlayıcıdır. ABAP'ın yapısal sözdizimi göz önüne alındığında 120 karakter daha pratiktir.
16.7 Kodu Yoğunlaştırın Orijinal Kaynak
Gereksiz boşluk eklemeyerek kodu yoğunlaştırın. Gereksiz boşluklar okumayı zorlaştırır ve gürültü ekler.
✓ İYİ KULLANIM
DATA(result) = calculate( items ).
✗ KÖTÜ KULLANIM
DATA(result) = calculate( items = items ) . " gereksiz boşluklar
💡 Uzman Yorumu: Hizalama amacıyla eklenen boşluklar, değişken adı uzunlukları değiştiğinde tüm satırları yeniden düzenlemenizi gerektirir. Bunu ABAP Formatter'a bırakın.
16.8 Tek Boş Satır Ekleyin Orijinal Kaynak
Farklı şeyleri birbirinden ayırmak için tek boş satır kullanın, birden fazla değil. Birden fazla boş satır gereksiz yere alanı kaplar.
✓ İYİ KULLANIM
DATA(result) = do_something( ).
DATA(else) = calculate_this( result ).
✗ KÖTÜ KULLANIM
DATA(result) = do_something( ).
DATA(else) = calculate_this( result ). " üç boş satır - gereksiz
💡 Uzman Yorumu: Çok fazla boş satır eklemek, metodun tek bir şey yapmadığının göstergesi olabilir. Boş satır ihtiyacı hissediyorsanız, o bölümü ayrı bir metoda çıkarmanın zamanı gelmiş olabilir.
16.9 Boş Satır Konusunda Obsesif Olmayın Orijinal Kaynak
Her ifadeyi boş satırlarla ayırma alışkanlığından kaçının. Birbirine ait ifadeler bir arada durmalı.
✓ İYİ KULLANIM
METHOD do_something.
do_this( ).
then_that( ).
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD do_something.
do_this( ).
then_that( ).
ENDMETHOD. " her ifade arasında boş satır - aşırı parçalama
💡 Uzman Yorumu: Boş satırlar anlam taşımalıdır: "bu ifadeler farklı bir şey yapıyor". Anlamsız boş satırlar dikkati dağıtır ve metodun ne kadar büyük göründüğünü yapay olarak artırır.
16.10 Aynı Nesneye Atamaları Hizalayın Orijinal Kaynak
Aynı nesneye ait atamaları hizalayın ama ilgisiz atamalar arasında hizalamaya gerek yok.
✓ İYİ KULLANIM
structure-type = 'A'.
structure-id = '4711'.
" ya da daha iyisi
structure = VALUE #( type = 'A'
id = '4711' ).
✗ KÖTÜ KULLANIM
customizing_reader = fra_cust_obj_model_reader=>s_get_instance( ).
hdb_access = fra_hdbr_access=>s_get_instance( ). " ilgisiz atamalar hizalanmış
💡 Uzman Yorumu: Hizalama görsel olarak ilişkiyi ortaya koyar. Aynı yapının alanları arasında hizalama anlamlıdır. İlgisiz atamalar arasında hizalama ise yanıltıcıdır.
16.11 Parantezleri Satır Sonunda Kapatın Orijinal Kaynak
Parantezleri satır sonunda kapatın; ayrı satırda değil. Ayrı satırda kapatılan parantez gereksizce kod uzunluğunu artırır.
✓ İYİ KULLANIM
modify->update( node = if_fra_alert_c=>node-item
key = item->key
data = item
changed_fields = changed_fields ).
✗ KÖTÜ KULLANIM
modify->update( node = if_fra_alert_c=>node-item
key = item->key
data = item
changed_fields = changed_fields
). " ayrı satırda kapanan parantez gereksiz
💡 Uzman Yorumu: Kapanan parantezi son parametrenin yanında bırakmak kodu daha kompakt tutar. Ayrı satırda kapatma yalnızca kodun daha uzun görünmesini sağlar ve bir değer katmaz.
16.12 Tek Parametreli Çağrıları Tek Satırda Tutun Orijinal Kaynak
Tek parametreli çağrıları tek satırda tutun. Gereksiz satır kırmaları okunabilirliği azaltır.
✓ İYİ KULLANIM
DATA(unique_list) = remove_duplicates( list ).
remove_duplicates( CHANGING list = list ).
✗ KÖTÜ KULLANIM
DATA(unique_list) = remove_duplicates(
CHANGING
list = list ). " tek parametre için gereksiz uzun
💡 Uzman Yorumu: Çok parametreli çağrılar için satır kırma mantıklıdır. Ama tek bir parametre için birden fazla satır kullanmak gereksiz alan israfıdır.
16.13 Parametreleri Çağrının Arkasında Tutun Orijinal Kaynak
Parametreleri mümkün olduğunda çağrının aynı satırında tutun. Satır çok uzarsa bir sonraki satıra taşıyın.
✓ İYİ KULLANIM
DATA(sum) = add_two_numbers( value_1 = 5
value_2 = 6 ).
DATA(sum) = add_two_numbers(
value_1 = round_up( input DIV 7 ) * 42 + round_down( 19 * step_size )
value_2 = VALUE #( ( `Calculation failed with a very weird result` ) ) ).
💡 Uzman Yorumu: Parametre çok uzunsa yeni satıra geçin ama yeni satır = yeni seviye girintileme demektir. Girinti, parametrelerin hangi metodun girdileri olduğunu açıkça göstermelidir.
16.14 Parametreleri Çağrının Altına Hizalayın Orijinal Kaynak
Satır kırıldığında parametreleri çağrının altına 4 boşlukla girintileyin.
✓ İYİ KULLANIM
DATA(sum) = add_two_numbers(
value_1 = 5
value_2 = 6 ).
✗ KÖTÜ KULLANIM
DATA(sum) = add_two_numbers(
value_1 = 5
value_2 = 6 ). " az girintileme hangi metoda ait olduğunu belirsiz kılar
💡 Uzman Yorumu: Yeterli girintileme, parametrelerin hangi metoda ait olduğunu görsel olarak gösterir. Az girintileme ise parametreleri bağımsız ifadeler gibi gösterir.
16.15 Çoklu Parametreleri Ayrı Satırlara Bölün Orijinal Kaynak
Birden fazla parametreyi ayrı satırlara bölün. Parametreleri aynı satırda sıralamak, birinin nerede bitip diğerinin nerede başladığını belirsiz kılar.
✓ İYİ KULLANIM
DATA(sum) = add_two_numbers( value_1 = 5
value_2 = 6 ).
✗ KÖTÜ KULLANIM
DATA(sum) = add_two_numbers( value_1 = 5 value_2 = 6 ). " parametre sınırları belirsiz
💡 Uzman Yorumu: Parametreler aynı satırda sıralandığında, özellikle değerler de ifade içeriyorsa, bir parametrenin nerede bitip diğerinin nerede başladığını anlamak çok zorlaşır.
16.16 Parametreleri Hizalayın Orijinal Kaynak
Parametreleri hizalayın. Bu, parametre adı ile değer arasındaki sınırı net gösterir.
✓ İYİ KULLANIM
modify->update( node = if_fra_alert_c=>node-item
key = item->key
data = item
changed_fields = changed_fields ).
✗ KÖTÜ KULLANIM
modify->update( node = if_fra_alert_c=>node-item
key = item->key
data = item
changed_fields = changed_fields ). " düzensiz kenar, okunması zor
💡 Uzman Yorumu: Hizalanmış parametreler tablo gibi görünür: ad sütunu ve değer sütunu. Bu düzenli yapı, bir bakışta tüm parametreleri ve değerlerini anlamayı kolaylaştırır.
16.17 Satır Çok Uzunsa Yeni Satıra Geçin Orijinal Kaynak
Satır çok uzarsa, atamayı yeni satıra alın ve metod çağrısını girintileyin.
✓ İYİ KULLANIM
DATA(some_super_long_param_name) =
if_some_annoying_interface~add_two_numbers_in_a_long_name(
value_1 = 5
value_2 = 6 ).
💡 Uzman Yorumu: Çok uzun değişken veya metod adları bazen satırı 120 karakteri aşmaya zorlar. Bu durumda atamayı bir satır, çağrıyı sonraki satırlara bölerek okunabilirliği koruyun.
16.18 Girintile ve Sekmeye Yapış Orijinal Kaynak
Parametre anahtar sözcüklerini 2 boşlukla, parametreleri 4 boşlukla girintileyin. Girintilemek için Tab tuşunu kullanın.
✓ İYİ KULLANIM
DATA(sum) = add_two_numbers(
EXPORTING
value_1 = 5
value_2 = 6
CHANGING
errors = errors ).
DATA(sum) = add_two_numbers(
value_1 = 5
value_2 = 6 ). " anahtar sözcük yoksa 4 boşluk
💡 Uzman Yorumu: Tutarlı girintileme kuralı öğrenildiğinde, kod yapısı zihinde otomatik olarak ayrıştırılır. Rastgele girintileme ise her seferinde aktif düşünme gerektirir.
16.19 Inline Bildirimleri Girintile Orijinal Kaynak
VALUE veya NEW ile inline bildirimlerini metod çağrısıymış gibi girintileyin.
✓ İYİ KULLANIM
DATA(result) = merge_structures( a = VALUE #( field_1 = 'X'
field_2 = 'A' )
b = NEW /clean/structure_type( field_3 = 'C'
field_4 = 'D' ) ).
💡 Uzman Yorumu: VALUE # ve NEW # yapıları görsel olarak metod çağrısına çok benzer. Aynı girintileme kurallarını uygulamak tutarlılığı sağlar ve kodu daha tahmin edilebilir kılar.
16.20 Tip Cümlelerini Hizalamayın Orijinal Kaynak
Değişken adları ve TYPE cümleleri arasında hizalama yapmayın. Değişken ve onun tipi birbirine yakın durmalı; aşırı hizalama bağı kopuk gösterir.
✓ İYİ KULLANIM
DATA name TYPE seoclsname.
DATA reader TYPE REF TO /clean/reader.
✗ KÖTÜ KULLANIM
DATA name TYPE seoclsname.
DATA reader TYPE REF TO /clean/reader. " hizalama iki sütun var gibi gösteriyor
💡 Uzman Yorumu: TYPE hizalaması değişken ve tip arasındaki bağı görsel olarak zayıflatır. Ayrıca uzun değişken adları eklendiğinde tüm satırların yeniden düzenlenmesini gerektirir.
16.21 Zincirleme Atamalar Yapmayın Orijinal Kaynak
Zincirleme atamalardan kaçının. Bu okuyucuyu şaşırtır ve inline bildirimlerle çalışmaz.
✓ İYİ KULLANIM
var2 = var3.
var1 = var3.
✗ KÖTÜ KULLANIM
var1 = var2 = var3. " JavaScript'teki a = (b == c) ile karıştırılabilir
💡 Uzman Yorumu: ABAP'ta = hem karşılaştırma hem atama için kullanılır. Zincirleme atama bu belirsizliği daha da artırır. Ayrıca inline bildirimlerle uyumlu değildir.
17. Test
17.1 Test Edilebilir Kod Yazın Orijinal Kaynak
Tüm kodu otomatik olarak test edebileceğiniz şekilde yazın. Bunu yapmak için kodunuzu refactor etmeniz gerekiyorsa, önce bunu yapın. Eklediğiniz her yeni özelliği en az birim testi ile doğrulayın.
�� Uzman Yorumu: Test edilemeyen kod, kalitesi hakkında hiçbir garanti verilemeyen koddur. Test edilebilirlik genellikle iyi tasarımın yan ürünüdür; Dependency Injection, arayüzler ve küçük sınıflar hem iyi tasarımı hem de test edilebilirliği sağlar.
17.2 Başkalarının Sizi Mock'lamasını Sağlayın Orijinal Kaynak
Başkaları tarafından tüketilecek kod yazıyorsanız, onların kendi kodları için birim testleri yazabilmesini sağlayın. Tüm dış yüzlerde arayüzler ekleyin, entegrasyon testlerini kolaylaştıran test double'ları sağlayın.
💡 Uzman Yorumu: Bir kütüphane veya API yazan geliştiricinin sorumluluğu, tüketicilerin test yazabilmesini sağlamaktır. Sınıf tabanlı bir API sunun ve arayüz sağlayın; böylece tüketiciler mock test double'lar oluşturabilir.
17.3 Okunabilirlik Kuralları Orijinal Kaynak
Test kodunuzu üretim kodunuzdan daha okunabilir yapın. Kötü üretim kodunu iyi testlerle telafi edebilirsiniz, ama testlerinizi bile anlayamıyorsanız kaybolmuşsunuzdur. Test kodunu standartlara ve kalıplara bağlı kalacak kadar basit ve anlaşılır tutun.
💡 Uzman Yorumu: Test kodu üretim kodu kadar önemsiz değildir; aksine daha kritik olabilir. Bir yıl sonra bile anlayabileceğiniz testler yazın. Karmaşık testler, test etme sırasında farkında olmadan bir hata üretilip üretilmediğini gizler.
17.4 Kopya Yapmayın Orijinal Kaynak
Geliştirme nesnesinin $TMP kopyasını oluşturup onun üzerinde denemeler yaparak çalışmaya başlamayın. Başkalarının bu nesnelerden haberi olmaz ve çalışmanızın durumunu bilemezler. Kopyayı silmeyi de unutursunuz.
💡 Uzman Yorumu: $TMP kopyalar hem yer israfıdır hem de kafa karışıklığı kaynağıdır. Doğrudan gerçek nesne üzerinde çalışın ve otomatik testlerle doğrulayın. Bu disiplin uzun vadede çok daha verimlidir.
17.5 Public'leri Test Edin Orijinal Kaynak
Sınıfların public bölümlerini, özellikle implemente ettikleri arayüzleri test edin. İç yapıyı (private/protected) değil, dışa açık davranışı doğrulayın.
💡 Uzman Yorumu: Private metodları test etme ihtiyacı genellikle tasarım sorunlarının habercisidir. "Bu private metod ayrı bir sınıf olabilir mi?" diye sorun. Eğer cevap evetse, o sınıfı çıkarın ve ayrı test edin.
17.6 Kapsam Konusunda Obsesif Olmayın Orijinal Kaynak
Kod kapsamı, test etmeyi unuttuğunuz kodu bulmak içindir; rastgele bir KPI'yı karşılamak için değil. Assert olmayan sahte testler yazmayın. %100 kapsamdan daha az ile mükemmel testleriniz olabilir.
💡 Uzman Yorumu: %100 kapsam hedeflemek genellikle değersiz testler üretir. Gerçek değer, önemli iş mantığının test edildiğinden emin olmaktır. Rakamları hedeflemek yerine kaliteye odaklanın.
17.7 Yerel Test Sınıflarını Adlandırın Orijinal Kaynak
Yerel test sınıflarını "ne zaman" veya "ne verildiğinde" bölümüne göre adlandırın. Test sınıfının adı senaryoyu açıklamalıdır.
✓ İYİ KULLANIM
CLASS ltc_when_all_entries_are_clean DEFINITION FOR TESTING ...
CLASS ltc_given_empty_table DEFINITION FOR TESTING ...
✗ KÖTÜ KULLANIM
CLASS ltc_fra_online_detection_api DEFINITION FOR TESTING ... " test edilen sınıfı tekrar ediyor
CLASS ltc_test DEFINITION FOR TESTING ... " test olmayan ne ki?
💡 Uzman Yorumu: Test sınıfının adı, o sınıftaki testlerin ortak bağlamını açıklamalıdır. Sınıf adını tekrar etmek gereksizdir; herkes zaten hangi sınıfı test ettiğini biliyor.
17.8 Testleri Yerel Sınıflara Koyun Orijinal Kaynak
Birim testlerini test edilen sınıfın yerel test include'una koyun. Bu, geliştiricilerin refactoring sırasında testleri bulmasını sağlar ve tek tuş basışıyla ilgili tüm testlerin çalıştırılmasına olanak tanır.
💡 Uzman Yorumu: Yerel test include (TEST INCLUDE veya Test Classes tab) testlerin üretim kodunun yanında yer almasını sağlar. Bu, testlerin gözden kaçmamasını garantiler.
17.9 Yardımcı Metodları Yardımcı Sınıflara Koyun Orijinal Kaynak
Birden fazla test sınıfı tarafından kullanılan yardım metodlarını yardım sınıfına koyun. Kalıtım (is-a) veya delegasyon (has-a) ilişkisiyle kullanıma açın.
✓ İYİ KULLANIM
CLASS lth_unit_tests DEFINITION ABSTRACT.
PROTECTED SECTION.
CLASS-METHODS assert_activity_entity
IMPORTING
actual_activity_entity TYPE REF TO zcl_activity_entity
expected_activity_entity TYPE REF TO zcl_activity_entity.
ENDCLASS.
CLASS ltc_unit_tests DEFINITION INHERITING FROM lth_unit_tests FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
💡 Uzman Yorumu: Test yardım sınıfları DRY prensibini test koduna da uygular. Tekrarlayan assertion veya setup kodu yardım sınıfına taşınmalı ve paylaşılmalıdır.
17.10 Test Sınıfları Nasıl Çalıştırılır Orijinal Kaynak
ABAP Development Tools'da testleri hızlı çalıştırmak için klavye kısayolları:
| Kısayol | Etki |
|---|---|
| Ctrl+Shift+F9 | Test ilişkileri dahil tüm testleri önizle |
| Ctrl+Shift+F10 | Sınıftaki tüm testleri çalıştır |
| Ctrl+Shift+F11 | Testleri çalıştır + kapsam ölçümü |
| Ctrl+Shift+F12 | Test ilişkilerindeki testleri de çalıştır |
💡 Uzman Yorumu: Bu kısayolları ezberlemenizi kesinlikle öneririm. Testleri kod değişikliğinden hemen sonra çalıştırmak, sorunları erken tespit etmenin en hızlı yoludur.
17.11 Test Edilen Kodu Anlamlı Adlandırın Orijinal Kaynak
Test edilen kodu temsil eden değişkeni anlamlı adlandırın. Anlam bulamazsanız varsayılan olarak "cut" (code under test) kullanın.
✓ İYİ KULLANIM
DATA blog_post TYPE REF TO ...
DATA empty_blog_post TYPE REF TO ...
DATA cut TYPE REF TO ... " anlam bulamazsanız
✗ KÖTÜ KULLANIM
DATA clean_fra_blog_post TYPE REF TO ... " sınıf adını gereksizce tekrar ediyor
💡 Uzman Yorumu: "cut" evrensel bir kısaltmadır. Değişken adı, test durumunun durumunu açıklayabiliyorsa (empty_blog_post, published_blog_post) bunu tercih edin. "cut" ise karmaşık testlerde bile hızlıca ne test edildiğini anlamayı sağlar.
17.12 Implementation'lara Karşı Değil Arayüzlere Karşı Test Edin Orijinal Kaynak
Test edilen kodu sınıf yerine arayüzle tiplendirilmiş değişkende tutun. Bu, public API'yı test ettiğinizi garanti eder.
✓ İYİ KULLANIM
DATA code_under_test TYPE REF TO some_interface.
✗ KÖTÜ KULLANIM
DATA code_under_test TYPE REF TO some_class. " sınıfa bağlı - iç yapıyı test etmeye açık
💡 Uzman Yorumu: Arayüz üzerinden test etmek, testlerinizin yalnızca public davranışa bağlı olmasını sağlar. Sınıf iç yapısı değişse bile testleriniz çalışmaya devam eder.
17.13 Çağrıyı Ayrı Metoda Çıkarın Orijinal Kaynak
Test edilen metodun birçok parametre veya hazırlık verisi gerektiriyorsa, çağrıyı varsayılan değerlere sahip bir yardım metoduna çıkarın.
✓ İYİ KULLANIM
METHODS map_xml_to_itab
IMPORTING
xml_string TYPE string
config TYPE /clean/xml2itab_config DEFAULT default_config
format TYPE /clean/xml2itab_format DEFAULT default_format.
DATA(itab) = map_xml_to_itab( '<xml></xml>' ).
✗ KÖTÜ KULLANIM
DATA(itab) = cut->map_xml_to_itab( xml_string = '<xml></xml>'
config = VALUE #( 'some meaningless stuff' )
format = VALUE #( 'more meaningless stuff' ) ).
💡 Uzman Yorumu: Test bağlamında önemsiz parametreler gereksiz karmaşıklık yaratır. Varsayılan değerleri olan yardım metodları, testin gerçek amacına odaklanmanızı sağlar.
17.14 Dependency Inversion Kullanın Orijinal Kaynak
Tüm bağımlılıkları constructor aracılığıyla geçirin. Setter injection veya FRIENDS injection kullanmayın.
✓ İYİ KULLANIM
METHODS constructor
IMPORTING
customizing_reader TYPE REF TO if_fra_cust_obj_model_reader.
METHOD constructor.
me->customizing_reader = customizing_reader.
ENDMETHOD.
✗ KÖTÜ KULLANIM
" Setter injection - üretim kodu kasıtsız kullanıma açık
METHODS set_customizing_reader
IMPORTING
customizing_reader TYPE REF TO if_fra_cust_obj_model_reader.
💡 Uzman Yorumu: Constructor injection en temiz bağımlılık enjeksiyon yöntemidir. Nesne oluşturulduktan sonra bağımlılıkları değiştirmeye izin vermez, bu da nesnenin tutarlı bir durumda kalmasını garantiler.
17.15 ABAP Test Double Aracını Kullanın Orijinal Kaynak
ABAP test double aracını (cl_abap_testdouble) kullanın. Elle yazılmış test double sınıflarından daha kısa ve anlaşılırdır.
✓ İYİ KULLANIM
DATA(customizing_reader) = CAST /clean/customizing_reader(
cl_abap_testdouble=>create( '/clean/default_custom_reader' ) ).
cl_abap_testdouble=>configure_call( customizing_reader )->returning( sub_claim_customizing ).
customizing_reader->read( 'SOME_ID' ).
💡 Uzman Yorumu: cl_abap_testdouble, elle yazılmış mock sınıflardan çok daha az kod gerektirir ve daha güçlüdür. Beklentileri yapılandırmak, gerçek çağrıları doğrulamak ve return değerleri ayarlamak için tam destek sunar.
17.16 Test Araçlarından Yararlanın Orijinal Kaynak
Genel olarak clean bir programlama stili, standart ABAP birim testleri ve test double'larla işin büyük çoğunluğunu yapmanıza imkân tanır. Mevcut çerçevelerin bir listesi için SAP örnekler deposuna bakın.
💡 Uzman Yorumu: SAP, test izolasyonu için çeşitli araçlar sunar. Bu araçları keşfetmek için zaman ayırın; doğru aracı seçmek test kodu yazma miktarını önemli ölçüde azaltır.
17.17 Test Seams'i Geçici Çözüm Olarak Kullanın Orijinal Kaynak
Tüm diğer teknikler başarısız olduğunda veya legacy kodun tehlikeli sığ sularında test seams kullanın. Bunlar invaziv ve uzun vadede zordur; yalnızca geçici çözüm olarak kullanın.
💡 Uzman Yorumu: Test seams (TEST-SEAM/END-TEST-SEAM) üretim koduna test kancaları ekler. Bu yöntem, kodu "kirletir" ama legacy kodu test altına almak için bazen tek yol budur. Refactoring tamamlandığında kaldırın.
17.18 LOCAL FRIENDS Kullanın Orijinal Kaynak
CREATE PRIVATE ile tanımlanmış sınıflara test erişimi sağlamak için LOCAL FRIENDS kullanın.
✓ İYİ KULLANIM
CLASS /clean/unit_tests DEFINITION.
PRIVATE SECTION.
DATA cut TYPE REF TO /clean/interface_under_test.
METHODS setup.
ENDCLASS.
CLASS /clean/class_under_test DEFINITION LOCAL FRIENDS unit_tests.
CLASS unit_tests IMPLEMENTATION.
METHOD setup.
DATA(mock) = cl_abap_testdouble=>create( '/clean/some_mock' ).
cut = NEW /clean/class_under_test( mock ).
ENDMETHOD.
ENDCLASS.
💡 Uzman Yorumu: LOCAL FRIENDS, CREATE PRIVATE sınıfları test için erişilebilir kılar. Bu, sınıfın dışarıdan oluşturulmasını sınırlandırırken test kodu için istisnaya izin verir.
LOCAL FRIENDS'i Kötüye Kullanmayın Orijinal Kaynak
LOCAL FRIENDS'i test edilen koda mock veri enjekte etmek için kötüye kullanmayın. Bu testleri kırılgan yapar; iç yapı değiştiğinde testler bozulur.
✗ KÖTÜ KULLANIM
CLASS /dirty/class_under_test DEFINITION LOCAL FRIENDS unit_tests.
CLASS unit_tests IMPLEMENTATION.
METHOD returns_right_result.
cut->some_private_member = 'AUNIT_DUMMY'. " private üyeye doğrudan erişim kırılgan
💡 Uzman Yorumu: Private üyelere doğrudan erişim, testi iç yapıya bağlar. İç yapı refactor edildiğinde test de bozulur. Constructor injection kullanmak bu sorunu tamamen önler.
17.20 Production Koduna Test Özellikleri Eklemeyin Orijinal Kaynak
Üretim koduna yalnızca otomatik test için kullanılacak özellikler eklemeyin.
✗ KÖTÜ KULLANIM
IF is_unit_test_running = abap_true.
"some logic here that runs only during unit tests
ENDIF.
" Üretim kodu test durumunu bilmemelidir!
💡 Uzman Yorumu: Üretim kodu test durumundan haberdar olmamalıdır. Bu, SoC (Separation of Concerns) prensibini ihlal eder. Test seams veya dependency injection kullanın.
17.21 Alt Sınıf Oluşturarak Mock Yapmayın Orijinal Kaynak
Metodları mock'lamak için alt sınıf oluşturup geçersiz kılmayın. Bu kırılgandır ve gerçek tüketicilerin de sınıfınızı miras almasını mümkün kılar.
✗ KÖTÜ KULLANIM
CLASS unit_tests DEFINITION INHERITING FROM /dirty/real_class FOR TESTING [...].
PROTECTED SECTION.
METHODS needs_to_be_mocked REDEFINITION. " kırılgan ve FINAL tasarımı bozar
💡 Uzman Yorumu: Alt sınıf mock, FINAL tasarımını ihlal eder ve refactoring'de kolayca kırılır. Arayüze dayalı tasarım ve cl_abap_testdouble çok daha sağlam bir alternatif sunar.
17.22 Gerekmeyen Şeyleri Mock'lamayın Orijinal Kaynak
Verilerinizi olabildiğince kesin tanımlayın: testinizin gerektirmediği veriler ayarlamayın, hiç çağrılmayan nesneleri mock'lamayın.
✓ İYİ KULLANIM
cut = NEW /clean/class_under_test( db_reader = db_reader
config = VALUE #( )
writer = VALUE #( ) ).
✗ KÖTÜ KULLANIM
cut = NEW /dirty/class_under_test( db_reader = db_reader
config = config " gerçekten gerekli mi?
writer = writer ). " test bu mock'u çağırıyor mu?
💡 Uzman Yorumu: Gereksiz mock'lar testlerin ne yaptığını gizler. Okuyucu "bu mock neden burada?" diye merak eder. Yalnızca gerçekten test için gerekli olan şeyleri mock'layın.
17.23 Test Framework'leri Oluşturmayın Orijinal Kaynak
Birim testleri için veri içi çerçeveler oluşturmayın. Test case ID'leri veri sağlamaya karar veren çerçeveler oluşturursanız, kodu uzun vadede yaşatamayacaksınız.
✓ İYİ KULLANIM
cl_abap_testdouble=>configure_call( test_double )->returning( data ).
✗ KÖTÜ KULLANIM
test_double->set_test_case( 1 ).
CASE test_case.
WHEN 1.
WHEN 2.
ENDCASE. " ölçeği artıkça yönetilmesi imkânsız hale gelir
💡 Uzman Yorumu: Test case ID'leriyle veri yönetimi, testleri ve veriyi ayrı dosyalarda depolamak gibi yaklaşımlar uzun vadede bakımı imkânsız hale getirir. Her test kendi verisini inline tanımlamalıdır.
17.24 Test Metodu İsimleri Orijinal Kaynak
Test metodunu verileni ve bekleniyi yansıtacak şekilde adlandırın.
✓ İYİ KULLANIM
METHOD reads_existing_entry.
METHOD throws_on_invalid_key.
METHOD detects_invalid_input.
✗ KÖTÜ KULLANIM
METHOD get_conversion_exits. " başarı mı başarısızlık mı bekleniyor?
METHOD test_loop. " test neden başka bir şey olsun?
METHOD parameterized_test. " amacı ne?
METHOD get_attributes_wo_w. " "_wo_w" ne demek? Bir yıl sonra hatırlanabilir mi?
💡 Uzman Yorumu: İyi bir test metod adı, test başarısız olduğunda ne beklediğinizi hemen anlatır. "throws_on_empty_input" başarısız olduğunda "ahh, boş girişte exception atılmıyor" diye hemen anlarsınız.
17.25 given-when-then Kullanın Orijinal Kaynak
Test kodunuzu given-when-then paradigmasına göre düzenleyin: önce given bölümünde başlatın, sonra when bölümünde test edilen şeyi çağırın, ardından then bölümünde sonucu doğrulayın.
✓ İYİ KULLANIM
METHOD throws_on_empty_input.
" given - henüz veri yok
" when
DATA(is_valid) = cut->is_valid_input( '' ).
" then
cl_abap_unit_assert=>assert_false( is_valid ).
ENDMETHOD.
💡 Uzman Yorumu: given-when-then yapısı, testin ne yaptığını üç ayrı endişeye böler: hazırlık, eylem ve doğrulama. Bu, testlerin okunmasını ve yazılmasını büyük ölçüde kolaylaştırır.
17.26 When Tam Olarak Bir Çağrıdır Orijinal Kaynak
"When" bölümünün test edilen sınıfa tam olarak bir çağrı içerdiğinden emin olun. Birden fazla çağrı, metodun odağının olmadığını ve çok fazla şeyi test ettiğini gösterir.
✓ İYİ KULLANIM
METHOD rejects_invalid_input.
" when - sadece bir çağrı
DATA(is_valid) = cut->is_valid_input( 'SOME_RANDOM_ENTRY' ).
" then
cl_abap_unit_assert=>assert_false( is_valid ).
ENDMETHOD.
💡 Uzman Yorumu: Tek bir "when" çağrısı, testin tam olarak bir davranışı test etmesini sağlar. Test başarısız olduğunda nedenin hangi çağrıda olduğu konusunda hiç belirsizlik olmaz.
17.27 TEARDOWN Eklemeyin Orijinal Kaynak
TEARDOWN metodları genellikle yalnızca veritabanı girişlerini veya diğer harici kaynakları temizlemek için gereklidir. Test sınıfı üyelerini (cut ve test double'lar gibi) sıfırlamak gereksizdir; setup tarafından üzerine yazılırlar.
💡 Uzman Yorumu: TEARDOWN her testten sonra çalışır. Eğer gerçekten veritabanı veya dosya sistemi gibi harici kaynaklar oluşturmuyorsanız, buna ihtiyacınız yoktur. Gereksiz TEARDOWN testleri yavaşlatır ve karmaşıklaştırır.
17.28 Anlamı Kolayca Görün Orijinal Kaynak
Hangi verilerin önemli olduğunu ve hangilerin yalnızca kodun çalışmasını sağlamak için orada olduğunu kolayca anlayabilmeyi sağlayın. Önemi olmayan şeyler için belirgin anlamsız isim ve değerler kullanın.
✓ İYİ KULLANIM
DATA(alert_id) = '42'. " bilinen anlamsız sayı
DATA(detection_object_type) = '?=/"&'. " klavye kazası
CONSTANTS some_random_number TYPE i VALUE 782346. " açıklayıcı değişken adı
✗ KÖTÜ KULLANIM
DATA(alert_id) = '00000001223678871'. " bu alert gerçekten var mı?
DATA(detection_object_type) = 'FRA_SCLAIM'. " bu tip gerçek customizing'e mi atıfta bulunuyor?
💡 Uzman Yorumu: Test verisinin anlamsız olduğu açık olmalıdır. Gerçek gibi görünen test verisi okuyucuyu "bu özel değer neden önemli?" diye merak ettirir ve gereksiz araştırmaya yol açar.
Farkları Kolayca Görün Orijinal Kaynak
Okuyucuları küçük farkları bulmak için uzun anlamsız dizeleri karşılaştırmaya zorlamayın. Farklar açıkça görünür olmalıdır.
✓ İYİ KULLANIM
exp_parameter_in = VALUE #(
( parameter_name = '...END1' )
( parameter_name = '...END2' ) ).
" Fark: END1 vs END2 - hemen görünür
💡 Uzman Yorumu: Test verisi arasındaki farkları vurgulayın, gizlemeyin. Uzun, neredeyse aynı string'ler arasındaki tek karakterlik fark bulunmaz ve testler yanıltıcı hale gelir.
Sabitler Kullanın Orijinal Kaynak
Test verisinin amacını ve önemini açıklamak için sabitler kullanın.
✓ İYİ KULLANIM
CONSTANTS some_nonsense_key TYPE char8 VALUE 'ABCDEFGH'.
METHOD throws_on_invalid_entry.
TRY.
cut->read_entry( some_nonsense_key ). " sabit amacı açıklıyor
cl_abap_unit_assert=>fail( ).
CATCH /clean/customizing_reader_error.
ENDTRY.
ENDMETHOD.
💡 Uzman Yorumu: "some_nonsense_key" sabit adı "bu gerçek bir anahtar değil, geçersiz bir girdi" demektir. Bu, testin amacını kod yorumu olmadan açıklar.
Az, Odaklı Assertion'lar Orijinal Kaynak
Yalnızca test metodunun hakkında olduğu şeyi, az sayıda assertion ile doğrulayın. Çok fazla assertion, metodun odağının olmadığını gösterir.
✓ İYİ KULLANIM
METHOD rejects_invalid_input.
DATA(is_valid) = cut->is_valid_input( 'SOME_RANDOM_ENTRY' ).
cl_abap_unit_assert=>assert_false( is_valid ). " tek, odaklı assertion
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD rejects_invalid_input.
DATA(is_valid) = cut->is_valid_input( 'SOME_RANDOM_ENTRY' ).
cl_abap_unit_assert=>assert_false( is_valid ).
cl_abap_unit_assert=>assert_not_initial( log->get_messages( ) ). " alakasız?
cl_abap_unit_assert=>assert_equals( act = sy-langu exp = 'E' ). " alakasız?
ENDMETHOD.
💡 Uzman Yorumu: Bir test metodundaki çok fazla assertion, testin birden fazla şeyi doğruladığı anlamına gelir. Bu, test başarısız olduğunda hangi özelliğin bozulduğunu belirsizleştirir.
Doğru Assert Tipini Kullanın Orijinal Kaynak
Doğru assertion tipini kullanın. assert_equals çok şey yapar (tip eşleştirme, ayrıntılı hata mesajı) ve hata mesajında ne yanlış gittiğini gösterir.
✓ İYİ KULLANIM
cl_abap_unit_assert=>assert_equals( act = table
exp = test_data ).
✗ KÖTÜ KULLANIM
cl_abap_unit_assert=>assert_true( xsdbool( act = exp ) ).
" Bu başarısız olduğunda hata mesajı "false was not true" der - hiçbir bilgi vermez
💡 Uzman Yorumu: assert_equals başarısız olduğunda "expected: X, but was: Y" gibi anlamlı mesajlar üretir. assert_true ise yalnızca "false was not true" der. Doğru assertion tipi, hata ayıklama süresini önemli ölçüde kısaltır.
İçeriği Değil Miktarı İddia Edin Orijinal Kaynak
Mümkünse sayı yerine içeriği doğrulayın. Sayılar değişebilir ama beklentiler karşılanmış olabilir; ya da tersine.
✓ İYİ KULLANIM
assert_contains_exactly( actual = table
expected = VALUE string_table( ( `ABC` ) ( `DEF` ) ( `GHI` ) ) ).
✗ KÖTÜ KULLANIM
assert_equals( act = lines( log_messages )
exp = 3 ). " neden tam 3? içerik doğru mu?
💡 Uzman Yorumu: Miktar assertion'ları kırılgandır: eklenen bir log mesajı tüm miktar testlerini bozabilir. İçerik doğrulaması hem daha sağlam hem de daha anlamlıdır.
İçeriği Değil Kaliteyi İddia Edin Orijinal Kaynak
Sonucun meta kalitesiyle ilgileniyorsanız ama gerçek içerikle değilseniz, uygun bir assertion ifade edin.
✓ İYİ KULLANIM
assert_all_lines_shorter_than( actual_lines = table
expected_max_length = 80 ).
" Gerçek içerik önemli değil, uzunluk önemli
✗ KÖTÜ KULLANIM
assert_equals( act = table
exp = VALUE string_table( ( `ABC` ) ( `DEF` ) ( `GHI` ) ) ).
" Refactoring farklı ama geçerli içerik üretse tüm testler bozulur
💡 Uzman Yorumu: Tam içerik doğrulaması testleri kırılgan yapar. Eğer gerçekten önem verdiğiniz şey kalite (uzunluk, format, sıra) ise, bunu doğrudan test edin.
FAIL Kullanın Orijinal Kaynak
Beklenen exception'ları kontrol etmek için FAIL kullanın.
✓ İYİ KULLANIM
METHOD throws_on_empty_input.
TRY.
cut->do_something( '' ).
cl_abap_unit_assert=>fail( ). " exception atılmadıysa test başarısız
CATCH /clean/some_exception.
" then - beklenen durum
ENDTRY.
ENDMETHOD.
💡 Uzman Yorumu: fail() çağrısı, "buraya ulaşılması beklenmiyordu" demektir. Exception atılmazsa kod fail() satırına gelir ve testi başarısız kılar. Bu, beklenen exception'ların kesin olarak doğrulanmasını sağlar.
Beklenmedik Exception'ları İletin Orijinal Kaynak
Beklenmedik exception'ları yakalayıp test başarısız kılmak yerine iletin. Böylece test kodu mutlu yola odaklanır ve okunması çok daha kolaydır.
✓ İYİ KULLANIM
METHODS reads_entry FOR TESTING RAISING /clean/some_exception.
METHOD reads_entry.
DATA(entry) = cut->read_something( ). " exception buradan iletilir
cl_abap_unit_assert=>assert_not_initial( entry ).
ENDMETHOD.
✗ KÖTÜ KULLANIM
METHOD reads_entry.
TRY.
DATA(entry) = cut->read_something( ).
CATCH /clean/some_exception INTO DATA(unexpected_exception).
cl_abap_unit_assert=>fail( unexpected_exception->get_text( ) ). " gereksiz karmaşık
ENDTRY.
cl_abap_unit_assert=>assert_not_initial( entry ).
ENDMETHOD.
💡 Uzman Yorumu: Beklenmedik exception'ları yakalamak, test kodunu gereksiz yere uzatır. RAISING ile iletmek test çerçevesinin exception'ı raporlamasını sağlar ve test kodu temiz kalır.
Özel Assertion'lar Yazın Orijinal Kaynak
Kodu kısaltmak ve tekrarden kaçınmak için özel assertion'lar yazın. Test kodu için de DRY prensibi geçerlidir.
✓ İYİ KULLANIM
METHODS assert_contains
IMPORTING
actual_entries TYPE STANDARD TABLE OF entries_tab
expected_key TYPE key_structure.
METHOD assert_contains.
TRY.
actual_entries[ key = expected_key ].
CATCH cx_sy_itab_line_not_found.
cl_abap_unit_assert=>fail( |Couldn't find the key { expected_key }| ).
ENDTRY.
ENDMETHOD.
" Çağrı
assert_contains( actual_entries = entries expected_key = key ).
💡 Uzman Yorumu: Özel assertion'lar, tekrar eden test mantığını kapsüller ve anlamlı hata mesajları üretir. Test kodu da refactor edilmeli; kopyala-yapıştır yerine yeniden kullanılabilir assertion'lar oluşturun.
Pratik Uygulama İpuçları
Günlük Geliştirme Pratikleri
Bu bölümde, Clean ABAP prensiplerini günlük iş akışınıza entegre etmenize yardımcı olacak pratik ipuçları ve genişletilmiş örnekler bulacaksınız. Teoriden pratiğe geçişte en sık karşılaşılan sorular ele alınmaktadır.
Yaygın Kötü İsimlendirme Örnekleri ve Çözümleri
Aşağıda gerçek ABAP projelerinde sık karşılaşılan kötü isimlendirme örnekleri ve bunların Clean ABAP versiyonları yer almaktadır.
✗ KÖTÜ KULLANIM - Gerçek projelerden kötü isimler
DATA lv_flag TYPE c. " hangi bayrak? ne anlamına geliyor?
DATA it_data TYPE STANDARD TABLE OF ty_s. " 'data' nedir? 'ty_s' ne tipi?
DATA lv_cnt TYPE i. " count mu, counter mi?
DATA wa_line TYPE ty_s. " wa_ öneki ve anlamız satır
METHODS process
IMPORTING
im_obj TYPE REF TO lcl_obj " im_ öneki gereksiz, obj belirsiz
EXPORTING
ex_rc TYPE i. " ex_ öneki ve 'rc' dönüş kodu anlamsız
✓ İYİ KULLANIM - Clean ABAP versiyonları
DATA has_valid_entries TYPE abap_bool.
DATA sales_orders TYPE STANDARD TABLE OF sales_order_type.
DATA order_count TYPE i.
DATA current_order TYPE sales_order_type.
METHODS validate_and_process_order
IMPORTING
order TYPE REF TO /clean/sales_order
RETURNING
VALUE(result) TYPE /clean/validation_result.
💡 Uzman Yorumu: Eski ABAP geleneklerinden (lv_, it_, wa_, im_, ex_ önekleri) vazgeçmek ilk başta zor gelebilir. Ekibinizle bir anlaşma yapın ve yeni geliştirmelerde bu önekleri kullanmayı bırakın. Legacy kodu dokunduğunuzda yavaş yavaş dönüştürün.
Büyük Metodları Adım Adım Küçültme
500 satırlık bir metod gördüğünüzde ne yaparsınız? Tüm metodu bir anda refactor etmeye çalışmak tehlikeli olabilir. İşte güvenli bir yaklaşım:
✗ KÖTÜ KULLANIM - 500 satırlık dev metod (kısaltılmış)
METHOD process_sales_document.
" 50 satır veri bildirimi
DATA: lv_vbeln TYPE vbeln,
lv_kunnr TYPE kunnr,
lv_netwr TYPE netwr,
...
" Müşteri doğrulama - 100 satır
SELECT SINGLE * FROM kna1 INTO wa_kna1
WHERE kunnr = im_kunnr.
IF sy-subrc <> 0.
ev_error = 'X'.
EXIT.
ENDIF.
...
" Fiyat hesaplama - 150 satır
...
" Stok kontrolü - 100 satır
...
" Belge oluşturma - 100 satır
...
ENDMETHOD.
✓ İYİ KULLANIM - Aşama aşama küçültülmüş versiyonu
METHOD process_sales_document.
DATA(customer) = validate_customer( customer_id ).
DATA(pricing) = calculate_pricing( customer = customer
items = line_items ).
DATA(stock) = check_stock_availability( items = line_items ).
result = create_sales_document( customer = customer
pricing = pricing
stock = stock ).
ENDMETHOD.
METHOD validate_customer.
TRY.
result = customer_repository->find_by_id( customer_id ).
CATCH /clean/customer_not_found.
RAISE EXCEPTION NEW /clean/invalid_customer_id( customer_id = customer_id ).
ENDTRY.
ENDMETHOD.
METHOD calculate_pricing.
result = pricing_engine->calculate(
customer = customer
items = items
valid_from = sy-datum ).
ENDMETHOD.
METHOD check_stock_availability.
result = inventory_service->check_availability(
items = items
check_date = sy-datum ).
ENDMETHOD.
METHOD create_sales_document.
DATA(doc_builder) = NEW /clean/sales_doc_builder( ).
doc_builder->set_customer( customer ).
doc_builder->set_pricing( pricing ).
doc_builder->set_stock_check( stock ).
result = doc_builder->build( ).
ENDMETHOD.
💡 Uzman Yorumu: Büyük metodları adım adım küçültürken "Strangler Fig" desenini uygulayın: yeni işlevselliği küçük temiz metodlara yazın, yavaş yavaş eski kodu yeni metodlara yönlendirin. Her adımda testlerin yeşil kaldığını doğrulayın.
Dependency Injection Gerçek Dünya Örneği
Dependency Injection'ın nasıl uygulandığını somut bir örnekle görelim. Bu desen hem test edilebilirliği hem de esnekliği artırır.
✓ İYİ KULLANIM - Tam Dependency Injection Örneği
" Arayüz tanımı
INTERFACE /clean/if_email_sender.
METHODS send
IMPORTING
to TYPE string
subject TYPE string
body TYPE string
RAISING
/clean/cx_email_send_failure.
ENDINTERFACE.
" Üretim implementasyonu
CLASS /clean/smtp_email_sender DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES /clean/if_email_sender.
ENDCLASS.
CLASS /clean/smtp_email_sender IMPLEMENTATION.
METHOD /clean/if_email_sender~send.
" SMTP üzerinden gerçek email gönderimi
" ...
ENDMETHOD.
ENDCLASS.
" Servis sınıfı - injection ile
CLASS /clean/order_notification_service DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor
IMPORTING
email_sender TYPE REF TO /clean/if_email_sender.
METHODS notify_customer
IMPORTING
order_id TYPE /clean/order_id
customer_id TYPE kunnr.
PRIVATE SECTION.
DATA email_sender TYPE REF TO /clean/if_email_sender.
ENDCLASS.
CLASS /clean/order_notification_service IMPLEMENTATION.
METHOD constructor.
me->email_sender = email_sender.
ENDMETHOD.
METHOD notify_customer.
DATA(customer) = customer_repo->find( customer_id ).
email_sender->send(
to = customer->get_email( )
subject = |Order { order_id } Confirmed|
body = build_confirmation_body( order_id ) ).
ENDMETHOD.
ENDCLASS.
" Üretim kodu - gerçek email sender
DATA(notification_service) = NEW /clean/order_notification_service(
email_sender = NEW /clean/smtp_email_sender( ) ).
" Test kodu - mock email sender
DATA(mock_sender) = CAST /clean/if_email_sender(
cl_abap_testdouble=>create( '/clean/if_email_sender' ) ).
DATA(notification_service_under_test) = NEW /clean/order_notification_service(
email_sender = mock_sender ).
💡 Uzman Yorumu: Bu örnek, arayüz-uygulama-servis üçlüsünün nasıl çalıştığını gösteriyor. Üretim kodunda gerçek SMTP sender, test kodunda ise mock sender kullanılıyor. Servis sınıfı hangi implementasyonu kullandığını bilmiyor.
Exception Hiyerarşisi Tasarımı
İyi tasarlanmış bir exception hiyerarşisi, çağıranların hem genel hem de özel hataları yakalamasına izin verir.
✓ İYİ KULLANIM - İyi tasarlanmış exception hiyerarşisi
" Temel application exception
CLASS /clean/cx_application_error DEFINITION
PUBLIC ABSTRACT INHERITING FROM cx_static_check.
PUBLIC SECTION.
METHODS constructor
IMPORTING
textid LIKE if_t100_message=>t100key OPTIONAL
previous LIKE previous OPTIONAL.
ENDCLASS.
" Domain exception'ları
CLASS /clean/cx_customer_error DEFINITION
PUBLIC ABSTRACT INHERITING FROM /clean/cx_application_error.
ENDCLASS.
CLASS /clean/cx_customer_not_found DEFINITION
PUBLIC FINAL INHERITING FROM /clean/cx_customer_error.
PUBLIC SECTION.
DATA customer_id TYPE kunnr READ-ONLY.
METHODS constructor
IMPORTING
customer_id TYPE kunnr
previous LIKE previous OPTIONAL.
ENDCLASS.
CLASS /clean/cx_customer_credit_limit_exceeded DEFINITION
PUBLIC FINAL INHERITING FROM /clean/cx_customer_error.
PUBLIC SECTION.
DATA customer_id TYPE kunnr READ-ONLY.
DATA credit_limit TYPE netwr READ-ONLY.
DATA order_amount TYPE netwr READ-ONLY.
ENDCLASS.
" Kullanım - katmanlı yakalama
TRY.
order_service->create_order( customer_id = '1000'
amount = 50000 ).
CATCH /clean/cx_customer_not_found INTO DATA(not_found).
" Müşteri bulunamadı - kullanıcıya bildir
show_message( |Customer { not_found->customer_id } not found| ).
CATCH /clean/cx_customer_credit_limit_exceeded INTO DATA(limit_exc).
" Kredi limiti aşıldı - yöneticiye ilet
notify_manager( limit_exc ).
CATCH /clean/cx_customer_error INTO DATA(cust_err).
" Diğer müşteri hataları - genel işlem
log_error( cust_err ).
CATCH /clean/cx_application_error INTO DATA(app_err).
" Tüm uygulama hataları - hata sayfası
show_error_page( ).
ENDTRY.
💡 Uzman Yorumu: Hiyerarşi, en özel exception'dan en genel olana doğru yakalanır. Bu, hem özel durumları ele alma hem de genel fallback sağlama imkânı tanır. ABSTRACT üst sınıflar yanlışlıkla doğrudan kullanımı engeller.
Birim Testi Tam Örneği
Aşağıda given-when-then yapısını kullanan eksiksiz bir birim testi örneği yer almaktadır.
✓ İYİ KULLANIM - Tam birim testi örneği
CLASS ltc_order_validator DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA cut TYPE REF TO /clean/if_order_validator.
DATA mock_customer_repo TYPE REF TO /clean/if_customer_repository.
METHODS setup.
METHODS given_valid_customer RETURNING VALUE(result) TYPE kunnr.
METHODS given_customer_with_no_credit RETURNING VALUE(result) TYPE kunnr.
METHODS validates_existing_customer FOR TESTING.
METHODS rejects_unknown_customer FOR TESTING.
METHODS rejects_customer_without_credit FOR TESTING.
METHODS validates_minimum_order_amount FOR TESTING.
ENDCLASS.
CLASS ltc_order_validator IMPLEMENTATION.
METHOD setup.
mock_customer_repo = CAST /clean/if_customer_repository(
cl_abap_testdouble=>create( '/clean/if_customer_repository' ) ).
cut = NEW /clean/order_validator(
customer_repository = mock_customer_repo ).
ENDMETHOD.
METHOD given_valid_customer.
result = '0000001000'.
cl_abap_testdouble=>configure_call( mock_customer_repo
)->returning( VALUE /clean/customer( id = result
credit_limit = 100000
credit_used = 0 ) ).
mock_customer_repo->find_by_id( result ).
ENDMETHOD.
METHOD given_customer_with_no_credit.
result = '0000002000'.
cl_abap_testdouble=>configure_call( mock_customer_repo
)->returning( VALUE /clean/customer( id = result
credit_limit = 1000
credit_used = 1000 ) ).
mock_customer_repo->find_by_id( result ).
ENDMETHOD.
METHOD validates_existing_customer.
" given
DATA(customer_id) = given_valid_customer( ).
DATA(order) = VALUE /clean/order( customer_id = customer_id
amount = 500 ).
" when
DATA(result) = cut->validate( order ).
" then
cl_abap_unit_assert=>assert_true( result->is_valid ).
ENDMETHOD.
METHOD rejects_unknown_customer.
" given
cl_abap_testdouble=>configure_call( mock_customer_repo
)->raising( NEW /clean/cx_customer_not_found( customer_id = 'UNKNOWN' ) ).
mock_customer_repo->find_by_id( 'UNKNOWN' ).
DATA(order) = VALUE /clean/order( customer_id = 'UNKNOWN'
amount = 500 ).
" when
DATA(result) = cut->validate( order ).
" then
cl_abap_unit_assert=>assert_false( result->is_valid ).
cl_abap_unit_assert=>assert_char_cp(
act = result->error_message
exp = '*not found*' ).
ENDMETHOD.
METHOD rejects_customer_without_credit.
" given
DATA(customer_id) = given_customer_with_no_credit( ).
DATA(order) = VALUE /clean/order( customer_id = customer_id
amount = 500 ).
" when
DATA(result) = cut->validate( order ).
" then
cl_abap_unit_assert=>assert_false( result->is_valid ).
ENDMETHOD.
METHOD validates_minimum_order_amount.
" given
DATA(customer_id) = given_valid_customer( ).
DATA(order) = VALUE /clean/order( customer_id = customer_id
amount = 0 ). " sıfır tutar
" when
DATA(result) = cut->validate( order ).
" then
cl_abap_unit_assert=>assert_false( result->is_valid ).
cl_abap_unit_assert=>assert_char_cp(
act = result->error_message
exp = '*minimum*' ).
ENDMETHOD.
ENDCLASS.
💡 Uzman Yorumu: Bu test örneği birçok Clean Code prensibini bir arada gösteriyor: anlamlı test sınıfı adı, setup metodunda DI, given yardım metodları, açık given-when-then yapısı ve odaklı assertion'lar. Bu şablonu kendi projelerinizde kullanabilirsiniz.
Modern ABAP Sözdizimi Karşılaştırma Tablosu
Eski ve modern ABAP sözdiziminin yan yana karşılaştırması:
| Eski Stil | Modern Stil |
|---|---|
MOVE 'X' TO flag. |
flag = abap_true. |
CREATE OBJECT obj TYPE lcl.
|
DATA(obj) = NEW lcl( ).
|
ADD 1 TO counter. |
counter += 1. |
TRANSLATE str TO UPPER CASE.
|
str = to_upper( str ).
|
DESCRIBE TABLE itab LINES cnt.
|
cnt = lines( itab ). |
READ TABLE itab INTO wa WITH KEY k = v.
|
DATA(wa) = itab[ k = v ].
|
LOOP AT itab INTO wa. ... ENDLOOP.
|
LOOP AT itab REFERENCE INTO DATA(wa). ... ENDLOOP.
|
CONCATENATE s1 s2 INTO result.
|
result = |{ s1 }{ s2 }|.
|
IF NOT x IS INITIAL. |
IF x IS NOT INITIAL. |
CLEAR itab. REFRESH itab.
|
CLEAR itab. |
💡 Uzman Yorumu: Modern ABAP sözdizimi sadece daha kısa değil, aynı zamanda tip güvenli ve daha az hata eğilimlidir. ABAP Development Tools'un Quick Fix özelliği eski sözdizimini otomatik olarak yenisiyle değiştirmenize yardımcı olabilir.
Clean ABAP Kontrol Listesi
Kod incelemesi sırasında kullanabileceğiniz kontrol listesi:
İsimler
- ☐ Tüm değişken ve metod isimleri açıklayıcı ve telaffuz edilebilir mi?
- ☐ Kısaltmalar ve kodlama önekleri (lv_, it_, im_) kaldırıldı mı?
- ☐ Koleksiyonlar çoğul, tekil öğeler tekil adlandırıldı mı?
- ☐ Sınıflar isim, metodlar fiil içeriyor mu?
Metodlar
- ☐ Her metod 20 satırdan az mı?
- ☐ Her metod tek bir şey mi yapıyor?
- ☐ 3'ten az IMPORTING parametresi var mı?
- ☐ Boolean parametre yerine ayrı metod kullanıldı mı?
- ☐ RETURNING mi EXPORTING yerine kullanılıyor?
Hata Yönetimi
- ☐ Dönüş kodu yerine exception kullanılıyor mu?
- ☐ Exception'lar anlamlı bilgi taşıyor mu?
- ☐ Sınıf tabanlı exception mı kullanılıyor?
Test
- ☐ Tüm public metodlar test edildi mi?
- ☐ given-when-then yapısı kullanıldı mı?
- ☐ Test double'lar arayüz üzerinden oluşturuldu mu?
- ☐ Her test metodu tek bir davranışı mı test ediyor?
Sınıflar
- ☐ Kalıtım için tasarlanmamış sınıflar FINAL mı?
- ☐ Üyeler varsayılan olarak PRIVATE mi?
- ☐ Public metodlar bir arayüz üzerinden mi?
- ☐ Bağımlılıklar constructor injection ile mi enjekte ediliyor?
💡 Uzman Yorumu: Bu kontrol listesini code review sürecinize entegre edin. Her pull request veya transport request onayında bu maddeleri sistematik olarak kontrol etmek, kaliteyi önemli ölçüde artırır.
Sık Yapılan Hatalar ve Çözümleri
Clean ABAP'a geçiş sürecinde en sık yapılan hatalar ve bunları nasıl düzelteceğiniz:
Hata 1: Tüm kurallara aynı anda uymaya çalışmak
✗ YANLIŞ YAKLAŞIM
" Tüm kodunuzu bir haftada Clean ABAP'a geçirmeye çalışmak
" → Projeyi riske atar ve ekibi bunaltır
✓ DOĞRU YAKLAŞIM
" Her sprint'te 1-2 kural seçin
" Sprint 1: Kötü metod isimleri düzeltildi
" Sprint 2: Boolean parametreler kaldırıldı
" Sprint 3: Büyük metodlar bölündü
" ...
Hata 2: Yorumları silip içerik eklememeк
✗ YANLIŞ YAKLAŞIM
" "Kodda ifade et" kuralını yanlış anlayıp tüm yorumları silmek
" ama kodu açıklayıcı hale getirmemek
✓ DOĞRU YAKLAŞIM
" Yorumu sil → ama kodu daha açıklayıcı hale getir
" Yorum: "bu fonksiyon müşteriyi doğrular"
" Aksiyon: validate_customer( ) metodunu çıkar, yorum gerekli olmaz
Hata 3: Birim testleri yazmadan refactor etmek
✗ YANLIŞ YAKLAŞIM
" Önce refactor et, sonra test yaz
" → Refactoring sırasında davranış değişikliğini fark edemezsiniz
✓ DOĞRU YAKLAŞIM
" Önce mevcut davranışı test et (characterization tests)
" Sonra refactor et
" Her adımda testlerin yeşil kaldığını doğrula
Hata 4: Herkesi aynı anda ikna etmeye çalışmak
✓ DOĞRU YAKLAŞIM
" Bir pilot projeyle başlayın
" Sonuçları ölçün (hata sayısı, geliştirme hızı, onboarding süresi)
" Verilere dayanarak diğer projelere genişletin
" Başarı hikayeleri paylaşın
💡 Uzman Yorumu: Clean Code'a geçiş bir maraton, sprint değil. Küçük, tutarlı adımlar atın ve ilerlemeyi kutlayın. Her geliştirici bu yolculukta farklı bir noktada başlar; sabrınızı koruyun ve ekibi yargılamayın.
İleri Okuma ve Kaynaklar
Clean ABAP yolculuğunuzu derinleştirmek için önerilen kaynaklar:
📚 Kitaplar
- Clean Code - Robert C. Martin
- The Pragmatic Programmer
- Refactoring - Martin Fowler
- Clean Architecture - Robert C. Martin
- Working Effectively with Legacy Code
🌐 Web Kaynakları
- SAP Styleguides (GitHub)
- SAP Community Blogs
- Clean Code Developer
- ABAP Development Tools Help
- SAP Help Portal - ATC
🛠️ Araçlar
- ABAP Test Cockpit (ATC)
- Code Inspector (SCI)
- ABAP Unit Test Framework
- cl_abap_testdouble
- ABAP Development Tools (ADT)
💡 Uzman Yorumu: Bu kaynaklar Clean Code yolculuğunuzda size eşlik edecek. Ancak en iyi öğrenme yolu pratik yapmaktır. Her gün biraz Clean Code, zaman içinde büyük bir fark yaratır.
Sonuç
Clean ABAP Yolculuğunuzda Başarılar
Bu kılavuz, SAP Clean ABAP stilkılavuzunun kapsamlı bir Türkçe çevirisi ve genişletilmiş yorumudur. 150'den fazla kural, gerçek kod örnekleri ve uzman yorumlarıyla ABAP geliştirme kalitenizi sistematik olarak artırmanıza yardımcı olmayı hedeflemektedir.
Unutmayın: Temiz kod, ahlaki bir yükümlülük değil; takımınıza ve gelecekteki kendinize duyduğunuz saygının göstergesidir. Bugün yazdığınız kod, altı ay sonra siz de dahil olmak üzere başkaları tarafından okunacak. O okuyucuya borçlu olduğunuz en iyi şey, açık ve anlaşılır bir koddur.
Clean ABAP Manifestosu
" Clean ABAP'ta çalışmanın özü:
" Gizem değil, netlik.
IF order IS NOT INITIAL AND order->is_valid( ).
process_order( order ).
ENDIF.
" Kısalık değil, açıklık.
METHODS process_customer_order_with_validation
IMPORTING valid_customer_order TYPE REF TO /clean/customer_order.
" Zekâ değil, basitlik.
DATA(total) = REDUCE netwr( INIT sum = 0
FOR item IN line_items
NEXT sum = sum + item-amount ).
" Kendi kendine, yorumsuz.
METHOD place_order.
validate_order( ).
reserve_inventory( ).
charge_customer( ).
send_confirmation( ).
ENDMETHOD.
💡 Son Söz: "Programların insanlar tarafından okunması için yazıldığını ve yalnızca makineler tarafından yürütülmesinin tesadüf olduğunu aklınızdan çıkarmayın." — Harold Abelson