Mert Özen Her Satırda Daha İleri
Yapay Zeka GitHub Copilot — #02

Inline Suggestion ve Next Edit Suggestions: Tamamlamayı Verimli Kullanmak ve Ne Zaman Kapatmak

Mert Özen 15 Kas 2026 9 dk 4 görüntülenme
Inline Suggestion ve Next Edit Suggestions: Tamamlamayı Verimli Kullanmak ve Ne Zaman Kapatmak

Inline suggestion'ı Tab ile değil, kelime ve satır kabulüyle okuyarak almak ve testin beklenen değerini asla tamamlamaya bırakmamak gerekir: Bookstore'da formülü tekrar eden bir test doğru kodu kırmızı gösterdi, kodu ona uydurmak ise elle seçilmiş değerli eski testleri kırdı. Kısayollar, NES, context ve dil bazında kapatma.

Sürüm notu: Bu yazıdaki kodlar .NET 10, Entity Framework Core 10.0.15 ve xUnit.net v3 4.0.3 ile derlenip denenmiştir. Inline suggestion ve next edit suggestions davranışı 15 Kasım 2026 itibarıyla Visual Studio 2026 (18.12) ve Visual Studio Code (VS Code) 1.146 dokümanlarından alınmıştır; bu yazı için Copilot oturumu açılmamış, gösterilen hiçbir kod Copilot'un önerisi değildir.

Önce Tahmin Et

Ayşe, sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) için sipariş satırı toplamına bir test yazıyor. Method imzasını yazıp Enter'a basıyor, gri metin olarak gelen gövdeyi Tab ile kabul ediyor. Beklenen değer, satır toplamının "bariz" hesabıyla üretiliyor:

decimal expected = Math.Round(price * quantity, 2);

Assert.Equal(expected, OrderItem.CalculateLineTotal(price, quantity));

Test kırmızı yanıyor. Tahminin ne? Hata kodda mı, testte mi? Ve test yeşile dönsün diye kodu "düzeltirsek" ne olur? İkisini de bu yazıda gerçek test çıktılarıyla göreceğiz; ama önce tamamlamanın nasıl çalıştığına bakalım.

Ghost Text'i Kabul Etmek: Tamamı, Kelime Kelime, Satır Satır

Inline suggestion, imlecin olduğu yere gri ve italik bir metin olarak gelir. Visual Studio 2026'da bu metin renklendirilmiş (syntax highlighting'li) gösteriliyor ama düşük opaklıkla, ki kendi kodundan ayrılsın. Öneriyi almanın tek yolu Tab değil; çoğu zaman en iyi kullanım bir kısmını almak:

İşVisual Studio 2026VS Code
Tamamını kabul etTabTab
ReddetEsc ya da yazmaya devam etEscape
Kelime kelime alCtrl+Sağ okCtrl+Sağ ok
Satır satır alCtrl+Aşağı okCommand Palette'te "Accept Next Line Of Inline Suggestion"
Alternatiflere bakAlt+. (sonraki), Alt+, (önceki)Önerinin üstüne gelince çıkan araç çubuğu
Elle tetikleAlt+. ya da Alt+,"Trigger Inline Suggestion" komutu

Visual Studio'da bir de tıklayarak kısmi kabul var: fareyi önerinin üstünde gezdirince kabul edilecek kısım vurgulanıyor, tıkladığın yere kadar olan kısım alınıyor. IntelliSense listesi açıkken Copilot önerileri bekletiliyor; listeyi kapatınca geri geliyor. Kelime ve satır kabulünün değeri şu: öneri genelde ilk yarısında doğru, sonlara doğru tahmine dönüşüyor. İlk satırı alıp geri kalanını kendin yazmak, yarısı yanlış bir bloğu kabul edip sonra düzeltmekten hem hızlı hem güvenli.

Next Edit Suggestions: Değişikliğin Devamı

NES (next edit suggestions; az önceki düzenlemeden yola çıkıp dosyada bir sonraki değişikliğin yerini ve içeriğini öneren özellik), ghost text'ten farklı bir soruya cevap veriyor. Ghost text "imlecin olduğu yere ne yazılacak?" diye sorar; NES ise "bu değişikliği yaptıysan, başka nereyi değiştirmen gerekiyor?" diye sorar. VS Code'da NES önerisi geldiğinde Tab seni önerinin olduğu yere götürür, ikinci Tab kabul eder, Escape reddeder. Visual Studio dokümanı da NES'i, düzenleme alışkanlığına bakıp bir sonraki düzenlemenin hem yerini hem içeriğini tahmin eden bir inline suggestion türü olarak tanımlıyor.

En çok işe yaradığı yer refactoring zincirleri. Bu yazının Bookstore değişikliğinde kurumsal müşteriler için Institutional module'ünü ekledik ve Institution entity'sine sonradan bir Code property'si ekledik. Bu tek değişikliğin devamı üç yerde: configuration'da HasMaxLength ve unique index, seed verisinde her kayda bir kod, endpoint'in döndüğü record'da yeni alan. Bunlar tam NES'in tahmin etmeye çalıştığı türden, aynı dosyada ya da yakın dosyalarda tekrar eden düzenlemeler. VS Code'da github.copilot.nextEditSuggestions.fixes ayarı NES'e derleyici uyarılarından (eksik using gibi) öneri üretmesini de söylüyor.

NES'in bir bedeli var: önerisi bazen imlecin olduğu yerden uzakta çıkar ve dikkatini dağıtır. editor.inlineSuggest.edits.showCollapsed ayarı öneriyi sen oraya gidene kadar kapalı (yalnız gutter'da bir işaret olarak) tutuyor. Bu ayarı bu yazının sonunda repo'ya ekledik.

Öneri Kalitesini Ne Belirliyor

Inline suggestion, imlecin çevresindeki koda ve editörde açık olan dosyalara bakıyor; VS Code dokümanı ilgili dosyaların açık olmasının Copilot'a projenin daha geniş resmini verdiğini söylüyor. Bu yüzden önerinin kalitesi büyük ölçüde senin elinde: hangi dosyaların açık olduğu, isimlerin ne kadar açık olduğu, niyeti anlatan bir yorum satırı.

Bookstore'da bunun en net örneği Entity Framework Core (EF Core) configuration'ları. Her module'ün configuration'ı aynı kalıpla yazılmış: kendi schema'sında bir tablo, her string için HasMaxLength, enum'lar için HasConversion<string>(), seed verisi için HasData. Institutional module'ünün configuration'ını yazarken CatalogConfiguration.cs ve OrderingConfiguration.cs'i açık tutmak, tamamlamanın bu kalıbı izleme ihtimalini artırır. Sonuç şu dosya oldu:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Bookstore.Institutional;

internal sealed class InstitutionConfiguration : IEntityTypeConfiguration<Institution>
{
    public void Configure(EntityTypeBuilder<Institution> institution)
    {
        institution.ToTable("Institutions", "institutional");
        institution.Property(i => i.Name).HasMaxLength(200);
        institution.Property(i => i.Code).HasMaxLength(20).IsUnicode(false);
        institution.HasIndex(i => i.Code).IsUnique();
        institution.Property(i => i.Kind).HasConversion<string>().HasMaxLength(20);
        institution.HasMany(i => i.Units).WithOne().HasForeignKey(u => u.InstitutionId).OnDelete(DeleteBehavior.Cascade);
        institution.HasData(InstitutionalSeed.Institutions);
    }
}

internal sealed class InstitutionUnitConfiguration : IEntityTypeConfiguration<InstitutionUnit>
{
    public void Configure(EntityTypeBuilder<InstitutionUnit> unit)
    {
        unit.ToTable("InstitutionUnits", "institutional");
        unit.Property(u => u.Name).HasMaxLength(200);
        unit.HasOne(u => u.ParentUnit).WithMany().HasForeignKey(u => u.ParentUnitId).OnDelete(DeleteBehavior.Restrict);
        unit.HasData(InstitutionalSeed.Units);
    }
}

Bu dosyanın ilk beş satırı komşu dosyalardan tahmin edilebilir; tamamlama burada iyi iş çıkarır. Asıl karar gerektiren satırlar ise kalıbın dışında kalanlar: Code'un neden IsUnicode(false) ve neden unique olduğu, birim hiyerarşisinde silme davranışının neden Restrict olduğu. Cascade seçilseydi SQL Server, tablonun kendisine bağlanan bu foreign key döngü ya da birden fazla cascade yolu oluşturabileceği için constraint'i reddederdi (ayrı bir deneme veritabanında "may cause cycles or multiple cascade paths" hatasını aldık). Daha önemlisi, buna izin verilseydi bir kampüsü silmek altındaki bölümleri de sessizce silerdi. Bu tür satırları tamamlamadan değil, iş kuralından yazmak gerekiyor.

Tamamlamanın hiç yapmaması gereken iş de var: migration. Configuration bittikten sonra migration'ı araçla üretiyoruz, elle ya da tahminle değil:

$ dotnet ef migrations add AddInstitutions --project src/Bookstore.Api --output-dir Data/Migrations
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'

Üretilen Up method'unda institutional schema'sı, iki tablo, iki foreign key ve seed satırları var. Migration'ın review'u EF Core serisinin konusu; burada önemli olan, migration dosyasının tamamlamayla yazılacak bir dosya olmaması. Aynı mantık Angular tarafında da geçerli: bookstore-web'in template'lerinde para gösterimi hep currency: 'TRY' : 'symbol-narrow' pipe'ıyla, test edilen elementler hep data-testid ile yazılmış. Bu kalıplar açık dosyalardan kolayca tamamlanır; ama yeni bir signal'ın neyi hesaplayacağı yine senin kararın.

Testte Tab'in Bedeli

Önce Tahmin Et'teki teste dönelim. OrderItem.CalculateLineTotal, Requirements Analysis serisinde konuşulan kurala göre satır toplamını iki haneye yuvarlıyor ve yarım kuruşu sıfırdan uzağa (MidpointRounding.AwayFromZero) yuvarlıyor. Testin tamamı:

[Theory]
[InlineData("0.125", 1)]
[InlineData("0.145", 1)]
public void Line_total_matches_the_formula(string unitPrice, int quantity)
{
    decimal price = decimal.Parse(unitPrice, CultureInfo.InvariantCulture);

    // Beklenen değer, implementasyonun formülünü tekrar ediyor.
    decimal expected = Math.Round(price * quantity, 2);

    Assert.Equal(expected, OrderItem.CalculateLineTotal(price, quantity));
}
failed Bookstore.Api.Tests.OrderItemMirrorTests.Line_total_matches_the_formula(unitPrice: "0.125", quantity: 1) (6ms)
  Assert.Equal() Failure: Values differ
  Expected: 0.12
  Actual:   0.13
failed Bookstore.Api.Tests.OrderItemMirrorTests.Line_total_matches_the_formula(unitPrice: "0.145", quantity: 1) (0ms)
  Assert.Equal() Failure: Values differ
  Expected: 0.14
  Actual:   0.15
Test run summary: Failed!
  total: 5
  failed: 2
  succeeded: 3
  skipped: 0

İlk cevap: kod doğru, test yanlış. Math.Round(decimal, int) varsayılan olarak banker's rounding kullanıyor (yarım değeri en yakın çift sayıya yuvarlıyor); test, iş kuralını değil bu varsayılanı kodluyor. IDE'ler serisinin dokuzuncu yazısında banker's rounding'i bir sınır değeri testi yakalamıştı; buradaki fark, hatanın test tarafında olması.

Asıl tehlike bundan sonra başlıyor. Kırmızı testi gören biri, testin de Tab ile gelmiş olduğunu unutup "kod yanlış" diye düşünebilir ve AwayFromZero'yu silip testi yeşile çevirebilir. Bunu gerçekten denedik:

failed Bookstore.Api.Tests.OrderItemTests.Line_total_is_rounded_to_two_decimals(unitPrice: "0.125", quantity: 1, expected: "0.13") (5ms)
  Assert.Equal() Failure: Values differ
  Expected: 0.13
  Actual:   0.12
failed Bookstore.Api.Tests.OrderItemTests.Line_total_is_rounded_to_two_decimals(unitPrice: "0.145", quantity: 1, expected: "0.15") (0ms)
  Assert.Equal() Failure: Values differ
  Expected: 0.15
  Actual:   0.14
Test run summary: Failed!
  total: 5
  failed: 2
  succeeded: 3
  skipped: 0

Yeni test yeşile döndü, ama bu sefer repo'da zaten var olan OrderItemTests kırmızı yandı. O testin beklenen değerleri bir formülle değil, iş kuralından elle seçilmiş sayılarla yazılmış: 0,125 için 0,13, 0,145 için 0,15. Bizi kurtaran tam olarak bu. İki ders çıkıyor. Testin beklenen değerini tamamlamaya bırakma; sayıyı iş kuralından sen seç. Ve beklenen değeri implementasyonla aynı formülle hesaplayan bir test, ya implementasyonu kopyalar (hiçbir şeyi test etmez) ya da bu örnekteki gibi farklı bir varsayılanı kodlar. Deneyden sonra yeni testi sildik, kodu geri aldık; repo'da yalnız elle seçilmiş değerlerle yazılmış test kaldı.

Ne Zaman Kapatmalı

Tamamlamayı kapatmanın birkaç iyi sebebi var: düzyazı yazarken öneriler düşünceyi bölüyorsa, bir algoritmayı ya da sınavı kendin çözmeyi öğreniyorsan, ya da gizli bilgi içeren bir dosyadaysan. VS Code'da dil bazında açıp kapatmak github.copilot.enable ayarıyla yapılıyor; * bütün diller için varsayılanı belirliyor. Bookstore'a eklediğimiz workspace ayarı:

{
  "github.copilot.enable": {
    "*": true,
    "plaintext": false,
    "markdown": false
  },
  "github.copilot.nextEditSuggestions.enabled": true,
  "editor.inlineSuggest.edits.showCollapsed": true
}

Markdown'ı kapattık çünkü repo'daki Markdown dosyaları (README, sonraki yazılarda gelecek talimat dosyaları) düz yazı ve orada önerinin yazdığı cümle ekibin kararı gibi görünüyor. Kısa süreli ara için VS Code'un Status Bar menüsündeki Snooze her tıklamada beş dakika ekliyor. VS Code ayrıca ücretli (metered) bağlantıdayken otomatik ghost text ve NES isteği başlatmıyor; elle tetikleme çalışmaya devam ediyor.

Visual Studio'da ayarlar Tools > Options > Text Editor > Inline Suggestions altında. "Inline Suggestions Invocation" Manual yapılırsa öneri yalnız Alt+. ya da Alt+, ile geliyor; "Show inline suggestions only after a pause in typing" ise yazarken önerilerin yanıp sönmesini engelleyen bir gecikme ekliyor. Kabul tuşunu Tab yerine Sağ ok yapmak da mümkün.

Dil bazında kapatmanın bir sınırı var: appsettings.Development.json'ı kapatmak için JSON'u kapatman gerekir, bu da bütün JSON dosyalarını etkiler. Dosya bazında kural Copilot Business ve Enterprise'daki content exclusion ile koyuluyor; Visual Studio dokümanı, dışarıda bırakılan dosyalarda tamamlamanın çalışmadığını söylüyor. Content exclusion ve sınırları onuncu yazıda. Asıl önlem ise değişmiyor: gerçek bir secret geliştirme makinesinde düz dosyada durmamalı.

Üretimde Dikkat

Public kodla eşleşen öneriler. Organization'da "Suggestions matching public code" policy'si eşleşen önerileri engelleyebilir ya da izin verip bildirebilir. İzin verildiğinde Visual Studio, bir tamamlama public bir GitHub reposundaki kodla eşleştiğinde bunu bildiriyor; Output penceresindeki Copilot log'unda lisans bilgisine giden bir bağlantı ve benzer kodun referansları görünüyor. Lisans kararını o kayda bakarak sen veriyorsun.

Maliyet değil, kalite. Ücretli planlarda inline suggestion ve NES kredi harcamıyor (ilk yazı); Free planda ise ayda 2.000 tamamlama sınırı var. Kapatma kararını bütçeye göre değil, dosyanın türüne ve işin doğasına göre ver.

Review'da kaynağı sorma. Diff'te bir satırın tamamlamayla mı yazıldığı görünmez ve önemli de değil; sorumluluk commit'i atanda. Ama testlerde beklenen değerin nereden geldiğini sormak, bu yazıdaki türden hataları review'da yakalatıyor.

Sık Düşülen Tuzaklar

Öneriyi okumadan Tab'lemek. Özellikle uzun bloklarda son satırlar tahmindir; kelime ve satır kabulüyle yalnız okuduğun kısmı al.

Testin beklenen değerini tamamlamaya yazdırmak. Bu yazıdaki gibi ya implementasyonu kopyalar ya da yanlış bir varsayılanı kodlar; iki durumda da test iş kuralını korumaz.

Kırmızı testi görünce otomatik olarak kodu değiştirmek. Önce testin doğru olduğundan emin ol; elle seçilmiş değerlerle yazılmış eski testler burada hakem.

Migration, lock dosyası ya da üretilmiş kodu tamamlamayla yazmak. Bunlar araçla üretilir.

Secret içeren dosyalarda tamamlamayı açık bırakmak ve dil bazında kapatmanın bunu çözdüğünü sanmak. Dosya bazında çözüm content exclusion; asıl çözüm secret'ı dosyada tutmamak.

Küçük Bir Deneme

★☆☆ Bir hafta boyunca Tab yerine yalnız kelime ve satır kabulüyle çalış. Gün sonunda kabul ettiğin önerilerden kaçını sonradan düzelttiğini not et ve önceki haftayla karşılaştır.

★★☆ Bookstore'da InstitutionUnit'e CostCenter adında bir string property ekle. Değişikliğin devamı olan düzenlemeleri (configuration, seed, endpoint record'u, test) önce kendin listele, sonra NES'in hangilerini önerdiğine bak. Migration'ı dotnet ef ile üret.

★★★ OrderItemTests'e üç sınır değeri daha ekle (örneğin adet 3 ve birim fiyat 0,335). Beklenen değerleri iş kuralından elle hesapla; sonra aynı testleri MidpointRounding.ToEven ile çalıştırıp hangilerinin farkı yakaladığını gör.

Tamamlama, imlecin etrafında çalışan en dar yardım. Bir sonraki yazıda soruyu genişletiyoruz: Copilot Chat'in Ask, Plan ve Agent akışları, #-referansları, workspace index ve "Ordering module'ünde iptal akışı nasıl çalışıyor" sorusunu doğru context'le sormak.