KoderKoder.ai
FiyatlandırmaKurumsalEğitimYatırımcılar için
Giriş YapBaşla

Ürün

FiyatlandırmaKurumsalYatırımcılar için

Kaynaklar

Bize UlaşınDestekEğitimBlog

Yasal

Gizlilik PolitikasıKullanım KoşullarıGüvenlikKabul Edilebilir Kullanım PolitikasıKötüye Kullanımı Bildir

Sosyal

LinkedInTwitter
Koder.ai
Dil

© 2026 Koder.ai. Tüm hakları saklıdır.

Ana Sayfa›Blog›Barbara Liskov’un Veri Soyutlaması: Güvenilir API’ler İnşa Etmek
07 Haz 2025·8 dk

Barbara Liskov’un Veri Soyutlaması: Güvenilir API’ler İnşa Etmek

Barbara Liskov’un veri soyutlaması ilkelerini öğrenin: kararlı arayüzler tasarlayın, kırılmaları azaltın ve açık, güvenilir API'lerle sürdürülebilir sistemler kurun.

Barbara Liskov’un Veri Soyutlaması: Güvenilir API’ler İnşa Etmek

Neden Barbara Liskov API Tasarımı İçin Hâlâ Önemli?

Barbara Liskov, modern yazılım ekiplerinin "dağılıp gitmeyen" şeyler inşa etme şeklini sessizce şekillendiren bir bilgisayar bilimcisidir. Onun veri soyutlaması, bilgi gizleme ve daha sonra ortaya çıkan Liskov Yerine Geçme İlkesi (LSP) üzerine çalışmaları, programlama dillerinden API'leri düşünme biçimimize kadar her şeyi etkiledi: net davranış tanımlayın, iç yapıyı koruyun ve başkalarının arayüzünüze güvenmesini güvenli kılın.

Ürün terimleriyle “güvenilir arayüz”

Güvenilir bir API sadece teorik olarak "doğru" değildir. Ürünün daha hızlı ilerlemesine yardımcı olan bir arayüzdür:

  • Yeni özellikler mevcut müşterileri bozmadan yayınlanır.
  • Entegrasyonlar sürümler boyunca çalışmaya devam eder.
  • On-call olayları azalır çünkü hatalar öngörülebilirdir.
  • Takımlar, halka açık davranış sabit kaldığı sürece iç yapıyı değiştirebilir; büyük koordinasyon toplantalarına gerek kalmaz.

Bu güvenilirlik bir deneyimdir: API'yi çağıran geliştirici, onu sürdüren ekip ve dolaylı olarak ona bağımlı kullanıcılar için.

Veri soyutlaması nasıl hata (ve toplantı) sayısını azaltır

Veri soyutlaması, çağıranların bir konsept (hesap, kuyruk, abonelik) ile nasıl saklandığı veya hesaplandığı yerine küçük bir operasyon seti aracılığıyla etkileşmesi gerektiği fikridir.

Temsili ayrıntıları gizlediğinizde, belirli hata kategorilerini ortadan kaldırırsınız: kimse "kamuya açık olmayan" bir veritabanı alanına kazara güvenemez veya sistemi kaldıramayacak şekilde paylaşılan durumu mutasyona uğratamaz. Aynı derecede önemli olarak, soyutlama koordinasyon yükünü düşürür: halka açık davranış tutarlı kaldığı sürece ekiplerin iç yapıyı refactor etmesi için izin gerekmez.

Makaleyi bitirdiğinizde uygulayabilecekleriniz

Sonunda pratik yolları bileceksiniz:

  • API davranışlarını kenar durumları da dahil olmak üzere açık vaatler olarak yazmak.
  • Sistemler evrilirken arayüzleri küçük ve stabil tutmak.
  • Çağıranların ele alabileceği öngörülebilir hata modları tasarlamak.

Hızlı bir özet isterseniz, daha sonra /blog/a-practical-checklist-for-designing-reliable-apis bölümüne bakabilirsiniz.

Veri Soyutlaması — Jargondan Uzak Anlatım

Veri soyutlaması basit bir fikirdir: bir şeyle nasıl yapıldığıyla değil, ne yaptığıyla etkileşirsiniz.

Bir otomatı düşünün. Motorların nasıl döndüğünü veya paraların nasıl sayıldığını bilmenize gerek yok. Sadece kontrolleri bilirsiniz ("ürün seç", "öde", "ürünü al") ve kuralları ("yeterince öderseniz ürünü alırsınız; tükenmişse iade edilir"). İşte soyutlama budur.

“Ne yaptığı” vs. “Nasıl çalıştığı”

Yazılımda arayüz "ne yaptığı"dır: operasyon isimleri, kabul ettiği girdiler, döndürdüğü çıktılar ve beklenen hatalar. Uygulama ise "nasıl çalıştığı"dır: veritabanı tabloları, caching stratejisi, iç sınıflar ve performans hileleri.

Bunları ayrı tutmak, sistem evrilirken arayüzlerin stabil kalmasını sağlar. İç yapıyı yeniden yazabilir, kütüphane değiştirebilir veya depolamayı optimize edebilirsiniz—kullanıcılar için arayüz aynı kalır.

Bir dakikada Soyut Veri Tipleri (ADT)

Bir soyut veri tipi, belirli bir iç yapıya bağlı kalmadan tanımlanmış "kapsayıcı + izin verilen işlemler + kurallar"dır.

Örnek: Stack (son giren, ilk çıkar).

  • push(item): bir öğe ekle
  • pop(): en son ekleneni kaldır ve döndür
  • peek(): üstteki öğeye bak, kaldırma

Önemli olan vaat: pop() en son push() edilen öğeyi döndürür. Stack'in arkasında dizi mi, bağlı liste mi olduğu gizlidir.

Gerçek API'lere nasıl yansır

Aynı ayrım her yerde uygulanır:

  • REST uç noktaları: POST /payments arayüzdür; fraud kontrolü, retry'ler ve veritabanı yazımları implementasyon.
  • SDK metodları: client.upload(file) arayüzdür; chunking, sıkıştırma ve paralel istekler implementasyon.
  • UI bileşenleri: bir “DatePicker” props/event'leri açığa çıkarır; DOM yapısı ve erişilebilirlik altyapısı implementasyondur.

Soyutlama ile tasarladığınızda, kullanıcıların güvendiği sözleşmeye odaklanırsınız—ve perde arkasını değiştirme özgürlüğünü kazanırsınız.

İnvariantlar: Sistemleri Doğru Tutan Gizli Kurallar

Invariant, bir soyutlama içinde her zaman doğru olması gereken kuraldır. Bir API tasarlıyorsanız, invariantlar verinizin imkansız durumlara kaymasını engelleyen koruyuculardır—örneğin bir bankanın iki para birimine aynı anda sahip olması veya "tamamlanmış" bir siparişin öğe içermemesi gibi.

İnvariantlar nasıl görünür (matematik olmadan)

Invariantı tipin “gerçekliği” olarak düşünün:

  • Bir Cart negatif miktar içeremez.
  • Bir UserEmail her zaman geçerli bir e-posta adresidir ("daha sonra doğrulanacak" değil).
  • Bir Reservation için start < end ve her iki zaman da aynı zaman diliminde olmalıdır.

Bu ifadeler doğru olmaktan çıktığında, sistem tahmin edilemez hale gelir çünkü her özellik artık "bozuk" verinin ne anlama geldiğini tahmin etmek zorunda kalır.

İnvariantlar doğrulama ve hata yönetimini nasıl yönlendirir

İyi API'ler invariantları sınırda uygular:

  • Oluştururken: geçersiz girdileri erken reddedin (açık bir hata döndürün).
  • Güncellerken: invariantı koruyan değişikliklere izin verin.
  • Parse/IO sırasında: dış veriyi güvensiz kabul edin; saklamadan önce doğrulayın.

Bu, belirsiz hatalar yerine API'nin hangi kuralın ihlal edildiğini açıklamasını sağlar ("başlangıç, bitişten sonra olmalı" gibi).

İnvariantların arayüze sızmasına izin vermeyin

Çağıranlar "önce normalize() çağrısı yapın" gibi iç kuralları ezberlememeli. Eğer bir invariant özel bir ritüle bağlıysa, o bir invariant değil—bir hata silahıdır.

Arayüzü şöyle tasarlayın:

  • geçersiz durumlar temsil edilemez (veya zor temsil edilir)
  • metodlar invariantı otomatik korur

Pratik dokümantasyon kontrol listesi

Bir API tipi belgelendiğinde şunları yazın:

  1. Invariant ifadeleri (düz İngilizce/Türkçe, test edilebilir)
  2. Nerede uygulandığı (constructor, setter'lar, endpoint'ler)
  3. İhlal durumunda ne olur (hata tipi/mesajı, status kodu)
  4. Hangi metodlar korur (ve varsa istisnalar)
  5. Geçerli vs geçersiz girdi örnekleri (kısa, somut)

Sözleşmeler: Çağıranlar ve Bakım Yapanlar İçin Davranışı Netleştirin

İyi bir API sadece fonksiyonlar seti değildir—o bir vaattir. Sözleşmeler bu vaadi açık hale getirir; böylece çağıranlar davranışa güvenebilir ve bakım yapanlar iç yapıyı değiştirse bile kimse şaşırmaz.

Bir sözleşmede neyi açığa çıkarmalı

En azından şunları dokümante edin:

  • Önkoşullar: çağrıdan önce ne doğru olmalı (geçerli aralıklar, gereken izinler, thread-safety beklentileri).
  • Sonkoşullar: başarılı bir çağrı sonrası ne doğru olacak (dönüş değeri anlamı, durum değişiklikleri).
  • Yan etkiler: başka neler değişir (diske yazma, ağ istekleri, geçtiğiniz objelerin değiştirilmesi).

Bu netlik davranışı öngörülebilir kılar: çağıranlar hangi girdilerin güvenli olduğunu ve hangi sonuçları ele almaları gerektiğini bilir; testler de niyeti tahmin etmek yerine vaadi kontrol eder.

Sözleşmeler “kabile bilgisini” azaltır

Sözleşme yoksa ekipler hafızaya ve gayri resmi normlara güvenir: "Oraya null geçirme", "O çağrı bazen retry yapıyor", "Hata olursa boş döner" gibi. Bu kurallar onboarding, refactor veya olaylar sırasında kaybolur.

Yazılı bir sözleşme bu gizli kuralları paylaşılan bilgi haline getirir. Ayrıca kod incelemelerinde stabil bir hedef sağlar: tartışma "Bu değişiklik hâlâ sözleşmeyi sağlıyor mu?" haline gelir.

İyi ve belirsiz ifadeye örnekler

Belirsiz: "Kullanıcı oluşturur."

Daha iyi: "Eşsiz bir e-postayla kullanıcı oluşturur.\n\n- Önkoşullar: email geçerli olmalı; çağıranın users:create izni olmalı.\n- Sonkoşullar: yeni userId döner; kullanıcı kalıcı hale gelir ve hemen alınabilir.\n- Hata modları: e-posta zaten varsa 409; alanlar geçersizse 400; kısmi kullanıcı oluşturulmaz."

Belirsiz: "Öğeleri hızlıca alır."

Daha iyi: "createdAt azalan biçimde sıralanmış, limit kadar öğe döndürür.\n\n- Yan etkiler: yok.\n- Tutarlılık: en fazla 60 saniye kadar eski olabilir.\n- Sayfalama: sonraki sayfa için nextCursor kullanın; cursor'lar 15 dakikada dolar."

Bilgi Gizleme: İç Yapıyı Gizli Tutun, API'yi Stabil Tutun

Bilgi gizleme veri soyutlamasının pratik tarafıdır: çağıranlar API'nin ne yaptığına güvenmeli, nasıl yaptığına değil. İç yapı görünmezse, her sürüm bir kırılma haline gelmez.

Temsili değil, işlemleri açığa çıkarın

İyi bir arayüz küçük bir operasyon seti (create, fetch, update, list, validate) yayımlar ve temsili—tablolar, cache'ler, kuyruklar, dosya düzenleri—gizli tutar.

Mesela “sepete öğe ekle” bir işlemdir. Veritabanı CartRowId'si iç bir detaytır. Detayı açığa çıkardığınızda kullanıcılar kendi mantıklarını buna göre kurar ve bu da değişiklik yapmanızı zorlaştırır.

İç yapı gizlendiğinde refactor'lar neden güvenlidir

İstemciler sadece stabil davranışa bağlıysa şunları yapabilirsiniz:

  • veritabanını veya depolama formatını değiştirmek
  • monoliti servislere bölmek
  • cache eklemek veya indekslemeyi değiştirmek
  • iç modelleri yeniden düzenlemek

…ve API uyumlu kalır çünkü sözleşme yerinde durur. Gerçek kazanç budur: kullanıcılar için stabilite, bakım yapanlar için özgürlük.

Kaçak desenlere dikkat

İç yapı istemeden dışarı sızabilir:

  • İç ID'leri döndürmek (sadece storage katmanınızda anlamlı olan auto-increment sayıları, shard anahtarları).
  • Değiştirilebilir yapıların açılması (ham nesne döndürüp istemcinin onu patchleyip geri göndermesi).
  • İstemcinin iç durum oluşturmasına izin vermek, örn. status=3 gibi.

Stabil kalan cevap şekilleri tasarlamak

Anlamı, mekanikleri değil, tarif eden cevapları tercih edin:

  • Veritabanı satır numaraları yerine stabil, opak public identifier kullanın (örn. \"userId\": \"usr_…\").
  • Koleksiyonların kopyalarını veya salt okunur görünümlerini döndürün; istemcilerin sıralama veya iç alanlara kazara güvenmesini engelleyin.
  • Alan eklerken geriye dönük uyumluluğa dikkat edin; mevcut alanların anlamını değiştirmeyin.

Bir detay değişebilir görünüyorsa yayımlamayın. Kullanıcılar buna ihtiyaç duyuyorsa, onu kasıtlı ve belgelenmiş bir parça yapın.

Liskov Yerine Geçme İlkesi — Bir Arayüz Vaatidir

Test edilebilir bir derleme gönderin
Davranış ve belgeler üzerinde iterasyon yaparken API'nizi ve UI'ınızı deploy edip barındırın.
Uygulamayı Dağıt

LSP bir cümlede: Bir kod bir arayüzle çalışıyorsa, o arayüzün herhangi geçerli bir implementasyonu yerine konulduğunda özel durumlar gerektirmeksizin çalışmaya devam etmelidir.

LSP miras ile ilgili olmaktan çok güven ile ilgilidir. Bir arayüz yayımladığınızda davranış hakkında bir vaat verirsiniz. LSP der ki her implementasyon bu vaadi tutmalı, çok farklı iç yaklaşımlar kullansa bile.

LSP: çağıranı şaşırtmayın

Çağıranlar API'nin ne dediğine güvenir—bugün ne yaptığına değil. Arayüz "geçerli herhangi bir kayıtla save() çağırabilirsiniz" diyorsa, her implementasyon o kayıtları kabul etmelidir. Arayüz "get() değer döndürür veya net bir 'bulunamadı' sonucu verir" diyorsa, implementasyonlar rastgele yeni hatalar fırlatmamalıdır.

Güvenli genişletme, yeni implementasyonlar eklediğinizde veya sağlayıcı değiştirdiğinizde kullanıcıların kodunu yeniden yazmasını gerektirmez. Bu LSP'nin pratik faydasıdır: arayüzler değiştirilip yerine konabilir kalır.

API'lerde yaygın LSP ihlalleri

İki yaygın yol vardır:

  • Daha dar girdiler (daha katı önkoşullar): yeni implementasyon, arayüzün izin verdiği girdileri reddeder.
  • Daha zayıf çıktılar (daha gevşek sonkoşullar): yeni implementasyon, vaat edilenden daha az döner (sıralama yok, tekrarlar var veya öğeler atılıyor).

Üçüncü, ince bir ihlal de hata davranışını değiştirmektir: bir implementasyon "bulunamadı" dönerken diğeri aynı durumda istisna fırlatıyorsa, çağıranlar bunların yerine geçmesini güvenle yapamaz.

Eklenti/plug-in davranışını sürpriz olmadan tasarlamak

"Plug-in" desteklemek için arayüzü bir sözleşme gibi yazın:

  • Hangi girdilerin geçerli olduğunu belirtin ve tüm implementasyonlarda tutarlı tutun.
  • Çıktıların ne anlama geldiğini belirtin (sıralama, varsayılanlar, uç durumlar dahil).
  • Hata modlarını standardize edin: hangi hatalar olabilir ve ne anlama gelir.

Eğer bir implementasyon gerçekten daha katı kurallar gerektiriyorsa, aynı arayüzün arkasına saklamayın: ayrı bir arayüz tanımlayın veya supportsNumericIds() gibi açık bir yetenekle bunu belgeleyin; böylece istemciler bilerek tercih eder.

İyi Arayüzler Küçük, Uyuma Sahip ve Okunması Kolaydır

İyi tasarlanmış bir arayüz, çağıranın sadece ihtiyacı olanı (ve fazlasını değil) sunar; bunun sonucu aracı kullanmak “açık” hissidir. Liskov’un veri soyutlaması görüşü sizi dar, stabil ve okunaklı arayüzlere yönlendirir, böylece kullanıcılar iç ayrıntıları öğrenmeden güvenebilir.

Her şeyi yapan yerine uyumlu olanı tercih edin

Büyük API'ler genellikle ilgisiz sorumlulukları karıştırır: konfigürasyon, durum değişiklikleri, raporlama ve hata ayıklama tek bir yerde toplanır. Bu ne zaman güvenli çağrı yapıldığını anlamayı zorlaştırır.

Uyumlu bir arayüz aynı soyutlamaya ait davranışları gruplayarak sadece kuyruk davranışlarına (enqueue/dequeue/peek/size) odaklanır. Daha az kavram, yanlış kullanım yollarını azaltır.

Belirsiz parametrelerden kaçının

"Esneklik" genellikle "belirsiz" demektir. options: any, mode: string veya çok sayıda boolean (force, skipCache, silent) belirsiz kombinasyonlar yaratır.

Tercih edin:

  • farklı davranışlar için ayrı metodlar (örn. publish() vs publishDraft()), veya
  • küçük, iyi tiplenmiş bir options objesi ve belgelenmiş varsayılanlar.

Eğer bir parametre için kaynak kodu okumak gerekiyorsa, o parametre iyi bir soyutlamanın parçası değildir.

İsimlendirme arayüzün bir parçasıdır

İsimler sözleşmeyi iletir. Gözlemlenebilir davranışı tarif eden fiiller seçin: reserve, release, validate, list, get. Mekaforik ve aşırı zekice isimlerden kaçının. İki metod benzer geliyorsa kullanıcılar benzer davranışı varsayar—o yüzden bunu doğru kılın.

Ne zaman modüllere/ressurslara bölünmeli

Şu durumlarda ayırın:

  • farklı kullanıcı rolleri (örn. "admin" vs "consumer") farklı yetenekler gerektiriyorsa, veya
  • farklı parçalar farklı hızlarda değişiyorsa (biri sık, diğeri stabil kalmalı).

Ayrı modüller iç yapıyı evrilirken temel vaadi korumanıza izin verir. Büyümeyi planlıyorsanız, ince bir “core” paketi ve eklentiler yaklaşımını düşünün.

Kullanıcıları Kırmadan API'leri Evriltmek

Geliştirirken kredi kazanın
Koder.ai hakkında içerik oluşturarak veya ekip arkadaşlarınızı davet ederek kredi kazanın.
Kredi Kazan

API'ler nadiren sabit kalır. Yeni özellikler gelir, uç durumlar keşfedilir ve "küçük iyileştirmeler" gerçek uygulamaları sessizce kırabilir. Amaç arayüzü dondurmak değil—kullanıcıların zaten güvendiği vaatleri ihlal etmeden evrimleştirmektir.

Semantik sürümlendirme (pratik, sınırlarıyla)

SemVer bir iletişim aracıdır:

  • MAJOR: kırıcı değişiklik.
  • MINOR: geriye dönük uyumlu yeni işlev ekleme.
  • PATCH: niyet edilen davranışı değiştirmeden hata düzeltmesi.

Sınırı: hâlâ yargı gerekir. Bir "bug fix" kullanıcıların dayandığı davranışı değiştiriyorsa pratikte kırıcıdır—eskiden beklenen yanlış davranışa güvenmiş olabilirler.

Kırıcı değişiklikler sadece tiplerle ilgili değildir

Birçok kırıcı değişiklik derleyicide görünmez:

  • Kabul edilen değerleri katılaştırmak (eskiden kabul edilenleri reddetmek).
  • Anlamı değiştirmek (aynı alanlar farklı yorumlanıyor).
  • Zamanlamayı değiştirmek (hızlı olan çağrı yavaşlıyor veya blokluyor).
  • Hata davranışını değiştirmek (yeni kodlar, farklı retry'ler, kısmi sonuçlar).

Bunun yerine önkoşullar ve sonkoşullar bağlamında düşünün: çağıranların ne sağlaması gerektiği ve neler alabilecekleri.

Kullanıcıların gerçekten takip edebileceği deprecasyon yolları

Deprecation açık ve zamanlı olduğunda işe yarar:

  • Eski davranışı belgelerde ve yanıtlarda (uyarılar, header'lar, loglar) deprecated olarak işaretleyin.
  • Çifte destek penceresi sunun (eski ve yeni yan yana).
  • Net bir zaman çizelgesi yayınlayın (örn. "varsayılan 60 gün içinde yeni olacak, 180 günde kaldırılacak").

Soyutlama evrimi kolaylaştırır

Liskov tarzı veri soyutlaması, kullanıcıların neye güvenebileceğini daralttığı için evrimi kolaylaştırır. Çağıranlar sadece arayüz sözleşmesine bağlıysa, depolama formatını, algoritmaları ve optimizasyonları özgürce değiştirebilirsiniz.

Uygulamada güçlü araçlar da yardımcı olur. Örneğin bir React uygulaması veya Go + PostgreSQL backend üzerinde hızlı iterasyon yapıyorsanız, Koder.ai gibi chat odaklı bir iş akışı uygulamayı hızlandırabilir; ama temel disiplin değişmez: net sözleşmeler, stabil kimlikler ve geriye dönük uyumlu evrim isteğe bağlıdır.

Hata Yönetimi ve Başarısızlık Modları: Tahmin Edilebilirlik İçin Tasarla

Güvenilir bir API hiç başarısız olmayan değil—çağıranların anlayabileceği, ele alabileceği ve test edebileceği şekillerde başarısız olan bir API'dir. Hata yönetimi soyutlamanın bir parçasıdır: "doğru kullanım" ne anlama gelir ve dünya (ağlar, diskler, izinler, zaman) karşı çıktığında ne olur.

Programcı hataları vs çalışma zamanı hataları

İlk olarak iki kategori ayırın:

  • Programcı hataları: çağıran sözleşmeyi ihlal etti (geçersiz ID formatı, yanlış sıra ile metod çağırma, gerekli alanları unutma). Bunlar erken ve yüksek sesle yakalanmalı—genellikle doğrulama hatalarıyla.
  • Çalışma zamanı hataları: çağıran sözleşmeye uydu ama dışsal bir şey başarısız (timeout, bağımlılıkların erişilemezliği, kota). Bunlar temsil edilebilir ve kurtarılabilir olmalı.

Bu ayrım arayüzünüzü dürüst kılar: çağıranlar kodda neyi düzeltebileceklerini ve neyi çalışma zamanında ele almaları gerektiğini öğrenir.

Sözleşme hata şekline karar verdirir

Sözleşmeniz mekanizmayı önerir:

  • Doğrulama hataları sözleşme ihlalleri için.
  • İstisnalar kütüphanelerde gerçekten istisnai, yerel olmayan hatalar için.
  • Result tipleri (Ok | Error) beklenen hatalar için ve çağıranın açık ele almasını istediğiniz durumlarda.

Ne seçerseniz seçin, API genelinde tutarlı olun ki kullanıcılar tahmin etmesin.

Başarısızlık modlarını açık ve test edilebilir yapın

Operasyon başına olası hataları anlam bağlamında listeleyin: "versiyon eski olduğu için çakışma", "bulunamadı", "izin reddedildi", "rate limited" gibi. Stabil hata kodları ve yapılandırılmış alanlar sağlayın ki testler string eşlemeye bağımlı olmasın.

Retry, idempotensi ve kısmi başarı

Bir işlemin yeniden denenebilir olup olmadığını, hangi koşullarda olduğunu ve idempotensi nasıl sağlanacağını (idempotency key'leri, doğal istek ID'leri) belgeleyin. Kısmi başarı mümkünse (batch işlemler), başarılar ve hatalar nasıl raporlanır ve zaman aşımından sonra istemcinin hangi durumda olduğunu varsayması gerektiği tanımlanmalı.

Soyutlamaları Test Etmek: Arayüzün Vaate Uygun Olduğunu Kanıtlayın

Bir soyutlama bir vaattir: "Bu işlemleri geçerli girdilerle çağırırsanız bu sonuçları alırsınız ve bu kurallar her zaman geçerlidir." Test, kod değiştikçe bu vaadi korumanın yoludur.

Sözleşmeleri birim ve entegrasyon testlerine çevirin

Sözleşmeyi otomatik kontrol edilebilecek kontrollere çevirerek başlayın.

Birim testleri her operasyonun sonkoşullarını ve uç durumlarını doğrulamalıdır: dönüş değerleri, durum değişiklikleri ve hata davranışı. Arayüz "olmayan öğeyi silmek false döndürür ve hiçbir şey değiştirmez" diyorsa tam olarak bunu test edin.

Entegrasyon testleri gerçek sınırlar boyunca sözleşmeyi doğrulamalıdır: veritabanı, ağ, serileştirme ve auth. Birçok "sözleşme ihlali" ancak tipler encode/decode edilirken ya da retry/zaman aşımı olduğunda ortaya çıkar.

İnvariantlar için property-based testing

Invariantlar, geçerli operasyonların herhangi bir dizisinde doğru kalması gereken kurallardır (örn. "bakiye negatif olamaz", "ID'ler benzersizdir", "list() ile dönen öğeler get(id) ile alınabilir").

Property-based testing, bu kuralları rastgele ama geçerli girdiler ve operasyon dizileri üretip test ederek sınar; insanın düşünmediği köşe durumlarını bulmada etkilidir.

Tüketici odaklı sözleşme testi (consumer-driven)

Paylaşılan veya halka açık API'ler için tüketicilerin yaptıkları istek örneklerini ve güvendikleri yanıtları yayınlamalarına izin verin. Sağlayıcılar CI'da bu sözleşmeleri çalıştırarak değişikliklerin gerçek kullanımı kırmadığını doğrular.

Prodüksiyonda sözleşme sürüklenmesini izleyin

Testler her şeyi kapsayamaz; bu yüzden sözleşmenin değiştiğini gösteren sinyalleri izleyin: yanıt şekli değişiklikleri, 4xx/5xx oranlarında artış, yeni hata kodları, gecikme artışları, bilinmeyen alan veya deseralize hataları. Bunları endpoint ve sürüm bazında izleyin ki sürüklenmeyi erken tespit edip güvenle geri alabilelim.

Eğer teslim hattınızda snapshot veya rollback destekliyorsa, bunlar bu zihniyetle doğal olarak eşleşir: sürüklenmeyi erken tespit edin, sonra istemcileri orta bir olaya zorlamadan geri alın. (Örneğin Koder.ai snapshot ve rollback iş akışının parçasıdır; bu "önce sözleşme, sonra değişiklik" yaklaşımına uyar.)

Yaygın Anti-Desenler ve Kaçınma Yolları

Kontrol listesini uygulamaya koyun
Gerçek uç noktalar ve yanıtlarla API kontrol listenizi uygulamak için bir proje başlatın.
Projeyi Başlat

Soyutlamayı önemseyen takımlar bile anlık pratiklik uğruna zamanla API'yi özel durumlar yığınına dönüştürebilecek desenlere kayabilir. İşte tekrarlayan tuzaklar ve ne yapmalı:

Kalıcı feature flag'leri API düğmeleri olarak kullanmak

Feature flagler rollout için iyidir ama flag'ler halka açık, uzun ömürlü parametrelere dönüştüğünde (?useNewPricing=true, mode=legacy, v2=true) sorun başlar. Zamanla çağıranlar bunları beklenmedik şekillerde birleştirir ve birden fazla davranışı sonsuza dek desteklemek zorunda kalırsınız.

Daha güvenli yaklaşım:

  • Rollout flaglerini mümkünse dahili tutun.
  • Davranış farklı olmalıysa, bunu açık bir yetenek ve yaşam döngüsüyle ifade edin (ve eskiye kaldırma planı).
  • Hangi kombinasyonların geçerli olduğunu dokümante edin; gerisini açıkça reddedin.

Veritabanı kavramlarını arayüze sızdırmak

Tablo ID'leri, join anahtarları veya "SQL şeklinde" filtreler (where=...) isteyen API'ler istemcileri storage modelinizi öğrenmeye zorlar. Bu, refactor'ları kırıcı yapar.

Bunun yerine domain kavramları ve stabil identifierlar etrafında modelleyin. İstemcilerin "nasıl sakladığınızı" sormasına gerek kalmasın; ne istediklerini sorun.

“Bir alan daha ekle” refleksi

Alan eklemek zararsız görünür ama tekrarlanan "bir alan daha" değişiklikleri sorumlulukları bulanıklaştırır ve invariantları zayıflatır. İstemciler kazara bu detaylara bağlı hale gelir.

Uzun vadeli maliyeti azaltın:

  • Yeni bir kavram için odaklanmış bir tip tanımlayın.
  • İlgili alanları anlamlı bir nesne içine gruplayın.
  • Her eklemeyi bir sözleşme değişikliği olarak değerlendirin: neyi ima ediyor ve hangi koşullar her zaman doğru kalmalı?

Soyutlama çok katı hale gelirse

Aşırı soyutlama gerçek ihtiyaçları engelleyebilir—örneğin cursor desteklemeyen bir sayfalama veya "exact match" belirtmeyen bir arama. İstemciler bunu aşmak için workaround yapar; daha kötü performans ve daha fazla hata ortaya çıkar.

Çözüm kontrollü esnekliktir: açık uçlu kaçış yolları yerine (örn. desteklenen filtre operatorleri) küçük, iyi tanımlanmış uzatma noktaları sunun.

Yeteneği azaltmadan sadeleştirin

Sadeleştirme güçten almak anlamına gelmez. Kafa karıştırıcı seçenekleri deprecate edin ama altta yatan yeteneği daha temiz bir biçimle tutun: üst üste binen parametreleri tek yapılandırılmış istek objesiyle değiştirin veya "her şeyi yapan" uç noktayı iki uyumlu uç noktaya bölün. Sonra geçişi sürümlü dokümantasyon ve net deprecasyon takvimi ile yönlendirin.

Güvenilir API Tasarlamak İçin Pratik Kontrol Listesi

Liskov’un veri soyutlaması fikirlerini basit bir tekrarlanabilir kontrol listesiyle uygulayabilirsiniz. Amaç mükemmellik değil—API vaatlerini açık, test edilebilir ve evrilmesi güvenli kılmaktır.

Kısa kontrol listesi

  • Invariantlar: Veri veya kaynak hakkında her zaman doğru olması gerekenler nelerdir? (örn. "bakiye negatif olamaz", "ID'ler benzersiz", "öğeler stabil sırada döner").
  • Sözleşmeler: Her operasyon için önkoşullar, sonkoşullar ve yan etkileri yazın (ne değişmeyecek dahil).
  • Gizli temsil: Hangi detayların kasıtlı olarak özel olduğunu listeleyin (dep. formatı, cache, iç ID'ler) ve istemcilerin bunlara bağımlı olmasını engelleyin.
  • Evrim planı: Yetenek eklemeyi nasıl yapacağınızı kararlaştırın: sürümlendirme stratejisi, deprecasyon politikası ve eski davranış ne kadar desteklenecek.

Hızlı API inceleme iş akışı (tekrarlanabilir)

  1. Sadece arayüzü okuyun (implementasyon yok). Yeni bir ekip arkadaşı davranışı tahmin edebilir mi?
  2. 5 “hikaye testi” üzerinden geçin: normal vaka, boş vaka, sınır vakası, geçersiz girdi, ve hata vakası.
  3. Yerine geçme güvenliğini kontrol edin: birden fazla implementasyon varsa, birini diğerinin yerine koymak çağıranı şaşırtır mı?
  4. Gizli bağlılıkları tarayın: istemciler iç durum, zamanlama veya depolama ayrıntılarını bilmek zorunda mı?
  5. Yapmayı düşündüğünüz kırıcı değişiklikleri yazın, sonra liste boşalana veya bilinçli kabul edilene kadar yeniden tasarlayın.

Dokümantasyon şablonları (kopyala/yapıştır)

Kısa, tutarlı bloklar kullanın:

  • Operasyon: transfer(from, to, amount)
  • Gerektirir: amount > 0 ve hesaplar mevcut
  • Garanti eder: bakiyeler atomik olarak güncellenir; toplam bakiye korunur
  • Hatalar: InsufficientFunds, AccountNotFound, Timeout
  • Notlar: idempotensi, sıralama, performans beklentileri

İleri okuma (isteğe bağlı)

Derinleşmek isterseniz bakın: Abstract Data Types (ADTs), Design by Contract, ve Liskov Substitution Principle (LSP).

Eğer ekibiniz iç notlar tutuyorsa, bunları /docs/api-guidelines gibi bir sayfadan linkleyin ki inceleme iş akışı tekrar kullanılabilir kalsın—ve eğer yeni servisleri hızlıca oluşturuyorsanız (elle veya Koder.ai gibi sohbet destekli bir araçla), bu kılavuzları "hızlı yayınlama"nın vazgeçilmez bir parçası olarak görün. Güvenilir arayüzler hızın bileşik olarak fayda sağlamasını sağlar, tersine çevirmesini değil.

SSS

Barbara Liskov’un çalışmaları neden bugün API tasarımı için hâlâ önemli?

O, veri soyutlaması ve bilgi gizleme kavramlarını yaygınlaştırdı; bunlar modern API tasarımına doğrudan uyarlanır: küçük ve stabil bir sözleşme yayınlayın, implementasyonu esnek tutun. Kazanç pratiktir: daha az kırılma, güvenli refactor'lar ve tahmin edilebilir entegrasyonlar.

Ürün ve mühendislik terimleriyle “güvenilir bir arayüz” ne demektir?

Bir güvenilir API, zaman içinde arayanların güvenebileceği bir şeydir:

  • Yeni sürümler mevcut tüketicileri kırmaz.
  • Hata modları tutarlı ve belgelenmiştir.
  • İç yapılar, kamu davranışını değiştirmeden değiştirilebilir.

Güvenilirlik "hiç başarısız olmamak" değil; tahmin edilebilir şekilde başarısız olmak ve sözleşmeye sadık kalmaktır.

Bir API uç noktasını veya metodunu açık bir davranış vaadine nasıl dönüştürürüm?

Davranışı bir sözleşme olarak yazın:

  • Önkoşullar: çağrıdan önce ne doğru olmalı (geçerli aralıklar, izinler).
  • Sonkoşullar: başarı sonrası ne doğru olacak (dönen değerler, durum değişiklikleri).
  • Yan etkiler: başka neler değişir (yazma, ağ çağrısı, önbellek güncellemesi).

Boş sonuçlar, çoğaltmalar, sıralama gibi uç durumları da ekleyin ki çağıranlar beklentilere göre kod yazıp test edebilsinler.

Invariantlar nedir ve API bunları nerede uygulamalı?

Invariant, bir soyutlama içinde her zaman doğru olması gereken kuraldır (ör. “miktar hiçbir zaman negatif olamaz”). API bunları sınırda uygulamalıdır:

  • Oluşturma/güncellemede doğrulayın.
  • Geçersiz girdileri erken ve spesifik hatalarla reddedin.
  • “Önce normalize() çağrısı yap” gibi özel ritüeller gerektirmesine izin vermeyin.

Bu, downstream hatalarını azaltır çünkü sistem artık imkansız durumlarla uğraşmak zorunda kalmaz.

Bilgi gizleme nedir ve yanıt şekillerine/ID'lere nasıl uygulanır?

Bilgi gizleme, işlemleri ve anlamı açığa çıkarmak; iç temsili gizlemek demektir. Değiştirme ihtimali olan şeylere tüketicileri bağlamayın (tablolar, cache anahtarları, shard anahtarları).

Pratik taktikler:

  • Veritabanı satır ID'leri yerine stabil, opak public ID'ler kullanın (örn. usr_...).
  • İstemcinin iç durumu oluşturmasını istemeyin (ör. yerine anlamlı bir eylem).
Veritabanı kavramlarını API'ye sızdırmak neden uzun vadede sık görülen bir problem?

Çünkü istemcileriniz storage modelinize bağlandığında, bir schema değişikliği API kırılmasına dönüşür. Eğer filtreler, join anahtarları veya dahili ID'ler açıksa, refactor yapmak zorlaşır.

Bunun yerine alanı gizli tutun ve müşterilerin ne istediklerini sorun: “belirli tarih aralığındaki müşteri siparişleri” gibi domain odaklı sorgular sağlayın.

Pratik API terimleriyle Liskov Yerine Geçme İlkesi (LSP) nedir?

LSP demektir ki: bir arayüzle çalışan kod, o arayüzün herhangi geçerli bir uygulamasıyla da özel durumlara ihtiyaç duymadan çalışmaya devam etmelidir. API açısından bu, çağıranı şaşırtmama kuralıdır.

Yerine geçebilir uygulamalar desteklemek için standardize edin:

  • Geçerli girdi seti (hiçbir implementasyon daha katı önkoşullar eklememeli).
  • Çıktı garantileri (sıralama, tamlık, benzersizlik).
  • Hata davranışı (aynı durum için aynı anlamdaki hatalar).
Birden fazla implementasyon veya sağlayıcı olduğunda yaygın LSP ihlalleri nelerdir?

Dikkat edilmesi gerekenler:

  • Daha dar girdiler: yeni bir implementasyon, arayüzün kabul ettiği girdileri reddeder.
  • Daha zayıf çıktılar: öğeleri düşürür, sıralamayı bozabilir veya kısmi veri dönebilir.
  • Farklı hata semantiği: birisi “not found” dönerken diğeri istisna fırlatır.

Eğer bir implementasyon gerçekten ek kısıt gerektiriyorsa, aynı arayüzü gizlice değiştirmeyin: ayrı bir arayüz veya açık bir yetenek bayrağı sunun ki istemciler bilerek tercih etsin.

Küçük, uyumlu ve okunması kolay bir API nasıl tasarlanır?

Arayüzleri küçük ve uyumlu tutun:

  • Aynı soyutlamaya ait davranışları gruplayın.
  • options: any veya çok sayıda boolean gibi belirsiz parametrelerden kaçının.
  • Gözlemlenebilir davranışı anlatan isimler kullanın (, , , ).
Hata yönetimini nasıl tasarlamalıyım ki başarısızlıklar tahmin edilebilir ve test edilebilir olsun?

Hataları sözleşmenin bir parçası olarak tasarlayın:

  • Programcı hataları (sözleşme ihlalleri) ile çalışma zamanı hataları (zaman aşımı, quota, concurrency) ayrılmalı.
  • Testlerin mesaj stringlerine değil stabil hata kodlarına ve yapısal alanlara bakmasını sağlayın.
  • Yeniden deneme güvenliği ve idempotensi (anahtarlar, istek ID'leri) belgelenmeli; toplu işlemlerde kısmi başarı tanımlanmalı.

UYgulamada mekanizma ne olursa olsun (istisnalar vs sonuç tipleri) tutarlılık, kullanıcıların tahmin edebilmesi için daha önemlidir.

İçindekiler
Neden Barbara Liskov API Tasarımı İçin Hâlâ Önemli?Veri Soyutlaması — Jargondan Uzak Anlatımİnvariantlar: Sistemleri Doğru Tutan Gizli KurallarSözleşmeler: Çağıranlar ve Bakım Yapanlar İçin Davranışı NetleştirinBilgi Gizleme: İç Yapıyı Gizli Tutun, API'yi Stabil TutunLiskov Yerine Geçme İlkesi — Bir Arayüz Vaatidirİyi Arayüzler Küçük, Uyuma Sahip ve Okunması KolaydırKullanıcıları Kırmadan API'leri EvriltmekHata Yönetimi ve Başarısızlık Modları: Tahmin Edilebilirlik İçin TasarlaSoyutlamaları Test Etmek: Arayüzün Vaate Uygun Olduğunu KanıtlayınYaygın Anti-Desenler ve Kaçınma YollarıGüvenilir API Tasarlamak İçin Pratik Kontrol ListesiSSS
Paylaş
Koder.ai
Build your own app with Koder today!

The best way to understand the power of Koder is to see it for yourself.

Start FreeBook a Demo
status=3
  • Alan eklemeyi geriye dönük uyumlu şekilde yapın; mevcut alanların anlamını değiştirmeyin.
  • reserve
    release
    list
    validate

    Farklı roller veya değişim hızları varsa modülleri ayırın; çekirdek ve eklenti yaklaşımı büyürken faydalıdır.