Salesforce platformu, Software-as-a-Service (SaaS) modelinin öncülerinden biri olarak, başlangıçta yapılandırılmış iş akışları ve nokta-tıklama araçları ile müşteri ilişkileri yönetimini demokratikleştirmeyi hedeflemişti. Ancak, platformun benimsenmesi ve iş gereksinimlerinin karmaşıklaşması ile birlikte, salt yapılandırma ile çözülemeyecek özelleştirme ihtiyaçları doğmaya başladı. Mevcut çözümler, veri merkezli iş mantığını platform dışına taşımak zorunda kalıyordu ki bu da multi-tenant bulut mimarisinin temel avantajlarından olan güvenlik, bütünlük ve performans üzerinde risk oluşturuyordu.
Bu kritik ihtiyacı karşılamak üzere Salesforce, 2007 yılında dünyaya Apex programlama dilini tanıttı. Dil, Java ve C# sentaksına benzer bir yapıda tasarlandı, böylece milyonlarca geliştiricinin aşina olduğu bir paradigmayı benimsedi. Apex'in en radikal özelliği, doğuştan Salesforce'un altyapısına, veri katmanına ve güvenlik modeline derinlemesine gömülü olmasıydı. Bu tasarım, geliştiricilere sunucu, ağ veya veritabanı yönetimi gibi kaygılar olmadan, doğrudan iş mantığına odklanma imkanı verdi. Dil, "Bulut İçin Yazıldı" (Written in the Cloud) sloganı ile pazarlanarak, geleneksel dillerden farklı olarak, bir derleyici veya geliştirme ortamı kurulumu gerektirmeden, tamamen web tabanlı bir IDE (Integrated Development Environment) üzerinden geliştirilmek ve dağıtılmak üzere kurgulandı.
Apex, Salesforce'un "Force.com" platformunun omurgasını oluşturdu. Onun ortaya çıkışı, platformu basit bir CRM uygulaması olmaktan çıkarıp, kurumsal düzeyde ölçeklenebilir ve son derece özelleştirilebilir bir PaaS (Platform-as-a-Service) çözümüne dönüştürdü. Günümüzde, milyonlarca satır Apex kodu, dünya çapında on binlerce işletmenin kritik süreçlerini otomatikleştirmekte ve Salesforce ekosisteminin can damarını oluşturmaktadır. Bu tarihsel bağlam, Apex'i anlamak için esastır, çünkü onun tüm kısıtlamaları ve güçlü yanları bu özgün, bulut-merkezli ve çok kiracılı (multi-tenant) doğasından kaynaklanmaktadır.
Dilin Temel Özellikleri
Apex, güçlü ve statik olarak tip belirlenmiş (strongly and statically typed) bir dildir. Bu, her değişkenin ve ifadenin derleme zamanında (compile-time) bilinen bir türe sahip olması gerektiği ve tür uyumsuzluklarının derleme sırasında yakalandığı anlamına gelir. Bu yaklaşım, çalışma zamanı (runtime) hatalarını önemli ölçüde azaltarak daha güvenilir ve sağlam uygulamalar geliştirilmesini sağlar. Java benzeri sentaksı, nesne yönelimli programlama (OOP) prensiplerini doğrudan destekler ve geliştiricilere hızlı bir şekilde adapte olma imkanı tanır.
Dilin en ayırt edici özelliklerinden biri, bulut tabanlı olması ve sınırlarıdır. Apex kodu, Salesforce'un çok kiracılı altyapısında yürütülür ve bu nedenle kaynak kullanımı katı governer limitleri ile sınırlandırılmıştır. Bu limitler, tek bir işlemin (transaction) tüketebileceği maksimum CPU süresi, bellek, veritabanı sorgu sayısı, DML (Data Manipulation Language) işlemi sayısı ve HTTP çağrısı sayısı gibi parametreleri içerir. Bu sınırlar, tek bir kiracının (tenant) performansının, aynı altyapıyı paylaşan diğer tüm kiracıları olumsuz etkilemesini engelleyerek platformun genel istikrarını ve adil kaynak dağılımını garanti eder. Bu, geleneksel sunucu-tarafı dillerden radikal bir kopuştur.
| Özellik Kategorisi | Apex'teki Durumu | Açıklama |
|---|---|---|
| Nesne Yönelimlilik | Tam Destek | Sınıflar, arayüzler, kalıtım (inheritance), polimorfizm ve encapsulation desteklenir. |
| Bellek Yönetimi | Otomatik (Çöp Toplayıcı) | Java'ya benzer şekilde, çöp toplayıcı (garbage collector) kullanılmayan nesneleri otomatik temizler. |
| Eşzamanlılık (Concurrency) | Sınırlı ve Kontrollü | Future metodları, Queueable Arayüzü ve Batch Apex gibi asenkron işleme modelleri ile yönetilir. Geleneksel thread oluşturma desteklenmez. |
| Veri Erişimi | Yerel ve Doğrudan | SOQL ve SOSL ile doğrudan veritabanına erişim sağlanır. Harici veri kaynakları için Callouts kullanılır. |
Apex aynı zamanda otomatik olarak işlemlere dayanıklı (transactional) bir dildir. Bir Apex işlemi başarısız olursa, o işlem kapsamında gerçekleştirilmiş tüm veritabanı değişiklikleri otomatik olarak geri alınır (rollback), böylece veri bütünlüğü korunur. Bu, geliştiricinin açıkça commit veya rollback komutları yazmasını gerektirmez. Dil, olay tabanlı programlamayı tetikleyiciler (triggers) ve platform olayları (platform events) aracılığıyla destekler. Ayrıca, test odaklı bir geliştirme sürecini zorunlu kılar; her Apex sınıfı için en az %75 kod kapsamı sağlayan test sınıfları yazılmadan, kod canlı (production) ortama dağıtılamaz. Bu özelliklerin tümü, Apex'i sadece bir programlama dili değil, aynı zamanda Salesforce platformunun güvenlik, tutarlılık ve güvenilirlik ilkelerini uygulayan bir çerçeve (framework) haline getirir.
Dilin geliştirme döngüsü de tamamen bulut merkezlidir. Kod, genellikle Salesforce'un tarayıcı tabanlı Lightning Platform IDE'si (önceden Developer Console) veya popüler kod editörleri için Salesforce Extensions ile birlikte gelen Visual Studio Code kullanılarak yazılır. Kod, doğrudan Salesforce orgnizasyonuna (org) dağıtılmadan önce, meta-veri (metadata) formatında paketlenir ve validasyon sürecinden geçer. Bu süreç, geleneksel derleme, bağlama (linking) ve sunucuya yükleme adımlarını ortadan kaldırarak modern, agile geliştirme pratikleri ile uyum sağlar.
Apex’in Nesne Yönelimli Yapısı
Apex, nesne yönelimli programlama (OOP) paradigmasını tam anlamıyla benimseyen ve bu paradigmayı Salesforce'un veri modeliyle kusursuz bir şekilde bütünleştiren bir dildir. Java ve C#'dan aşina olduğumuz temel OOP konseptlerinin hepsi – sınıflar (classes), nesneler (objects), kalıtım (inheritance), çok biçimlilik (polymorphism), soyutlama (abstraction) ve kapsülleme (encapsulation) – Apex'te de mevcuttur. Bu yapı, karmaşık iş mantığının modüler, yeniden kullanılabilir ve bakımı kolay birimlere ayrılmasını sağlar.
Apex'teki her şey bir sınıf içinde tanımlanır. Bir sınıf, metodlar (methods) ve özellikler (properties) içerir. Özellikler, sınıfın durumunu temsil ederken, metodlar bu durumu işleyen ve sınıfın davranışını tanımlayan işlevlerdir. Apex, public, private, protected ve global erişim değiştiricilerini (access modifiers) destekleyerek kapsüllemeyi güçlü bir şekilde uygular. Kalıtım mekanizması, bir sınıfın (alt sınıf) başka bir sınıfın (üst sınıf) özelliklerini ve metodlarını miras almasına olanak tanır, bu da kod tekrarını önler ve hiyerarşik ilişkileri modeller. Arayüzler (interfaces), farklı sınıflar için ortak bir sözleşme tanımlayarak, bu sınıfların aynı metod kümesini uygulamasını zorunlu kılar ve böylece çok biçimliliği ve gevşek bağlı (loosely coupled) mimarileri destekler.
Salesforce'un standart ve özel (custom) nesneleri (objects), Apex'te doğrudan sınıflar olarak temsil edilir. Örneğin, 'Account' standart nesnesi, bir Apex kodu içinde 'Account' türünde bir değişken olarak kullanılabilir ve bu değişken üzerinden alanlara (fields) erişilebilir ve metodlar çağrılabilir. Bu, veri modeli ile programlama dilini birbirine yakınlaştırır ve geliştirici üretkenliğini artırır. Ayrıca, Apex sınıfları tetikleyicilerden (triggers), Visualforce denetleyicilerinden, Lightning Web Bileşenlerinden ve hatta REST web servislerinden doğrudan çağrılabilir, bu da onları platformdaki her türlü özelleştirmenin merkezine yerleştirir. Nesne yönelimli yapı, Apex kodunun organizasyonunu ve ölçeklenebilirliğini sağlayan temel taştır.
Veri Yönetimi ve SOQL/SOSL
Salesforce platformunun kalbi veridir ve Apex, bu veriyle etkileşim kurmak için güçlü, platforma özgü iki sorgu dili sağlar: Salesforce Object Query Language (SOQL) ve Salesforce Object Search Language (SOSL). SOQL, ilişkisel veritabanı sorgulama diline (SQL) benzer bir sözdizimine sahiptir, ancak Salesforce'un çok kiracılı, nesne-tabanlı veri modeline göre uyarlanmıştır. SOQL, kayıtları okumak için kullanılır ve SELECT deyimleri aracılığıyla standart veya özel nesnelerden, ilişkili alanlardan ve filtrelerden veri çekmeyi mümkün kılar. SOQL, platformun güvenlik modeliyle otomatik olarak entegredir, yani bir kullanıcının profil ve izin ayarlarına göre erişimi olmayan kayıtları veya alanları otomatik olarak filtreler.
SOQL'in gücü, ilişkileri (relationships) kolayca sorgulayabilmesinde yatar. Parent-child ve child-parent ilişkileri, nokta notasyonu kullanılarak tek bir sorguda gezinebilir. Bu, karmaşık veri modelleri üzerinde verimli bir şekilde çalışmayı sağlar. Öte yandan, SOSL metin tabanlı tam metin aramaları (full-text search) için tasarlanmıştır. SOSL, bir veya daha fazla nesne üzerinde arama yapabilir ve ilgili kayıtların bir listesini döndürebilir, bu da SOQL'in yapısıyla çözülmesi zor olan, kullanıcı tarafından girilen arama terimlerini işlemek için idealdir.
| Sorgu Dili | Birincil Amaç | Anahtar Özellikler | Kullanım Senaryosu Örneği |
|---|---|---|---|
| SOQL | Yapılandırılmış Veri Sorgulama | WHERE, ORDER BY, LIMIT, GROUP BY, Aggregate fonksiyonlarını destekler. İlişkisel sorgular yapabilir. | "Bu ay kapanan ve toplam değeri 10.000$'ın üzerinde olan tüm Fırsatları (Opportunities) ve ilgili Hesap (Account) adlarını getir." |
| SOSL | Tam Metin Arama | Çoklu nesne üzerinde arama yapabilir. Bulanık eşleştirme (fuzzy matching) ve ağırlıklandırma sunar. | "Müşteri destep portalında, 'battery error' ifadesini Açıklama (Description) alanında içeren Tüm Vaka (Case) ve Bilgi Bankası (Knowledge) makalelerini ara." |
Apex içinde, SOQL sorguları köşeli parantezler `[]` içine yazılır ve doğrudan bir SOQL deyimi olarak veya bir String içinde dinamik olarak oluşturulabilir. Bu sorgular, bir kaydın listesini (`List
Ayrıca, Salesforce'un güçlü ilişkisel veri modeli, SOQL'in parent-to-child (alt sorgular) ve child-to-parent sorguları yazmasına izin verir, bu da karmaşık veri toplama ihtiyaçlarını tek bir sorguda karşılayabilir. Bu özellik, veritabanına yapılan seyahat sayısını en aza indirerek uygulama performansını optimize eder. SOQL ve SOSL, Apex geliştiricisinin Salesforce veri katmanına güçlü, güvenli ve verimli erişiminin temel araçlarıdır.
Tetikleyiciler ve İş Mantığı
Salesforce'ta, veri odaklı iş mantığını uygulamanın en yaygın ve güçlü yollarından biri Apex Tetikleyicileridir (Triggers). Tetikleyiciler, belirli bir Salesforce nesnesi üzerinde belirli bir veri manipülasyon dili (DML) olayı meydana geldiğinde otomatik olarak yürütülen Apex kod bloklarıdır. Bu olaylar, bir kaydın veritabanına eklenmesinden (insert), güncellenmesinden (update), silinmesinden (delete) veya geçici olarak kaydedilmesinden (upsert) önce (before) veya sonra (after) tetiklenebilir. Tetikleyiciler, veri bütünlüğü kurallarını zorlamak, karmaşık alan güncellemelerini otomatikleştirmek, ilgili kayıtları oluşturmak veya güncellemek ve harici sistemlerle entegrasyonu başlatmak için kritik öneme sahiptir.
Tetikleyiciler, `Trigger` adlı özel bir bağlam (context) değişkenine erişebilir. Bu değişken, tetiklenen olay hakkında, işlenmekte olan kayıtların listesi (`Trigger.new`, `Trigger.old`) gibi hayati bilgileri içerir. Örneğin, bir `Before Update` tetikleyicisinde, `Trigger.new` içindeki bir alanın değerini değiştirmek, kaydın veritabanına güncellenmeden önce bu yeni değeri kullanmasını sağlar. Bu, veri doğrulama ve otomatik hesaplama için idealdir. Tetikleyicilerin etkili ve verimli yazılması, özellikle toplu (bulk) işlemleri destekleyecek şekilde tasarlanmalarını gerektirir. Çünkü bir DML işlemi 200 kayıt üzerinde gerçekleşebilir ve tetikleyici tüm kayıt kümesi için bir kez çağrılır.
- Before Triggers: Kayıtlar veritabanına kaydedilmeden önce çalışır. Genellikle alan değerlerini doğrulamak veya otomatik olarak doldurmak için kullanılır. Bu aşamada kayıtların ID'si henüz yoktur (insert için).
- After Triggers: Kayıtlar veritabanına kaydedildikten sonra çalışır, kayıtların ID'si mevcuttur. Başka bir nesnedeki ilgili kayıtları güncellemek veya asenkron işlemler (future metodlar) başlatmak için kullanılır.
- Trigger Context Değişkenleri: `Trigger.isBefore`, `Trigger.isAfter`, `Trigger.isInsert`, `Trigger.new`, `Trigger.old`, `Trigger.newMap`, `Trigger.oldMap` gibi değişkenler tetikleyicinin mantığını yönlendirir.
- Bulkification Zorunluluğu: Tetikleyici kodunun, `Trigger.new` listesini döngüye alarak tüm gelen kayıtları işleyecek şekilde yazılması gerekir. Tek bir kayıt için SOQL veya DML içeren bir döngü, limit aşımlarına neden olur.
Modern Apex geliştirme pratikleri, tetikleyici mantığını mümkün olduğunca sade tutmayı ve karmaşık iş kurallarını, tetikleyiciden çağrılan ayrı Apex sınıflarına (genellikle "Handler" sınıfları) taşımayı önerir. Bu "Tetikleyici-Handler" deseni, kodun daha test edilebilir, yeniden kullanılabilir ve bakımı kolay olmasını sağlar. Tetikleyiciler, Salesforce platformunda iş süreçlerini otomatikleştirmenin ve veri merkezli kuralları uygulamanın merkezinde yer alır.
Test Zorunluluğu ve Çerçevesi
Salesforce, yazılım kalitesini ve platform istikrarını garanti altına almak için, Apex kodu için zorunlu bir test çerçevesi uygular. Bu, Apex'i diğer birçok programlama dilinden ayıran en önemli özelliklerden biridir. Kural basit ama katıdır: Her Apex sınıfı veya tetikleyicisi için, kodu en az %75 oranında kapsayan test sınıfları yazılmadan, hiçbir Apex kodu canlı (production) bir Salesforce organizasyonuna dağıtılamaz. Bu, test güdümlü geliştirme (TDD) pratiğini platform düzeyinde teşvik eder ve geliştiricileri kodlarını düşünülmüş bir şekilde test etmeye zorlar.
Apex test sınıfları, `@isTest` annotation'ı ile işaretlenir ve bu onları normal organizasyon veri limitlerinden muaf tutar. Test metodları, test verilerini oluşturma (setup), test edilecek kodu yürütme (exercise), sonuçları doğrulama (verify) ve test verilerini temizleme (teardown) adımlarını izler. Test sınıfları, sentetik test verileri üzerinde çalışır; varsayılan olarak, test yürütmesi organizasyondaki mevcut verilere erişemez (ancak `@isTest(SeeAllData=true)` ile bu değiştirilebilir). Bu izolasyon, testlerin güvenilir ve tekrarlanabilir olmasını sağlar.
- Test Verisi Oluşturma: Test metodları içinde SOQL, DML veya özel test verisi fabrika sınıfları kullanılarak gerekli test kayıtları oluşturulur. `Test.startTest()` ve `Test.stopTest()` blokları, governer limitleri sıfırlamak ve asenkron kodları senkron olarak test etmek için kullanılır.
- Doğrulama (Assertions): `System.assert()`, `System.assertEquals()` ve `System.assertNotEquals()` metodları, kodun beklenen şekilde çalışıp çalışmadığını doğrulamak için kullanılır. Başarısız bir assertion, testin başarısız olmasına neden olur.
- Kapsam Hesaplama: Salesforce, test sınıfları çalıştırıldığında hangi satırların Apex kodunun yürütüldüğünü izler. Bu, toplam yürütülen satır sayısının, toplam aktif satır sayısına bölünmesiyle kod kapsamı yüzdesini hesaplar.
- Performans ve Limit Testi: Testler aynı zamanda kodun governer limitleri içinde kalıp kalmadığını doğrulamak için bir fırsat sunar. Büyük veri kümeleriyle test yapmak, tetikleyicilerin ve sınıfların "bulkification"ını doğrulamak için çok önemlidir.
Bu zorunlu test yaklaşımı, sadece bir kalite kontrol önlemi değil, aynı zamanda sürekli entegrasyon ve sürekli dağıtım (CI/CD) işlem hatları oluşturmanın temelidir. Kapsamlı test paketleri, değişikliklerin mevcut işlevselliği bozmadığından (regression testing) emin olmayı sağlar. Testler olmadan dağıtım yoktur ilkesi, Salesforce ekosistemindeki uygulamaların genel güvenilirliğini ve kararlılığını korumada hayati bir rol oynar ve Apex geliştiricisinin disiplinlerinden biri haline gelmiştir.
Güçlü Yönler ve Sınırlamalar
Apex programlama dili, Salesforce platformuna özgü tasarımı sayesinde benzersiz avantajlar sunar. En önemli güçlü yanı, platformla derin ve yerel entegrasyonudur. Geliştiriciler, altyapı yönetimi, ölçeklendirme veya yük dengeleme gibi endişeler olmadan, doğrudan iş mantığına odaklanabilir. Veri modeli, güvenlik şeması (profiller, izin setleri) ve kullanıcı arayüzü ile sorunsuz çalışır. Ayrıca, multi-tenant mimarisi gereği otomatik yükseltmeler ve yamalar alır; Salesforce platformunda yapılan her güncelleme, Apex kodunun uyumluluğu korunarak arka planda gerçekleşir. Bu, şirketlerin en son güvenlik ve özellik geliştirmelerinden yararlanırken altyapı yönetimi yükünden kurtulduğu anlamına gelir.
Dilin güvenlik modeli de bir diğer kritik üstünlüktür. Apex kodu, "system context" altında çalışır, yani kodu çalıştıran kullanıcının izinlerini aşabilir. Bu, önemli ama kontrollü bir güçtür. Ancak, geliştirici bu gücü kullanırken, şirket verilerini korumak için kodun içine açık izin kontrolleri (`WITH SECURITY_ENFORCED` veya `Security.stripInaccessible()`) eklemelidir. Ayrıca, zorunlu test çerçevesi ve governer limitleri, kod kalitesini ve platform istikrarını proaktif olarak koruyan yerleşik mekanizmalar sağlar. Bu sınırlar, başlangıçta kısıtlayıcı görünse de, aslında ölçeklenebilir ve güvenilir uygulamalar geliştirmek için bir rehber görevi görür.
Ancak, Apex'in platforma özgü doğası beraberinde kaçınılmaz sınırlamalar getirir. En belirgin sınırlama, katı governer limitleridir. CPU süresi, bellek, veritabanı sorguları ve DML ifadeleri gibi kaynaklar için sert sınırlar vardır. Kötü yazılmış, verimsiz kod (örneğin, SOQL sorgularını bir döngü içine almak) bu limitleri kolayca aşabilir ve çalışma zamanı istisnalarına neden olabilir. Apex aynı zmanda genel amaçlı bir dil değildir; Salesforce ekosistemi dışında kullanılamaz. Dilin özellik seti, platformun ihtiyaçlarına göre belirlenir ve geliştirme, büyük ölçüde Salesforce'un sunduğu araçlara (IDE'ler, debug log'ları) bağımlıdır.
Diğer bir önemli kısıtlama, asenkron işleme modelleriyle ilgilidir. Uzun süren işlemler veya harici servis çağrıları (callouts) genellikle senkron tetikleyiciler içinde yapılamaz. Bunun yerine, `@future`, `Queueable Apex`, `Batch Apex` veya `Scheduled Apex` gibi özel asenkron framework'ler kullanılmalıdır. Bu modeller daha karmaşıktır ve durum yönetimi konusunda dikkatli olunmasını gerektirir. Ayrıca, dilin sürümü ve çalışma zamanı ortamı üzerinde tam kontrol Salesforce'ta olduğu için, geliştiriciler yeni dil özelliklerini veya kütüphaneleri keyfi olarak ekleyemezler. Tüm bu sınırlamalar, Apex geliştiricisinin platformun yetenekleri ve felsefesi içinde düşünmesini ve tasarım yapmasını gerektirir. Sonuç olarak, Apex'in gücü, onun Salesforce ile olan bütünleşik doğasından gelir, ancak aynı zamanda esnekliği de bu doğa tarafından şekillendirilir ve sınırlandırılır.
Performans optimizasyonu, Apex'te her zaman ön planda olmalıdır. Toplu işlem (bulkification) prensibi, tetikleyicilerden, Batch Apex'e kadar her yerde uygulanmalıdır. SOQL sorgularını ve DML ifadelerini döngülerin dışına almak, koleksiyonları ve haritaları (maps) verimli bir şekilde kullanmak, sorgu seçiciliğini artırmak ve gereksiz kod yürütmeyi önlemek, limitlerin içinde kalmak ve kullanıcı deneyimini korumak için hayati öneme sahiptir. Apex geliştiricisi, bir dil uzmanı olmanın yanı sıra, platformun kaynak yönetimi kurallarını da iyi bilen bir mimar olmalıdır.