Kullanımdan kaldırılmış bir fonksiyonu çağıran tüm fonksiyonları bulun.

Eski bir fonksiyonu kaldırmadan önce, o fonksiyonu çağıran tüm yerleri nasıl bulabilirsiniz?

Bir kod tabanından kullanımdan kaldırılmış bir fonksiyonu kaldırmak, kavramsal olarak bir geliştiricinin yapabileceği en basit şeylerden biridir. Tanımı silin, hiçbir şeyin onu kullanmadığını doğrulayın, değişiklikleri kaydedin. Uygulamada, kullanımdan kaldırılacak kadar uzun süredir var olan herhangi bir fonksiyon için, "hiçbir şeyin onu kullanmadığını doğrulayın" adımı, sürecin aksadığı noktadır. Fonksiyon, artık ekipte olmayan biri tarafından yıllar önce yazılmış bir koddan, nadiren değişiklik alan bir depodan, mevcut ekibin sahip olmadığı bir dil veya çerçeveden çağrılabilir. Bir sarmalayıcı aracılığıyla, yansıma yoluyla veya herhangi bir statik çağrı grafiğinde görünmeyen bir çalışma zamanı dağıtım mekanizması aracılığıyla dolaylı olarak çağrılabilir. Oluşturulan kodda, test iskeletinde veya adıyla tetikleyen bir yapılandırma dosyasında referans verilebilir. Fonksiyonu kullanımdan kaldırılmış olarak işaretleyen geliştirici ve sonunda onu kaldıran geliştirici, eksiksiz, depolar arası çağırıcı envanteri oluşturabilen bir araç olmadan bunların hiçbirini bilemeyebilir.

Herhangi bir şeyi kaldırmadan önce tüm arayanları bulun.

SMART TS XL Değişiklik yapmadan önce herhangi bir fonksiyonun her çağırıcısını belirleyen, diller arası bir çağrı grafiği oluşturur.

Buraya Tıkla

Bu konuda hata yapmanın maliyeti anında ve somuttur. Eksik çağrı keşfiyle kaldırılan bir fonksiyon, ona hala bağımlı olan sistemlerde çalışma zamanı hatalarına neden olur. Tek bir dağıtıma sahip monolitik bir sistemde, hata yüzeyi sınırlıdır. Her biri bağımsız olarak dağıtılan birden fazla hizmete sahip dağıtılmış bir sistemde, hatalar zincirleme reaksiyonla yayılır: fonksiyonu sağlayan hizmet güncellenir, tüketiciler güncellenmez ve üretimde, farklı ekiplere ait olabilecek sistemlerde çalışma zamanında bozulmalar ortaya çıkar. COBOL programlarının paylaşılan yardımcı program paragraflarını adlarıyla çağırdığı bir ana bilgisayar ortamında, hata belirli bir toplu iş çalışana kadar ortaya çıkmayabilir; bu da haftalık veya aylık olabilir ve eksik referansı normal test döngülerinde görünmez hale getirir. Eski kodun yönetimi bağlamında incelendiğinde , riskler zamanla artar: eksik kaldırılan eski kod, yerinde bırakılan eski koddan daha tehlikelidir, çünkü kaldırma işlemi, kalan çağrı yapanlar artık mevcut olmayan bir tanıma karşı çalışmaya devam ederken, eksiksizlik yanılsaması yaratır.

Bu makale, fonksiyon kaldırmadan önce çağrı yapanı keşfetmeye yönelik pratik bir kılavuzdur: eksiksiz bir çağrı yapan envanterinin neler gerektirdiği, geliştiricilerin ilk başvurduğu araçların yapısal olarak neden yetersiz olduğu, farklı çağrı ilişkisi türlerinin neden farklı analiz yaklaşımları gerektirdiği ve dilleri, platformları ve depoları karıştıran kurumsal ölçekli kod tabanlarında gerçek sistemler arası çağrı yapan numaralandırmanın nasıl göründüğü konularını ele almaktadır.

Arayan Kişiyi Bulma İşlemi Neden Göründüğünden Daha Zor?

Çağrı yapan fonksiyonları bulmanın yüzeysel versiyonu her geliştiriciye tanıdık gelir: Bir IDE'de bir fonksiyon adına sağ tıklayın, "Tüm Referansları Bul" veya "Çağrı Hiyerarşisini Göster"i seçin ve sonuçları inceleyin. Bu, tek bir IDE örneğinde yüklenen tek bir proje kapsamında güvenilir bir şekilde çalışır. Kod tabanı bu kapsamın ötesine geçtiği anda, sonuçlar çıktıda görünmeyen şekillerde eksik hale gelir. IDE, hangi çağrı yapan fonksiyonları bulamadığını göstermez çünkü bunları içeren depoları indekslememiştir. Geliştirici, eksiksiz görünen bir sonuç kümesi görür ve buna göre ilerler.

Bu, büyük ölçekte çağrı yapanı bulmanın yapısal sorunudur: geliştiricilerin en akıcı şekilde kullandığı araçlar, indeksleme kapsamlarıyla sınırlıdır ve büyük, dağıtılmış, çok dilli sistemlerde bu kapsam, belirli bir fonksiyonun çağrılabileceği yerlerin yalnızca küçük bir bölümünü kapsar. Geliştiricinin sonuçların eksiksizliğine olan güveni, aramanın gerçek eksiksizliğiyle ters orantılıdır. Küçük, tek dilli bir kod tabanında, IDE çağrı hiyerarşisi gerçekten güvenilirdir. Birden fazla depoyu, dili ve dağıtım ortamını kapsayan kurumsal bir sistemde ise sistematik olarak yanıltıcıdır. Kod entropisi ve yeniden düzenleme riski bağlamında analiz edildiğinde , eski modüller kullanımdan kaldırılmış arayüzlere bağımlı olabilirken, daha yeni hizmetler hala daha önceki ortamlar için tasarlanmış rutinleri çağırır ve bu sistemler arası çağrı ilişkileri, IDE'ye bağlı aramanın göremediği ilişkilerdir.

Arayan tespitinin başarısız olmasının özel nedenlerini anlamak, her bir ana çağrı türünü incelemeyi gerektirir: doğrudan çağrılar, dolaylı çağrılar, diller arası çağrılar ve dinamik yönlendirme. Her biri farklı nedenlerle başarısız olur ve doğru şekilde çözmek için farklı analiz teknikleri gerektirir.

Depo Sınırları Arasında Doğrudan Çağrılar

Doğrudan çağrılar en basit çağrı türüdür: bir fonksiyonun başka bir fonksiyonu adıyla açıkça çağırması. Tek bir depo içinde, IDE'ler bunları güvenilir bir şekilde işler. Depo sınırları arasında ise analiz başarısız olur çünkü IDE'nin indekslemesi sınırı kapsamaz. Eğer A deposu paylaşılan bir yardımcı fonksiyon tanımlıyorsa ve B, C ve D depolarının her biri bu fonksiyonu içe aktarıp çağırıyorsa, bu depolardan herhangi birinin IDE'si yalnızca kendi indekslenmiş kapsamındaki çağrıları görür.

Bu çoklu depo çağrı modeli, paylaşımlı kütüphanelerin paketler halinde yayınlandığı ve düzinelerce servis tarafından kullanıldığı mikroservis mimarilerinde istisna değil, normdur. Paylaşımlı paketteki bir fonksiyonu kullanımdan kaldıran kütüphane yöneticisinin, hangi kullanan servislerin hala bu fonksiyonu çağırdığını bilmesi gerekir. IDE'si tüketiciler hakkında hiçbir şey bilmez. Paket yöneticisi, hangi servislerin pakete bağımlı olduğunu bilir, ancak her servisin paket içindeki hangi belirli fonksiyonu çağırdığını bilmez. "Bu servis bu paketin X sürümünü kullanıyor" ifadesinden "bu servis bu belirli kullanımdan kaldırılmış fonksiyonu çağırıyor" ifadesine eşleme, her tüketicinin kaynak kodunu indekslemeyi ve çağrıyı belirli fonksiyon tanımına çözümlemeyi gerektirir.

Dolaylı Çağrılar: Sarmalayıcılar, Temsilciler ve Cepheler

Bir fonksiyon, tüketicileri tarafından doğrudan çağrılamaz. Ek günlük kaydı, hata işleme veya parametre dönüştürme sağlayan bir sarmalayıcı fonksiyon aracılığıyla çağrılabilir. Bir delegeye veya fonksiyon işaretçisine atanabilir ve delege aracılığıyla çağrılabilir. Bir servis kayıt defterine veya eklenti çerçevesine kaydedilebilir ve bir dağıtım mekanizması aracılığıyla adı belirtilerek çağrılabilir. Bu durumların her birinde, kullanımdan kaldırılmış fonksiyona yapılan çağrılar için doğrudan arama eksik bir sonuç döndürür, çünkü gerçek çağırıcılar kullanımdan kaldırılmış fonksiyonun kendisini değil, sarmalayıcıyı veya dağıtıcıyı çağırır.

Özellikle büyük kod tabanlarında, loglama, yetkilendirme ve yeniden deneme mantığı gibi kesişen kaygıların, sarmalayıcı kalıplar aracılığıyla temel fonksiyonların etrafına katmanlandığı durumlarda, sarmalayıcı aracılığıyla çağrı oldukça yaygındır. Bir loglama yardımcı programı tarafından sarmalanan eski bir fonksiyon, aslında sarmalayıcının her çağırıcısı tarafından çağrılır, eski fonksiyonun adını içeren herhangi bir kod tarafından değil. Bu çağırıcıları belirlemek, sarmalayıcı üzerinden izleme gerektirir: loglama yardımcı programı eski fonksiyonu çağırır ve bu nedenle loglama yardımcı programının her çağırıcısı, eski fonksiyonun dolaylı bir çağırıcısıdır. Bu özyinelemeli çağrı grafiği geçişi, kapsamlı bir çağırıcı envanterini yüzeysel bir referans aramasından ayıran şeydir.

Bir yetkilendirme katmanı aracılığıyla erişilen, kullanımdan kaldırılmış bir yöntemin yer aldığı temsili bir Java örneğini ele alalım:

Java

// Deprecated in the core service
@Deprecated
public BillingResult calculateLegacyFee(Account account) {
    // original implementation
}

// Facade that delegates; not visible as a direct caller in a simple reference search
public BillingResult computeFee(Account account) {
    return calculateLegacyFee(account);  // indirect caller
}

// Actual consumer; calls computeFee, unaware of the underlying deprecated method
public void processMonthlyBilling(List<Account> accounts) {
    accounts.forEach(a -> computeFee(a));  // two hops from the deprecated function
}

“Tüm Referansları Bul” araması için calculateLegacyFee İade computeFee tek arayan olarak. Geri dönüş yapmaz. processMonthlyBillingBu, kullanım dışı bırakılan davranışın gerçek tüketicisidir. Tam bir arayan envanteri, çağrı grafiğini yukarı doğru taramayı gerektirir. computeFee Son olarak, kullanımdan kaldırılmış yöntemi çağıran her yolu belirlemek.

Diller Arası Çağrılar

Diller arası çağrılar, standart çağrı keşif araçlarının en çok başarısız olduğu kategoridir. Bir Java servisi, bir ara katman aracılığıyla bir COBOL programını adıyla çağırdığında, bir Python betiği, kullanımdan kaldırılmış bir fonksiyonu saran bir saklı prosedürü çağırdığında veya bir JCL işi, dahili olarak kullanımdan kaldırılmış bir paragrafı çağıran bir programı PROGNAME'iyle çağırdığında, bu ilişkilerin hiçbiri tek bir dilin çağrı grafiğinde görünmez. Her dilin araçları yalnızca çağrının kendi tarafını görür.

Ana bilgisayar ortamlarında, diller arası çağrılar yapısal ve yaygındır. Bir JCL iş akışı, çalıştırdığı COBOL programının adını belirtir. COBOL programı, paragrafları ve alt programları adlarıyla çağırır. Kopyalama kütüphanelerinde tanımlanan yardımcı paragraflar birçok program arasında paylaşılır. Bir kopyalama kütüphanesindeki bir paragraf kullanımdan kaldırıldığında, tüm çağırıcıları bulmak, COBOL çağrı ilişkilerini (hangi programların kopyalama kütüphanesini içerdiği ve hangilerinin paragrafı çağırdığı), JCL çağrı ilişkilerini (hangi işlerin bu programları çağırdığı) ve herhangi bir diller arası arayüzü (bu programlarla etkileşim kuran Java veya SQL) anlamayı gerektirir. Tek bir araç tüm bu ilişkileri kapsamaz. Eski sistemlerde statik analiz incelemesinde de görüldüğü gibi , modern ortamlar için geliştirilen statik analiz araçları, çağrı ilişkileri JCL, COBOL ve sistemler arası arayüzleri aynı anda kapsadığında, eski programların nasıl tetiklendiğini, çağrıldığını ve birbirine bağlandığını tam olarak göremez.

Dinamik Sevk ve Yansıma

Bazı çağırıcılar, bir fonksiyonu kaynak kodundaki tam adıyla değil, çalışma zamanında fonksiyonu çözümleyen bir mekanizma aracılığıyla çağırır: Java veya .NET'te yansıma (reflection). getattr/__call__ Python'da, COBOL'da geç bağlama yoluyla CALL identifierPolimorfizm yoluyla dinamik dağıtım veya eklenti çerçevelerinde ve yapılandırma odaklı sistemlerde dize ile çağırma gibi yöntemler kullanılır. Bu çağırıcılar, statik analizin güvenilir bir şekilde tespit edebileceği herhangi bir biçimde, kullanımdan kaldırılmış fonksiyonun adını içermez.

Çalışma zamanında yüklenen ve yansıma yoluyla fonksiyonu çağırmak için kullanılan, bir fonksiyon adını dize olarak belirten bir yapılandırma dosyası, herhangi bir kaynak kod analizinde hiçbir yerde görünmeyen bir çağırıcıdır. Kayıtlı işleyicileri arayüz üzerinden keşfeden ve çağıran bir eklenti çerçevesi, çağrı grafiğinde yalnızca dağıtım mekanizmasına yapılan bir çağrı olarak görünür, belirli bir işleyiciye yapılan bir çağrı olarak değil. Bu çağırıcıları tanımlamak, dinamik dağıtım kalıplarını bulmak için statik analiz, gerçek çağrıları gözlemlemek için çalışma zamanı izleme ve hangi fonksiyonların gönderileceğini belirleyen yapılandırma ve kayıt mantığının manuel olarak incelenmesinin bir kombinasyonunu gerektirir. Gizlenmiş ve oluşturulmuş kod üzerinde statik analizin incelenmesinde tartışıldığı gibi , yürütme yolları kaynak kodda doğrudan ifade edilmediğinde, statik analiz, olası yolları doğrudan metinsel referanslardan ziyade yapısal kalıplardan yeniden oluşturmalıdır ve bu yeniden oluşturmalar, dağıtım mekanizmasının kendisinin dile duyarlı analizini gerektirir.

Geliştiricilerin İlk Olarak Başvurduğu Araçlar ve Durdukları Nokta

Geliştiricilerin arayan kişiyi bulmaya çalışırken kullandıkları araçların öngörülebilir bir sırası ve her birinin güvenilir sonuçlar vermeyi bıraktığı bir nokta vardır. Bu sırayı anlamak önemlidir çünkü her aracın çıktısı, aslında eksiksiz olmasa bile eksiksiz gibi görünür.

IDE Çağrı Hiyerarşisi: Tek Bir Proje İçinde Güvenilir

IDE çağrı hiyerarşisi özellikleri en doğal ilk adımdır. IntelliJ IDEA, Visual Studio, VS Code ve Eclipse'in tümü, mevcut proje veya çalışma alanının indekslenmiş kapsamı içinde seçilen bir fonksiyonun çağırıcılarını özyinelemeli olarak listeleyen bir tür "tüm çağırıcıları bul" veya "çağrı hiyerarşisini göster" özelliği sunar. Yalnızca bir depoda ve bir dilde kullanılan bir fonksiyon için bu özellikler doğru ve yeterlidir.

Sınırlama, kapsam belirlemesinde açıkça belirtilmiştir: "dizinlenen kapsam dahilinde". Diğer depolardaki, diğer dil çalışma ortamlarındaki veya bu koda doğrudan proje referansı yerine paket yöneticisi aracılığıyla bağımlı olan hizmetlerdeki çağrı yapanlar kapsam dışındadır. IDE, arama yapmadığı şeyleri belirtmez. Geliştirici bir sonuç kümesi alır ve dizinlenmemiş kaç ek depo olduğunu, bunlardan kaçının kullanımdan kaldırılmış işlevi kullandığını veya "sıfır çağrı yapan" sonucunun gerçekten sıfır çağrı yapan mı yoksa "bu aracın görebildiği sistemin bir bölümü içinde sıfır çağrı yapan" mı anlamına geldiğini göremez.

grep ve Metin Arama: Geniş Kapsamlı Ama Yapısal Olarak Kör

IDE aramasının eksik olduğundan şüphelenildiğinde, bir sonraki adım genellikle metin aramasıdır: mevcut kaynak dizinlerinde grep ile arama yapmak veya GitHub veya GitLab kod araması yoluyla platform araması yapmak. Bu, kapsamı önemli ölçüde genişletir ve erişilebilir olan diğer depolardaki çağırıcıları da bulur. Yapısal sorun, metin aramasının çağrıları değil, dizeleri bulmasıdır. Fonksiyon adının her geçtiği yeri döndürür; buna fonksiyondan bahseden yorumlar, dokümantasyon dizeleri, hata ayıklama amacıyla fonksiyonu adlandıran günlük mesajları ve fonksiyon adını içeren ancak onu çağırmayan dize değişmezleri dahildir. Ayrıca, fonksiyon adının arama dizesinden farklı olduğu çağırıcıları da gözden kaçırır: takma adlar aracılığıyla çağırıcılar, COBOL'da adların kısaltılmış olabileceği kısmen eşleşen adlar aracılığıyla çağırıcılar veya adın çalışma zamanında oluşturulduğu dinamik çağrılar aracılığıyla çağırıcılar.

Metin aramasından elde edilen sonuç kümesi, hangi kayıtların gerçek arama yerleri, hangilerinin dokümantasyon referansları ve hangilerinin dize çakışmalarından kaynaklanan yanlış pozitifler olduğunu belirlemek için manuel filtreleme gerektirir. Büyük bir sistemde, bu filtreleme başlı başına önemli bir çaba gerektirir ve filtreleme işlemi eksiksizliği doğrulayamaz: eğer bir arayan farklı bir isim kullandığı için gözden kaçırılmışsa, filtrelenmiş sonuç kümesinde bu eksikliğe dair hiçbir gösterge bulunmaz.

Derleyici Uyarıları ve @Deprecated Açıklamalar

Modern programlama dilleri ve araç zincirleri, kullanımdan kaldırılmış işlevler çağrıldığında uyarı üreten kullanımdan kaldırma ek açıklama mekanizmaları sunar. Java'nın @Deprecated açıklama ile birleştirilmiş -Xlint:deprecation C#'ın bu özelliği, çağrı noktalarında derleme zamanı uyarıları üretir. [Obsolete] Bu özellik derleme sırasında uyarılar oluşturur. Go'nun kullanımdan kaldırılmış fonksiyonları adlandırma ve bunları godoc'ta belgeleme geleneği otomatik olarak uyarı üretmez. Bu mekanizmalar değerlidir ancak belirli bir şekilde sınırlıdır: yalnızca kullanımdan kaldırma işleminin açıklandığı aynı kod tabanına karşı derleme yapan çağırıcılar için çalışırlar.

Kütüphanenin daha eski bir sürümünü kullanan, yani önceki bir sürüme ait bir arayan. @Deprecated Ek açıklama kullanan bir çağrı yapan, hiçbir uyarı almaz. Kaynak koddan derlemek yerine ikili bir yapıt kullanan bir çağrı yapan da hiçbir uyarı almaz. Farklı bir dilde, diller arası bir arayüz aracılığıyla çağrı yapan bir çağrı yapan da hiçbir uyarı almaz. Ve en önemlisi, derleme sırasında üretilen uyarılar derleyicinin görüş alanına özgüdür: ayrı olarak derlenen diğer depolardaki çağrılar hakkında değil, gördüğü çağrılar hakkında uyarı verirler. Çoklu hizmet sisteminde çağrı yapanı keşfetmek için tek mekanizma olarak derleyici uyarılarını kullanmak, bağımsız olarak derlenen her çağrı yapanı gözden kaçırır; bu da mikro hizmet mimarilerinde normal durumdur.

Statik Analiz Araçları: Daha İyi, Ama Kapsamı Sınırlı

Amaca yönelik olarak geliştirilmiş statik analiz araçları, hedef dilleri için IDE'lerden daha doğru çağrı yapanları listeler ve birden fazla kod tabanını indeksleyecek şekilde yapılandırıldıklarında genellikle depo sınırlarını aşabilirler. Metin eşleştirmeye güvenmek yerine doğru çağrı grafikleri oluştururlar, takma adlandırmayı ve dolaylı çağrıları IDE aramasından daha iyi ele alırlar ve yeni çağrı yapanları eklendikçe yakalamak için CI işlem hatlarında çalıştırılabilirler. Mevcut en yetenekli tek dilli yaklaşımdırlar.

Sınırlama, IDE'leri kısıtlayan kapsam sınırıyla aynıdır, ancak bu sefer araç düzeyindedir: bir Java statik analiz aracı COBOL programlarını indekslemez, bir COBOL analiz aracı Java servislerini indekslemez ve ikisi de JCL iş akışlarını indekslemez. Kullanımdan kaldırılan fonksiyonun, JCL işlerinden çağrılan ve veri çıktısı Java servisleri tarafından tüketilen COBOL programlarından çağrılan bir COBOL yardımcı programı olduğu bir sistemde, her statik analiz aracı çağrı ilişkisinin yalnızca bir parçasını görür. Temel yeniden düzenleme teknikleri bağlamında incelendiğinde , nadir hata durumları ve geri dönüş dalları da dahil olmak üzere, belirli bir kod bölümüne giden tüm yürütme yollarını belirlemek, tek dilli araçların dil sınırları arasında oluşturamayacağı türden eksiksiz bir çağrı grafiği eşlemesi gerektirir.

Eksiksiz Bir Arayan Envanteri Gerçekte Neler Gerektirir?

Kurumsal bir sistemde kullanımdan kaldırılmış bir fonksiyon için eksiksiz bir çağrı envanteri, bir arama sonucu değildir. Bu, kullanımdan kaldırılmış fonksiyona ulaşılabilecek her yürütme yolunun yapılandırılmış bir listelemesidir; bu yollar arasında doğrudan, dolaylı, diller arası ve dinamik olarak yönlendirilen yollar da bulunur. Bu listelemeyi oluşturmak, tek bir standart aracın sağlayamadığı çeşitli yetenekler gerektirir.

Birleşik bir diller arası çağrı grafiği. Çağrı grafiği sistemdeki her dili kapsamalıdır. Bir JCL prosedüründen bir COBOL programına yapılan çağrı, bir COBOL programından paylaşılan bir yardımcı program paragrafına yapılan çağrı ve bir Java servisinden aynı COBOL programına bir ara katman arayüzü aracılığıyla yapılan çağrı, aynı grafikteki düğümler ve kenarlar olmalıdır. Kullanımdan kaldırılmış fonksiyon bu grafikte bir düğümdür ve çağıran numaralandırması, hangi dilden kaynaklandığına bakılmaksızın, tüm gelen kenarların (doğrudan ve geçişli) bir geçişidir.

Çağrı grafiğinin tamamında özyinelemeli geçiş. Doğrudan çağıranlar yalnızca ilk katmandır. Tam bir envanter, çağrı grafiğini dolaylı çağıranlar, sarmalayıcı fonksiyonlar ve cephe katmanları üzerinden yukarı doğru takip etmeyi gerektirir; bu takip, kendi çağıranları olmayan fonksiyonlara ulaşana kadar devam eder ve bu fonksiyonlar çağrı zincirlerinin gerçek giriş noktalarıdır. Kullanımdan kaldırılmış fonksiyonda sona eren bir yoldaki her fonksiyon, ilgili anlamda bir çağırandır: kullanımdan kaldırılmış fonksiyonun kaldırılması, ondan geçen her yolu bozacaktır.

Çapraz depo indeksleme. Çağrı grafiği, paylaşılan bir kütüphane veya paket aracılığıyla fonksiyona bağımlı olan depolar da dahil olmak üzere, fonksiyonu potansiyel olarak çağırabilecek her depodan kod içermelidir. Bu, tüm depoların eş zamanlı olarak indekslenmesini ve bir depodaki çağrıları başka bir depodaki tanımlara bağlamak için çapraz depo içe aktarma ilişkilerinin çözümlenmesini gerektirir.

Dolaylı çağrı kalıplarının tespiti. Analiz, yansıma, dinamik dağıtım, fonksiyon işaretçileri, delegeler ve yapılandırma dosyalarındaki dize tabanlı çağrılar yoluyla yapılan çağrıları belirlemelidir. Bunlar, doğrudan çağrı kenarı çözümlemesi yerine kalıp tabanlı tespit gerektirir: kodda dinamik dağıtım mekanizmalarını bulmak ve hangi koşullar altında hangi fonksiyonlara dağıtım yapabileceklerini belirlemek.

Aktif çağrı yapanlar ile yalnızca test amaçlı veya ölü çağrı yapanlar arasında ayrım yapılmalıdır. Tüm çağrı yapanlar aynı yanıtı gerektirmez. Yalnızca kullanımdan kaldırılmış fonksiyonun kendisi için bir test düzeneğinde bulunan bir çağrı yapanın, temizleme işleminin bir parçası olarak kaldırılması gerekir, taşınması gerekmez. Kullanım analizi yoluyla ölü kod olarak tanımlanmış bir koddaki bir çağrı yapan, fonksiyonun kaldırılması için bir engel teşkil etmez. Bu ayrımları anlamak, çağrı yapan numaralandırmasını hangi kod yollarının gerçekten aktif olduğuna dair bilgilerle birleştirmeyi gerektirir. Statik analiz yoluyla ölü kod tespitinin incelenmesinde ayrıntılı olarak açıklandığı gibi , erişilemeyen kod ve kullanılmayan fonksiyonlar, eksik dokümantasyon veya geçmiş bağımlılıklar hakkındaki belirsizlik nedeniyle kritik sistemlerde yıllarca kalabilir ve kullanımdan kaldırılmış bir fonksiyonun çağrı yapan envanteri, kendileri canlı olan çağrı yapanlar ile kendileri ölü olan çağrı yapanlar arasında ayrım yapmalıdır.

Kullanımdan Kaldırma Süreci: Yapılandırılmış Bir Yaklaşım

Kullanımdan kaldırılmış fonksiyonların tek bir olay olarak değil de yapılandırılmış bir süreç olarak ele alınması, çoğu çağrı tespit hatasının kaynağıdır. Doğru yaklaşım, kaldırma işlemini, herhangi bir kod silinmeden çok önce başlayan çok aşamalı bir sürecin son adımı olarak ele alır.

Aşama 1: İşaretleme ve Ölçme

İlk adım, dilin yerleşik mekanizmasını kullanarak fonksiyonu kullanımdan kaldırılmış olarak işaretlemektir (@Deprecated Java'da, [Obsolete] C# dilinde, #[deprecated] Rust'ta (veya uygun eşdeğerinde) arama yaparak ve temel bir çağıran sayısı belirleyerek. Bu temel sayı, tek bir aramanın sonucu değildir; fonksiyonu çağırabilecek bilinen her kod tabanının indekslenmesi ve sonuçların sayılması sonucudur. Temel sayı iki amaca hizmet eder: geçiş kapsamını nicelendirir ve çağıranlar taşındıkça ilerlemenin ölçülebileceği bir referans sağlar.

Temel veriler arayan türüne ve konumuna göre düzenlenmelidir:

Arayan kategorisisaymakÖncelikMal sahibi
Aynı depodaki doğrudan arayanlarNYüksekŞu anki takım
Bağımlı hizmetlerdeki doğrudan arayanlarNYüksekHizmet sahipleri
Çağrı yapanlar, sarmalayıcı fonksiyonlar aracılığıylaNOrtaAmbalaj sahipleri
Oluşturulan veya çerçeve kodundaki çağrı yapanlarNOrtaÇerçeve ekibi
Yalnızca test amaçlı kodda çağrı yapanlarNDüşükŞu anki takım
Ölü kodda arayanlarNSadece temizlikŞu anki takım

Aşama 2: Bildirim ve Geçiş

Eksiksiz bir arayan envanteriyle, geçiş reaktif bir süreç olmaktan ziyade organize bir çaba haline gelir. Her arayan sahibi, belirli çağrı konumlarıyla ilgili bilgilendirilir: "Bu işlevi çağırıyor olabilirsiniz" yerine "Bu işlevi 247. satırda çağırıyorsunuz" şeklinde bir bildirim alır. BillingService.java82. satır AccountProcessor.javave entegrasyon testinde 14. satırda BillingServiceTest.javaBu düzeydeki ayrıntılandırma, arayan envanterinin mümkün kıldığı ve genel kullanımdan kaldırma uyarılarının sağlayamadığı şeydir.

Bildirimle birlikte bir geçiş yolu sağlamak çok önemlidir. Kullanımdan kaldırılma bildirimi, yerine geçecek fonksiyonun dokümantasyonunu, eski ve yeni uygulamalar arasındaki davranışsal farklılıkların açıklamasını ve değişiklik önemsiz değilse, öncesini ve sonrasını gösteren bir kod örneğini içermelidir. Diğer ekiplerin kod tabanlarındaki çağrı yapanlar için, geçiş zaman çizelgesi tek taraflı olarak duyurulmak yerine açıkça müzakere edilmelidir, çünkü bu ekiplerin kendi öncelikleri ve teslimat taahhütleri vardır. Bağımlı sistemler genelinde veritabanı yeniden yapılandırması bağlamında incelendiği gibi , eski yapıyı kullanımdan kaldırmadan önce yeni yapının tüketicilerini aşamalı olarak devreye almak, beklenmedik olaylar olarak ortaya çıkan kırıcı değişiklikleri önleyen disiplindir.

3. Aşama: Arayan Sayısını İzleme

Temel ölçüm ile planlanan kaldırma tarihi arasında, çağrı yapan fonksiyon sayısı sürekli olarak izlenmelidir. Bir çağrı yapan fonksiyon yedek fonksiyona her geçtiğinde, sayı azalır. Aktif çağrı yapan fonksiyon sayısı sıfıra ulaştığında kaldırma eşiğine ulaşılır (yalnızca test amaçlı ve ölü kod çağrı yapan fonksiyonlar, fonksiyonun kendisiyle eş zamanlı olarak kaldırılabilir). Sürekli izleme, kod değişiklikleriyle güncelliğini yitiren tek seferlik bir envantere güvenmek yerine, CI işlem hattının bir parçası olarak çağrı yapan fonksiyon numaralandırmasının programlı bir şekilde çalıştırılmasını gerektirir.

İzleme, kullanım dışı bırakma döneminde eklenen yeni çağrı yapanları da yakalar. Büyük kuruluşlarda, geliştiricinin kullanım dışı bırakmadan haberdar olmaması, kod incelemesinin bunu gözden kaçırması veya otomatik bir kod oluşturucunun kullanım dışı bırakılmış işlevi çağıran kod üretmesi nedeniyle, geçiş penceresi sırasında kullanım dışı bırakılmış bir işlevi çağıran yeni kod yazılması yaygındır. Yeni çağrı noktalarında başarısız olacak şekilde yapılandırılmış, kullanım dışı bırakılmış işlev için CI düzeyinde çağrı yapan tespiti, geçiş devam ederken çağrı yapan sayısının artmasını önler.

4. Aşama: Çıkarma İşleminden Önce Tamamlanmış Olduğunu Doğrulayın

Fonksiyonu kaldırmadan hemen önce, çağrı yapanların numaralandırılması, bilinen tüm kod tabanlarının tam kapsamına karşı son bir kez daha çalıştırılmalıdır. Bu son kontrol, güvenlik kapısı görevi görür: aktif çağrı yapanların sayısının sıfıra ulaştığını doğrular ve CI izlemesi tarafından yakalanmayan geç aşamadaki eklemeleri belirler. Bu noktada, envanter ayrıca dinamik çağrı yapanların yokluğunu da doğrulamalıdır: fonksiyonu dizeyle referans alan yapılandırma dosyaları, yansıma tabanlı kayıtlar ve ilk analiz sırasında belirlenen diğer dolaylı çağrı mekanizmaları.

Doğrulama, kullanımdan kaldırılan işlevi sunan tüm paylaşımlı kütüphanelerin veya paketlerin bağımlılık grafiğini de kapsamalıdır. İşlev, harici taraflarca kullanılan bir genel API'nin parçasıysa, kaldırma zaman çizelgesi, dahili kod analizi yoluyla erişilemeyen harici tüketicileri de hesaba katmalıdır. Dahili sistemler için doğrulama, indekslenmiş her kod tabanını kapsar. Genel olarak yayınlanan API'ler için doğrulama, bilinen tüketici kümesini ve harici tüketicilerin geçiş yapması gereken tanımlanmış bir geçiş süresini kapsar.

Eski ve Yeni Nesil Bilgisayar Ortamlarında Arayan Kişinin Tespiti Nasıl Farklı Çalışır?

Yukarıda açıklanan zorluklar, herhangi bir büyük yazılım sistemi için geçerlidir, ancak özellikle ana bilgisayar ve eski sistem ortamlarında daha da belirgindir çünkü bu ortamlardaki çağrı ilişkileri, modern arayan bulma araçlarının analiz etmek üzere tasarlanmadığı mekanizmalar aracılığıyla ifade edilir.

COBOL ortamlarında, fonksiyonlar, hedefi sabit bir dize, program adını içeren bir veri öğesi veya bir prosedür işaretçisi ile referans gösterebilen CALL ifadeleri aracılığıyla çağrılır. Sabit dize durumu statik analiz yoluyla çözülebilir; veri öğesi durumu, çağrı noktasında veri öğesinin hangi değeri tutabileceğini belirlemek için veri akışı analizi gerektirir; ve prosedür işaretçisi durumu, işaretçinin nasıl atandığını izlemeyi gerektirir. Bu çağrı mekanizmalarının her biri kaynak kodda farklı şekilde görünür ve çözülmesi için farklı analiz gerektirir.

JCL ortamlarında, programlar EXEC PGM= ifadelerinde isimleriyle çağrılır. Program adı, bir yükleme kütüphanesindeki derlenmiş bir modüle karşılık gelen bir dizedir. Bir COBOL programının JCL üzerinden çağrılarını izlemek, program adlarını çıkarmak için JCL'yi ayrıştırmayı, bu adları onları uygulayan derlenmiş COBOL programlarına eşlemeyi ve bu programlar içindeki hangi COBOL paragraflarının eski yardımcı programı çağırdığını çözmeyi gerektirir. Bu çok adımlı çözümleme, tek başına çalışan bir COBOL analizcisi veya bir JCL analizcisinin kapsamının tamamen dışındadır.

Paylaşımlı copybook'lar, COBOL ortamlarında özellikle önemli bir durumdur. Bir copybook'ta tanımlanan ve artık kullanılmayan bir paragraf, COPY ifadeleri aracılığıyla birçok programa dahil edilebilir. Paragraf her programda fiziksel olarak çoğaltılmaz; derleme zamanında dahil edilir. Kaynak dosyalardaki paragraf adının sayısını, copybook dahil etmelerini çözümlemeden sayan bir analiz, hem fazla sayım (paragraf tanımını copybook'un kendisinde bulma) hem de eksik sayım (copybook'u içeren her programın paragrafa erişimi olduğu gerçeğini gözden kaçırma) yapacaktır. Doğru çağırıcı keşfi, hangi programların hangi copybook'ları içerdiğini ve bu copybook'lar içindeki hangi paragrafları gerçekten çağırdığını anlamayı gerektirir. Sabit kodlanmış referanslar ve bunların aşağı akış tüketicileri arasındaki ilişki , herhangi bir yapısal değişiklikten önce bu program düzeyindeki çağrı ilişkilerinin çözümlenmesinin neden gerekli olduğunu göstermektedir: basit bir dize referansı gibi görünen şey, düzinelerce programın kritik işlevselliğe ulaşmasının tek mekanizması olabilir.

Ne kadar SMART TS XL Eksiksiz Arayan Envanterini Oluşturur

SMART TS XL Dizinlenmiş ortamdaki her dil, platform ve depo genelinde birleşik bir çağrı grafiği oluşturur. COBOL programları, JCL iş akışları, Java servisleri, .NET uygulamaları, SQL saklı prosedürleri, Python betikleri ve diğer kaynak yapıtları, dile özgü analiz kullanılarak ortak bir çapraz referans grafiğine ayrıştırılır. Her fonksiyon, paragraf, prosedür, metot ve program birimi bu grafikte bir düğümdür. Her çağrı ilişkisi, ister bir COBOL CALL ifadesi, ister bir Java metot çağrısı, ister bir JCL EXEC PGM veya bir SQL EXEC olsun, tipli bir kenardır. Grafik, sistemin tam çağrı topolojisini temsil eder, dil bazında kısmi bir görünümü değil.

Bir fonksiyon kaldırılmak üzere işaretlendiğinde, SMART TS XLÇağrı yapanları numaralandırma işlemi, hedef fonksiyon düğümünden gelen çağrı grafiğini dolaşarak, çağrı hiyerarşisinin her seviyesindeki her çağrı yapanı toplar. Bu dolaşma özyinelemeli olup, çağrı zincirinin gerçek giriş noktalarını temsil eden, çağrı yapmayan fonksiyonlara ulaşana kadar sarmalayıcı fonksiyonlar, cephe katmanları ve ara yardımcı programlar üzerinden grafiği takip eder. Sonuçlar dile, depoya, çağrı yapan türüne ve çağrı derinliğine göre düzenlenerek, ekibe doğrudan çağrı yapanları dolaylı çağrı yapanlardan ve aktif çağrı yapanları ölü kod çağrı yapanlarından ayıran yapılandırılmış bir envanter sunar.

Platformun etki analizi yeteneği, bunu yapılandırılmış bir değişiklik etki raporuna dönüştürür: yalnızca hangi fonksiyonların kullanımdan kaldırılan fonksiyonu çağırdığı değil, aynı zamanda bağımlılık zincirinin her seviyesinde hangi programların, hizmetlerin, toplu işlerin ve JCL prosedürlerinin etkilendiği de belirtilir. Bu rapor, kullanımdan kaldırma sürecini uygulanabilir kılan unsurdur: sahipleri belirtir, belirli çağrı konumlarını tanımlar ve kaldırma işlemi güvenli bir şekilde devam etmeden önce gereken geçişin kapsamını nicelendirir. Kurumsal değişiklik yönetimi için etki analizinin ayrıntılarında incelendiği gibi , yapısal bir değişiklik yapmadan önce etkilenen bileşenleri listeleme yeteneği, karmaşık, birbirine bağlı kurumsal sistemlerin güvenli çalışması için temel bir gerekliliktir.

SMART TS XL Ayrıca, kullanımdan kaldırılma sürecinin devam eden izleme aşamasını da destekler. Kaynak kod değişiklikleri indekslendikçe çapraz referans grafiği sürekli olarak güncellendiğinden, kullanımdan kaldırılmış bir fonksiyon için çağrı sayısı her zaman günceldir. CI işlem hattı entegrasyonu, kullanımdan kaldırılmış fonksiyonlara yapılan yeni çağrılarda otomatik kontrollerin başarısız olmasına olanak tanıyarak, ihlallerin sonradan keşfedilmesi yerine, yeni kodun tanıtıldığı noktada geçiş disiplinini uygular. İlk numaralandırma, geçiş rehberliği ve sürekli izlemenin bu kombinasyonu, kullanımdan kaldırılmış bir fonksiyonun açıklama eklenmesinden güvenli bir şekilde kaldırılmasına kadar tüm yaşam döngüsünü kapsar.

İşlev Kaldırma İşlemi Pişmanlık Duymadan

Sorunsuz bir şekilde gerçekleşen bir fonksiyon kaldırma işlemi ile üretim hatalarına yol açan bir kaldırma işlemi arasındaki fark neredeyse her zaman çağıran fonksiyonların keşfinin eksiksizliğindeki farklılıktan kaynaklanır. Kaldırma işleminin kendisi basittir: tanımı silin ve dağıtın. Asıl iş hazırlık aşamasındadır ve hazırlık, dayandığı çağıran fonksiyon envanteri kadar iyidir.

Çağrı grafiğinin sığ, tek dilli ve tek bir depoda yer aldığı sistemlerde, IDE çağrı hiyerarşisi ve derleyici uyarıları yeterli bir hazırlıktır. Çağrı grafiğinin birden fazla dili, birden fazla depoyu, birden fazla platformu ve potansiyel olarak onlarca yıllık kodu kapsadığı sistemlerde ise bu araçlar, gerçek çağrı yüzeyinin küçük ve bilinmez bir bölümünü kapsar. Bu araçların döndürdüğü sonuç ile fonksiyonu gerçekten çağıran şey arasındaki fark, üretim hatalarının kaynağıdır.

Amaca yönelik olarak tasarlanmış, diller arası ve depolar arası çağrı yapan fonksiyon numaralandırması, fonksiyon kaldırma için geliştirici iş akışının bir iyileştirmesi değildir. Bu, kurumsal kod tabanlarındaki kullanımdan kaldırılmış fonksiyonların rutin olarak taşıdığı türden sistemler arası çağrı ilişkilerini biriktirmiş olan yeterince karmaşık herhangi bir sistemde bu iş akışını güvenli bir şekilde yürütmenin ön koşuludur. Eksiksiz bir çağrı yapan fonksiyon envanteri olmadan kaldırılan her kullanımdan kaldırılmış fonksiyon, eksik tanıma ulaşan belirli yürütme yolunu bekleyen bilinmeyen sayıda çalışma zamanı hatası içeren bir sürümdür. Bu bilinmeyeni ortadan kaldırmak, yapılandırılmış çağrı yapan fonksiyon keşfinin amacıdır.